vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.28k stars 6.05k forks source link

ESM `.postcssrc.ts` w. `"type": "module"` results in `ERR_REQUIRE_ESM` #15869

Open karlhorky opened 7 months ago

karlhorky commented 7 months ago

Originally reported over here by @ElPrudi (before the issue was fixed in postcss-load-config):


Describe the bug

Upgrading to a version after postcss-load-config@5.0.0 (which added support for ESM postcss.config.ts w. "type": "module" does not resolve the problem in Vite that require() is used to load an ESM postcss.config.ts (or any other variations on the TS config) when in a "type": "module" project:

> vite

[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /home/projects/vitejs-vite-2gepfr): [Error] Must use import to load ES Module: /home/projects/vitejs-vite-2gepfr/.postcssrc.ts
require() of ES modules is not supported.
require() of /home/projects/vitejs-vite-2gepfr/.postcssrc.ts from /home/projects/vitejs-vite-2gepfr/node_modules/vite/dist/node/chunks/dep-bb8a8339.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /home/projects/vitejs-vite-2gepfr/package.json.

Error: Must use import to load ES Module: /home/projects/vitejs-vite-2gepfr/.postcssrc.ts
require() of ES modules is not supported.
require() of /home/projects/vitejs-vite-2gepfr/.postcssrc.ts from /home/projects/vitejs-vite-2gepfr/node_modules/vite/dist/node/chunks/dep-bb8a8339.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /home/projects/vitejs-vite-2gepfr/package.json.

    at createErrRequireEsm (/home/projects/vitejs-vite-2gepfr/node_modules/ts-node/dist-raw/node-internal-errors.js:46:15)
    at assertScriptCanLoadAsCJSImpl (/home/projects/vitejs-vite-2gepfr/node_modules/ts-node/dist-raw/node-internal-modules-cjs-loader.js:584:11)
    at Object.require.extensions.<computed> [as .ts] (/home/projects/vitejs-vite-2gepfr/node_modules/ts-node/src/index.ts:1610:5)
    at Module.load (node:internal/modules/cjs/loader:54:13457)
    at Function.Module._load (node:internal/modules/cjs/loader:54:10535)
    at Module.require (node:internal/modules/cjs/loader:54:13775)
    at i (node:internal/modules/cjs/helpers:98:2198)
    at eval (/home/projects/vitejs-vite-2gepfr/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:36654:16)
    at Object.search (/home/projects/vitejs-vite-2gepfr/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:29044:44)] {
  code: 'ERR_REQUIRE_ESM'
}

cc @bluwy

Reproduction

https://stackblitz.com/edit/vitejs-vite-2gepfr?file=package.json

Steps to reproduce

Create a config file called postcss.config.ts (or .postcssrc.ts, as in the reproduction above):

import type { Config } from 'postcss-load-config'
import cssnano from 'cssnano'

export default ({ env }): Config => ({
    plugins: [
        cssnano({
            preset: 'default'
        })
    ]
})

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.18.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.14.0 - /usr/local/bin/pnpm

Used Package Manager

npm

Logs

See logs above

Validations

stackblitz[bot] commented 7 months ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

brc-dd commented 7 months ago

15235 would fix this. But it's a breaking change, so it will probably be added in v6. Use .cts extension for now.

karlhorky commented 7 months ago

@brc-dd thanks!

I tried using postcss.config.cts, but this resulted in a confusing ts-node error which I was unable to find much info on:

[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /Users/k/p/projec/packages/slide-decks): [TSError] ⨯ Unable to compile TypeScript:
error TS5110: Option 'module' must be set to 'NodeNext' when option 'moduleResolution' is set to 'NodeNext'.

TSError: ⨯ Unable to compile TypeScript:
error TS5110: Option 'module' must be set to 'NodeNext' when option 'moduleResolution' is set to 'NodeNext'.

    at createTSError (/Users/k/p/projec/node_modules/ts-node/src/index.ts:859:12)
    at reportTSError (/Users/k/p/projec/node_modules/ts-node/src/index.ts:863:19)
    at /Users/k/p/projec/node_modules/ts-node/src/index.ts:1379:34
    at Object.compile (/Users/k/p/projec/node_modules/ts-node/src/index.ts:1440:28)
    at Module.m._compile (/Users/k/p/projec/node_modules/ts-node/src/index.ts:1617:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Object.require.extensions.<computed> [as .js] (/Users/k/p/projec/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Function.Module._load (node:internal/modules/cjs/loader:1023:12)
    at Module.require (node:internal/modules/cjs/loader:1235:19)] {
  diagnosticCodes: [ 5110 ]
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
github.com/evanw/esbuild/internal/helpers.(*ThreadSafeWaitGroup).Wait(...)
        github.com/evanw/esbuild/internal/helpers/waitgroup.go:36
main.runService.func2()
        github.com/evanw/esbuild/cmd/esbuild/service.go:114 +0x8c
main.runService(0x1)
        github.com/evanw/esbuild/cmd/esbuild/service.go:160 +0x4b4
main.main()
        github.com/evanw/esbuild/cmd/esbuild/main.go:240 +0x8d8

goroutine 18 [chan receive]:
main.runService.func1()
        github.com/evanw/esbuild/cmd/esbuild/service.go:98 +0x40
created by main.runService
        github.com/evanw/esbuild/cmd/esbuild/service.go:97 +0x1a0

goroutine 19 [chan receive]:
main.(*serviceType).sendRequest(0x140001ac060, {0x100866300, 0x140000d3b00})
        github.com/evanw/esbuild/cmd/esbuild/service.go:192 +0x11c
main.runService.func3()
        github.com/evanw/esbuild/cmd/esbuild/service.go:125 +0x38
created by main.runService
        github.com/evanw/esbuild/cmd/esbuild/service.go:122 +0x308
error Command failed with exit code 1.

My tsconfig.json file does indeed use NodeNext for both module and moduleResolution:

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "eslint-config-upleveled/tsconfig.base.json",
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "checkJs": true,
    "jsx": "preserve"
  },
  "include": [
    "**/*.ts",
    "**/*.tsx",
    "**/*.js",
    "**/*.jsx",
    "**/*.cts",
    "**/*.cjs",
    "**/*.mjs"
  ],
  "exclude": ["node_modules"]
}

I tried also switching to tsx as suggested by other users having issues with ts-node ("NODE_OPTIONS='--import tsx' vite dev"), but this led to a different confusing error, also thrown by ts-node:

[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /Users/k/p/projec/packages/slide-decks): [TypeError] Cannot assign to read only property '.mjs' of object '[object Object]'
TypeError: Cannot assign to read only property '.mjs' of object '[object Object]'
    at registerExtension (/Users/k/p/projec/node_modules/ts-node/src/index.ts:1607:26)
    at registerExtensions (/Users/k/p/projec/node_modules/ts-node/src/index.ts:1579:5)
    at Object.register (/Users/k/p/projec/node_modules/ts-node/src/index.ts:600:3)
    at file:///Users/k/p/projec/node_modules/vite/dist/node/chunks/dep-94_H5fT6.js:29068:43
    at Object.search (file:///Users/k/p/projec/node_modules/vite/dist/node/chunks/dep-94_H5fT6.js:21277:48)]
error Command failed with exit code 1.
brc-dd commented 7 months ago

Probably ts-node has some issue with nodenext. You can do something like:

// tsconfig.json
{
  // ...
  "ts-node": {
    "transpileOnly": true,
    "compilerOptions": {
      "module": "ESNext",
      "moduleResolution": "Node10"
    }
  }
}

https://stackblitz.com/edit/vitejs-vite-mbgkvz

aaronadamsCA commented 7 months ago

Just for added clarity: you can install v5 of postcss-load-config, you can override transitive dependencies to use v5, but Vite still contains postcss-load-config v4 as vendored code. That's why, even after excising ts-node from your codebase, you still get a ts-node error.

IMO just stick with postcss.config.cjs for now. It's just not worth the trouble trying to get ts-node working in a modern environment.

I wonder if Vite v6 could reconsider vendoring postcss-load-config? I definitely wasn't aware until now that installing my own postcss-load-config means I'm writing a "type-safe" config for a completely different version than what's baked into Vite. That is… not ideal!

benedictleejh commented 39 minutes ago

As an alternative to not vendoring postcss-load-config, would Vite consider re-exporting the PostCSS config type from postcss-load-config? This would have the advantage of allowing us to write type-safe configs using the same version of postcss-load-config that Vite uses, and users would not need to install their own version of postcss-load-config just to get access to the config typings.