できない.dev

postcss.config.js が ESM プロジェクトで読み込めずビルドが落ちる

package.json に type: module があると postcss.config.js は ES モジュールとして評価されるため、module.exports や require が使えず落ちる。
export default に書き換えるか拡張子を .cjs にする。

公開: 更新:

症状できない · exit 1
npx postcss input.css -o output.css
…
ReferenceError: module is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/tmp/tmp.BH5jgFhN20/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at file:///tmp/tmp.BH5jgFhN20/postcss.config.js?t=1792458048714:1:1
    at ModuleJob.run (node:internal/modules/esm/module_job:325:25)
解決後できた · exit 0
npx postcss input.css -o output.css

2026-10-20 に node:20(PostCSS 8.5.31 / Node.js 20.20.2) で実際に打って取った出力。検証環境の詳細

要約

module is not defined in ES module scope や require is not defined で PostCSS の設定読み込みが落ちるのは、package.json に "type": "module" があるためだ。
この指定があると .js ファイルは ES モジュールとして評価され、module.exports も require も使えない。

設定を ES モジュールの書き方に直す。

// postcss.config.js
import autoprefixer from "autoprefixer";
 
export default {
  plugins: [autoprefixer],
};

実行例

実際に上記の手順を node:20(PostCSS 8.5.31)で動かすと、"type": "module" のプロジェクトで module.exports の postcss.config.js を読ませた npx postcss は ReferenceError: module is not defined in ES module scope を出して終了コード 1 で止まった。
拡張子を .cjs に変えた場合と export default に書き換えた場合は、どちらも終了コード 0 で user-select にベンダープレフィックスが付いた CSS が出力された。

$ cat postcss.config.js
module.exports = {
  plugins: [require("autoprefixer")],
};
$ npx postcss input.css -o output.css
ReferenceError: module is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/tmp/tmp.BH5jgFhN20/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at file:///tmp/tmp.BH5jgFhN20/postcss.config.js?t=1792458048714:1:1
    at ModuleJob.run (node:internal/modules/esm/module_job:325:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:606:24)
    at async req (/tmp/tmp.BH5jgFhN20/node_modules/postcss-load-config/src/req.js:22:13)
    at async Object.search (/tmp/tmp.BH5jgFhN20/node_modules/lilconfig/src/index.js:225:23)
    at async Promise.all (index 0)
$ echo $?
1
$ mv postcss.config.js postcss.config.cjs
$ npx postcss input.css -o output.css
$ echo $?
0
$ cat output.css
.box {
  display: flex;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}
$ cat postcss.config.js
import autoprefixer from "autoprefixer";
 
export default {
  plugins: [autoprefixer],
};
$ npx postcss input.css -o output.css
$ echo $?
0
$ cat output.css
.box {
  display: flex;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

— 2026-10-20 時点の出力

検証環境Node.js 20.20.2 / npm 10.8.2 / Python 3.11.2 / 2026-10-20 検証(ほか 2 件)
検証日
実行環境
node:20 Debian GNU/Linux 12 (bookworm)
バージョン
  • Node.js 20.20.2
  • npm 10.8.2
  • Python 3.11.2
  • Git 2.39.5
  • PostCSS 8.5.31

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

解決策

1. export default 形式に書き換える

プラグインをオブジェクト記法で書く場合は、そのまま export default を付ける。

// postcss.config.js
export default {
  plugins: {
    autoprefixer: {},
  },
};

配列記法にすると、プラグイン関数を直接渡せてオプションも書ける。

// postcss.config.js
import autoprefixer from "autoprefixer";
 
export default {
  plugins: [autoprefixer({ grid: "autoplace" })],
};

2. 拡張子を .cjs にして CommonJS のまま使う

既存の設定を触りたくないときは、ファイル名を変えるだけで通る。
postcss-load-config は postcss.config.cjs も探索対象にしている。

mv postcss.config.js postcss.config.cjs

.cjs は type の値にかかわらず CommonJS として読まれるので、module.exports と require がそのまま使える。

3. .mjs で ES モジュールを明示する

逆に、type を指定していないプロジェクトで ES モジュールとして書きたい場合は .mjs にする。

mv postcss.config.js postcss.config.mjs

4. TypeScript の設定ファイルにはローダーを入れる

postcss.config.ts を使うなら、TypeScript を読める実行環境が要る。

npm i -D tsx

jiti でも同じ役割を果たす。
どちらも入れずに .ts の設定だけ置くと、設定が見つからないまま処理が進み、プラグインが一切適用されない状態になる。

よくある原因

  1. "type": "module" と module.exports の組み合わせ: Node.js は package.json の type で .js の扱いを決める。module なら ES モジュールとして読むので、CommonJS の書き方は構文エラーになる。
  2. 設定ファイル内の require: プラグインを require("autoprefixer") で読み込んでいると、同じ理由で落ちる。
  3. 拡張子で明示していない: .js は package.json の設定に左右される。
    チームで type を切り替えたときに、設定ファイルだけ取り残されることがある。
  4. TypeScript 版を置いた: postcss-load-config は postcss.config.ts も探すが、その場合は tsx か jiti を peer dependency として自分で入れる必要がある。

この手順で直った?