vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.76k stars 26.63k forks source link

`next/lib/find-config` does not support ESM config files #34448

Closed ctjlewis closed 5 months ago

ctjlewis commented 2 years ago

Verify canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: #110-Ubuntu SMP PREEMPT Thu Jan 13 19:01:34 UTC 2022
    Binaries:
      Node: 16.10.0
      npm: 7.24.0
      Yarn: 1.22.17
      pnpm: N/A
    Relevant packages:
      next: 12.0.11-canary.19
      react: 17.0.2
      react-dom: 17.0.2

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

Converting Next project to "type": "module", uses Tailwind and PostCSS. next/lib/find-config does not attempt to load via dynamic import and so throws even after converting PostCSS config to ESM:

./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[1]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[2]!./src/styles/index.css
Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/my/repo/components/postcss.config.js from /path/to/my/repo/components/node_modules/next/dist/lib/find-config.js not supported.
Instead change the require of postcss.config.js in /path/to/my/repo/components/node_modules/next/dist/lib/find-config.js to a dynamic import() which is available in all CommonJS modules.

Expected Behavior

Should attempt to load configs via ESM-CJS-interoperable default import.

To Reproduce

Convert a Tailwind Next.js project to "type": "module" and run next dev.

ctjlewis commented 2 years ago

Next no longer throws with the changes in #34451, but Tailwind will need to make changes in order for Tailwind to not throw:

../../next.js/packages/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[1]!../../next.js/packages/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[2]!./src/styles/index.css
Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/my/repo/components/tailwind.config.js from /path/to/my/repo/components/node_modules/tailwindcss/lib/lib/setupTrackingContext.js not supported.
Instead change the require of tailwind.config.js in /path/to/my/repo/components/node_modules/tailwindcss/lib/lib/setupTrackingContext.js to a dynamic import() which is available in all CommonJS modules.
ctjlewis commented 2 years ago

Worked around for Tailwind and PostCSS by forcing CJS in the type: module project with .cjs file extension for postcss.config.cjs and tailwind.config.cjs.

BB-19 commented 2 years ago

If anyone is struggling with TailwindCSS + "type: module":

mdaverde commented 2 years ago

Worked around for Tailwind and PostCSS by forcing CJS in the type: module project with .cjs file extension for postcss.config.cjs and tailwind.config.cjs.

@ctjlewis I'm not sure this works? At least from what I can tell from the way findConfig searches for files. For me, the .cjs versions get ignored. See also here.

@BB-19 I'm not sure this can work for filtering plugins against process.env.NODE_ENV such as written about here

vvo commented 2 years ago

@BB-19 Thank you 🙏 that's the only way I could make my website work. Why is renaming to postcss.config.cjs not sufficient though?

damianobarbati commented 2 years ago

@BB-19 is not working for me, what version of next are you using?

error - ./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[1]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[2]!./src/styles/index.css
/Users/damians/Desktop/predator/tailwind.config.cjs:29
export {};
^^^^^^

SyntaxError: Unexpected token 'export'
    at compileFunction (<anonymous>)
Ready on http://localhost:80
ctjlewis commented 2 years ago

@damianobarbati You can’t use exports keyword in a CJS file. Do module.exports = {…}.

madeleineostoja commented 1 year ago

This is a dealbreaker for me, I need my postcss config to be a module because I share an ESM js dependency between config and code (custom media queries), would be great to hear if it's at least on the roadmap to be fixed

ConnorLanglois commented 1 year ago

@damianobarbati

@BB-19 is not working for me, what version of next are you using?

error - ./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[1]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[2].oneOf[8].use[2]!./src/styles/index.css
/Users/damians/Desktop/predator/tailwind.config.cjs:29
export {};
^^^^^^

SyntaxError: Unexpected token 'export'
    at compileFunction (<anonymous>)
Ready on http://localhost:80

I was receiving the same error myself when using ts-node with a custom Next.js server. To resolve this, I added tailwind.config.cjs to the ignore option of ts-node. You can do this through the --ignore option or ignore field in ts-node config in the tsconfig.json file. For example, I now have:

...,
"ts-node": {
  "esm": true,
  "ignore": ["node_modules", "tailwind.config.cjs"]
}

The reason why "export {}" is added is explained here. Namely that,

the compiler must emit the export statement in order to ensure that the compiled file is also a Module.

This might only be the case if you set "module": "esnext" in your tsconfig file, which compiles TypeScript files to ESM modules. You might also have "type": "module" in your package.json if that's the case, as I do.

My guess for why adding this to ts-node's ignore field is required is that normally with just tsc TypeScript wouldn't compile tailwind.config.cjs, and I'm guessing that postcss/tailwind dynamically requires it (perhaps something like require('tailwind.config.' + extension) or something like that, which TypeScript can't compile since it can't know what the file is at compile-time), so it would just require it normally and work fine. But with ts-node, since it is now compiling at runtime, the dynamic require would now cause tailwind.config.cjs to be compiled and thus have the export {} line added. Adding the file to the ignore field stops it from doing so.

DannyPark1 commented 1 year ago

@BB-19 you saved me, but why does this work?

ctjlewis commented 1 year ago

@BB-19 you saved me, but why does this work?

PostCSS and Tailwind do not support ESM config files. You must rename them to .cjs.

There's no need to move postcss config to package.json and I don't recommend that.

Triment commented 1 year ago

如果有人在使用 TailwindCSS +“type: module”时遇到困难:

  • 将 tailwind 配置文件重命名为“tailwind.config.cjs”
  • 将 postcss.config.js 中的配置以 JSON 形式放入 package.json: 的“postcss”键下。
  • 删除 postcss.config.js 文件。
  • 从项目目录中删除 .next 文件夹以清除缓存并重新启动

It's magical !!!

Mon-ius commented 1 year ago

If anyone is struggling with TailwindCSS + "type: module": 1.Rename the tailwind config file to "tailwind.config.cjs" 2.Put your config from postcss.config.js as JSON to your package.json: under the key "postcss". 3.Remove your postcss.config.js file. 4.Remove the .next folder from your project directory to clear the cache and restart

@BB-19, No need to rename tailwind.config.js to tailwind.config.cjs. The problem is postcss.config.js, remove it and add the config to package.json. For example

{
...
  "type": "module",
  "postcss": {
    "plugins": {
      "tailwindcss": {},
      "autoprefixer": {}
    }
  },
...
}

For me, Yarn Berry with PnP Strict, the solution for convert next project from CommonJS to ESModule:

  1. Add or update package.json with "type": "module"
  2. Remove postcss.config.js and apply it to package.json with "postcss" json format, see above example
  3. Update next.config.js and tailwind.config.js to ESM format
  4. Add "pnpEnableEsmLoader: true" to .yarnrc.yml
  5. Clear Cache yarn cache clean && rm -rf yarn.lock && yarn install && yarn build

Hope it help to following guys 🤗

vishnupb123 commented 1 year ago

@Mon-lus Thanks a lot. It worked for me. It would be helpful if you could explain why the error happened. Once again thanks a lot

karlhorky commented 10 months ago

PostCSS and Tailwind do not support ESM config files

@ctjlewis This is not true anymore, both support ESM:

Tailwind CSS config files can also be written in ESM syntax with TypeScript - and this already works now with Next.js.

As far as I can tell, this is a problem with Next.js or some other dependency in between.

karlhorky commented 10 months ago

In the meantime, before Next.js supports ESM in PostCSS config files, I've opened the following PR to rename postcss.config.js to postcss.config.cjs in create-next-app, so that there is one fewer problem requiring manual intervention when someone wants to add "type": "module" to their package.json:

karlhorky commented 9 months ago

Just upgraded to next@14.0.4 and postcss-load-config@5.0.2 and confirmed that the bug still remains, ESM and TypeScript PostCSS formats are still not supported:

backslash112 commented 8 months ago

Hey guys, try this to see if it works:

  1. Remove file postcss.config.js, and add a new file postcss.config.json with the same config in JSON format:
    {
    "plugins": {
    "tailwindcss": {},
    "autoprefixer": {}
    }
    }
  2. rm -rf .next && npm run dev
will-stone commented 8 months ago

@backslash112 I just tried postcss.config.json with tailwind.config.mjs and it worked! 🥳 Thank you.

SalahAdDin commented 7 months ago

@backslash112 I just tried postcss.config.json with tailwind.config.mjs and it worked! 🥳 Thank you.

We want to use postcss.config.mjs, is it possible?

It is not working now.

phanect commented 6 months ago

Just opened a PR to fix this issue: #63109

karlhorky commented 5 months ago

Thanks for the PR for ESM support @phanect and for the review and merge @huozhi 🙌

I can confirm that next@14.2.0-canary.25 does have support for the following ESM configurations 🎉

  1. CommonJS project + postcss.config.mjs in ESM format
  2. ESM project + postcss.config.js in ESM format

I left the ReferenceError: module is not defined in ES module scope error in the log output below to show that a postcss.config.mjs file with CommonJS format fails (as expected) 👍

1. CommonJS project + postcss.config.mjs in ESM format

➜  p mkdir postcss-esm-and-ts-configs
➜  p cd postcss-esm-and-ts-configs
➜  postcss-esm-and-ts-configs pnpm create next-app@canary . --app --no-eslint --no-src-dir --import-alias @/\* --tailwind --typescript

.../Library/pnpm/store/v3/tmp/dlx-15463  |   +1 +
.../Library/pnpm/store/v3/tmp/dlx-15463  | Progress: resolved 1, reused 0, downloaded 1, added 1, done
Creating a new Next.js app in /Users/k/p/postcss-esm-and-ts-configs.

Using pnpm.

Initializing project with template: app-tw

Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- postcss
- tailwindcss

Downloading registry.npmjs.org/next/14.2.0-canary.26: 20.50 MB/20.50 MB, done
Packages: +132
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Downloading registry.npmjs.org/@next/swc-darwin-arm64/14.2.0-canary.26: 36.71 MB/36.71 MB, done
Progress: resolved 140, reused 127, downloaded 5, added 132, done

dependencies:
+ next 14.2.0-canary.26
+ react 18.2.0
+ react-dom 18.2.0

devDependencies:
+ @types/node 20.11.28
+ @types/react 18.2.66
+ @types/react-dom 18.2.22
+ postcss 8.4.35
+ tailwindcss 3.4.1
+ typescript 5.4.2

Done in 4.8s
Initialized a git repository.

Success! Created postcss-esm-and-ts-configs at /Users/k/p/postcss-esm-and-ts-configs

➜  postcss-esm-and-ts-configs git:(main) ls -al
total 136
drwxr-xr-x  15 k  staff    480 Mar 17 16:30 .
drwxr-xr-x  63 k  staff   2016 Mar 17 16:30 ..
drwxr-xr-x  12 k  staff    384 Mar 17 16:30 .git
-rw-r--r--   1 k  staff    391 Mar 17 16:30 .gitignore
-rw-r--r--   1 k  staff   1383 Mar 17 16:30 README.md
drwxr-xr-x   6 k  staff    192 Mar 17 16:30 app
-rw-r--r--   1 k  staff    201 Mar 17 16:30 next-env.d.ts
-rw-r--r--   1 k  staff     92 Mar 17 16:30 next.config.mjs
drwxr-xr-x  12 k  staff    384 Mar 17 16:30 node_modules
-rw-r--r--   1 k  staff    490 Mar 17 16:30 package.json
-rw-r--r--   1 k  staff  34550 Mar 17 16:30 pnpm-lock.yaml
-rw-r--r--   1 k  staff     61 Mar 17 16:30 postcss.config.cjs
drwxr-xr-x   4 k  staff    128 Mar 17 16:30 public
-rw-r--r--   1 k  staff    498 Mar 17 16:30 tailwind.config.ts
-rw-r--r--   1 k  staff    574 Mar 17 16:30 tsconfig.json
➜  postcss-esm-and-ts-configs git:(main) cat postcss.config.cjs
module.exports = {
  plugins: {
    tailwindcss: {},
  },
};
➜  postcss-esm-and-ts-configs git:(main) pnpm dev

> postcss-esm-and-ts-configs@0.1.0 dev /Users/k/p/postcss-esm-and-ts-configs
> next dev

  1 export default {
   ▲ Next.js 14.2.0-canary.26
   - Local:        http://localhost:3000

 ✓ Ready in 2.4s
 ○ Compiling / ...
 ✓ Compiled / in 1889ms (523 modules)
 ✓ Compiled in 122ms (244 modules)
^C
➜  postcss-esm-and-ts-configs git:(main) mv postcss.config.cjs postcss.config.mjs
➜  postcss-esm-and-ts-configs git:(main) ✗ pnpm dev

> postcss-esm-and-ts-configs@0.1.0 dev /Users/k/p/postcss-esm-and-ts-configs
> next dev

   ▲ Next.js 14.2.0-canary.26
   - Local:        http://localhost:3000

 ✓ Ready in 2.1s
 ○ Compiling / ...
 ⨯ app/layout.tsx
An error occurred in `next/font`.

ReferenceError: module is not defined in ES module scope
    at file:///Users/k/p/postcss-esm-and-ts-configs/postcss.config.mjs:1:1
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:431:15)
    at async findConfig (/Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/find-config.js:74:21)
    at async getPostCssPlugins (/Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/config/blocks/css/plugins.js:89:18)
    at async /Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/config/blocks/css/index.js:124:36
    at async /Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/loaders/next-font-loader/index.js:86:33
    at async Span.traceAsyncFn (/Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/trace/trace.js:151:20)
 ⨯ app/layout.tsx
An error occurred in `next/font`.

ReferenceError: module is not defined in ES module scope
    at file:///Users/k/p/postcss-esm-and-ts-configs/postcss.config.mjs:1:1
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:431:15)
    at async findConfig (/Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/find-config.js:74:21)
    at async getPostCssPlugins (/Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/config/blocks/css/plugins.js:89:18)
    at async /Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/config/blocks/css/index.js:124:36
    at async /Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/loaders/next-font-loader/index.js:86:33
    at async Span.traceAsyncFn (/Users/k/p/postcss-esm-and-ts-configs/node_modules/.pnpm/next@14.2.0-canary.26_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/trace/trace.js:151:20)
^C
➜  postcss-esm-and-ts-configs git:(main) ✗ vim postcss.config.mjs
➜  postcss-esm-and-ts-configs git:(main) ✗ cat postcss.config.mjs
export default {
  plugins: {
    tailwindcss: {},
  },
};
➜  postcss-esm-and-ts-configs git:(main) ✗ pnpm dev

> postcss-esm-and-ts-configs@0.1.0 dev /Users/k/p/postcss-esm-and-ts-configs
> next dev

   ▲ Next.js 14.2.0-canary.26
   - Local:        http://localhost:3000

 ✓ Ready in 1589ms
 ○ Compiling / ...
 ✓ Compiled / in 1931ms (523 modules)
 ✓ Compiled in 168ms (244 modules)
 ○ Compiling /favicon.ico ...
 ✓ Compiled /favicon.ico in 1658ms (530 modules)
^C

2. ESM project + postcss.config.js in ESM format

➜  postcss-esm-and-ts-configs git:(main) ✗ vim package.json
➜  postcss-esm-and-ts-configs git:(main) ✗ cat package.json
{
  "name": "postcss-esm-and-ts-configs",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "react": "^18",
    "react-dom": "^18",
    "next": "14.2.0-canary.26"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "postcss": "^8",
    "tailwindcss": "^3.4.1"
  }
}
➜  postcss-esm-and-ts-configs git:(main) ✗ mv postcss.config.mjs postcss.config.js
➜  postcss-esm-and-ts-configs git:(main) ✗ pnpm dev

> postcss-esm-and-ts-configs@0.1.0 dev /Users/k/p/postcss-esm-and-ts-configs
> next dev

   ▲ Next.js 14.2.0-canary.26
   - Local:        http://localhost:3000

 ✓ Ready in 1679ms
 ○ Compiling / ...
 ✓ Compiled / in 1875ms (523 modules)
 ✓ Compiled in 117ms (244 modules)
 ○ Compiling /favicon.ico ...
 ✓ Compiled /favicon.ico in 1663ms (530 modules)
karlhorky commented 5 months ago

One thing that is NOT yet supported is the postcss.config.ts file format supported by postcss-load-config:

➜  postcss-esm-and-ts-configs git:(main) ✗ mv postcss.config.mjs postcss.config.ts
➜  postcss-esm-and-ts-configs git:(main) ✗ pnpm dev

> postcss-esm-and-ts-configs@0.1.0 dev /Users/k/p/postcss-esm-and-ts-configs
> next dev

   ▲ Next.js 14.2.0-canary.26
   - Local:        http://localhost:3000

 ✓ Ready in 1666ms
 ○ Compiling / ...
 ✓ Compiled / in 1648ms (523 modules)
 ○ Compiling /favicon.ico ...
 ✓ Compiled /favicon.ico in 793ms (530 modules)
^C

It looks like the compilation works, but this results in an unstyled application.

But since this was not the main request by @ctjlewis in this issue, and appeared later in the issue comments, it's probably best to open a new issue for this.

karlhorky commented 5 months ago

One thing that probably could be still improved here is altering create-next-app to create postcss.config.mjs file with ESM format instead of the postcss.config.cjs file that is currently created.

I opened a PR for this here:

phanect commented 5 months ago

@karlhorky Thanks for testing. Yes, *.config.ts is out of scope of the PR I created this time and not supported yet, unfortunately.

SalahAdDin commented 5 months ago

@karlhorky Thanks for testing. Yes, *.config.ts is out of scope of the PR I created this time and not supported yet, unfortunately.

So, right now we can use postcss.config.mjs, right?

phanect commented 5 months ago

@SalahAdDin Yes, the latest canary release should support *.config.mjs now. I guess the stable version does not support it yet until the next release.

github-actions[bot] commented 5 months ago

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.