diff --git a/CHANGELOG.md b/CHANGELOG.md index fc7774ac1ab..4716e651b54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## Unreleased + +* Allow using the `node:` import prefix with `es*` targets ([#3821](https://github.com/evanw/esbuild/issues/3821)) + + The [`node:` prefix on imports](https://nodejs.org/api/esm.html#node-imports) is an alternate way to import built-in node modules. For example, `import fs from "fs"` can also be written `import fs from "node:fs"`. This only works with certain newer versions of node, so esbuild removes it when you target older versions of node such as with `--target=node14` so that your code still works. With the way esbuild's platform-specific feature compatibility table works, this was added by saying that only newer versions of node support this feature. However, that means that a target such as `--target=node18,es2022` removes the `node:` prefix because none of the `es*` targets are known to support this feature. This release adds the support for the `node:` flag to esbuild's internal compatibility table for `es*` to allow you to use compound targets like this: + + ```js + // Original code + import fs from 'node:fs' + fs.open + + // Old output (with --bundle --format=esm --platform=node --target=node18,es2022) + import fs from "node"; + fs.open; + + // New output (with --bundle --format=esm --platform=node --target=node18,es2022) + import fs from "node:fs"; + fs.open; + ``` + ## 0.23.0 **_This release deliberately contains backwards-incompatible changes._** To avoid automatically picking up releases like this, you should either be pinning the exact version of `esbuild` in your `package.json` file (recommended) or be using a version range syntax that only accepts patch upgrades such as `^0.22.0` or `~0.22.0`. See npm's documentation about [semver](https://docs.npmjs.com/cli/v6/using-npm/semver/) for more information. diff --git a/compat-table/src/index.ts b/compat-table/src/index.ts index aab10e7a83a..9d57e235adb 100644 --- a/compat-table/src/index.ts +++ b/compat-table/src/index.ts @@ -466,6 +466,8 @@ import('./kangax').then(kangax => { '15': { force: false }, '16': { force: true }, } + js.NodeColonPrefixImport.ES = { 0: { force: true } } + js.NodeColonPrefixRequire.ES = { 0: { force: true } } // Arbitrary Module Namespace Names { diff --git a/internal/compat/js_table.go b/internal/compat/js_table.go index a725bad238c..f3461ab1d9f 100644 --- a/internal/compat/js_table.go +++ b/internal/compat/js_table.go @@ -651,9 +651,11 @@ var jsTable = map[JSFeature]map[Engine][]versionRange{ Safari: {{start: v{10, 0, 0}}}, }, NodeColonPrefixImport: { + ES: {{start: v{0, 0, 0}}}, Node: {{start: v{12, 20, 0}, end: v{13, 0, 0}}, {start: v{14, 13, 1}}}, }, NodeColonPrefixRequire: { + ES: {{start: v{0, 0, 0}}}, Node: {{start: v{14, 18, 0}, end: v{15, 0, 0}}, {start: v{16, 0, 0}}}, }, NullishCoalescing: { diff --git a/scripts/js-api-tests.js b/scripts/js-api-tests.js index 77d7a3ebf5b..d32d7c85ca7 100644 --- a/scripts/js-api-tests.js +++ b/scripts/js-api-tests.js @@ -3065,7 +3065,7 @@ import "after/alias"; stdin: { contents: `import fs from 'node:fs'; import('node:fs'); fs()` }, bundle: true, platform: 'node', - target, + target: target.split(','), format: 'esm', write: false, }) @@ -3079,6 +3079,7 @@ import "after/alias"; assert.strictEqual(await tryTargetESM('node12.99'), `// \nimport fs from "node:fs";\nimport("node:fs");\nfs();\n`) assert.strictEqual(await tryTargetESM('node12.20'), `// \nimport fs from "node:fs";\nimport("node:fs");\nfs();\n`) assert.strictEqual(await tryTargetESM('node12.19'), `// \nimport fs from "fs";\nPromise.resolve().then(() => __toESM(__require("fs")));\nfs();\n`) + assert.strictEqual(await tryTargetESM('node18,es6'), `// \nimport fs from "node:fs";\nimport("node:fs");\nfs();\n`) }, async nodeColonPrefixRequire({ esbuild }) { @@ -3087,7 +3088,7 @@ import "after/alias"; stdin: { contents: `require('node:fs'); require.resolve('node:fs')` }, bundle: true, platform: 'node', - target, + target: target.split(','), format: 'cjs', write: false, }) @@ -3101,6 +3102,7 @@ import "after/alias"; assert.strictEqual(await tryTargetESM('node14.99'), `// \nrequire("node:fs");\nrequire.resolve("node:fs");\n`) assert.strictEqual(await tryTargetESM('node14.18'), `// \nrequire("node:fs");\nrequire.resolve("node:fs");\n`) assert.strictEqual(await tryTargetESM('node14.17'), `// \nrequire("fs");\nrequire.resolve("fs");\n`) + assert.strictEqual(await tryTargetESM('node18,es6'), `// \nrequire("node:fs");\nrequire.resolve("node:fs");\n`) }, async nodeColonPrefixImportTurnedIntoRequire({ esbuild }) { @@ -3109,7 +3111,7 @@ import "after/alias"; stdin: { contents: `import fs from 'node:fs'; import('node:fs'); fs()` }, bundle: true, platform: 'node', - target, + target: target.split(','), format: 'cjs', write: false, }) @@ -3123,6 +3125,7 @@ import "after/alias"; assert.strictEqual(await tryTargetESM('node14.99'), `// \nvar import_node_fs = __toESM(require("node:fs"));\nimport("node:fs");\n(0, import_node_fs.default)();\n`) assert.strictEqual(await tryTargetESM('node14.18'), `// \nvar import_node_fs = __toESM(require("node:fs"));\nimport("node:fs");\n(0, import_node_fs.default)();\n`) assert.strictEqual(await tryTargetESM('node14.17'), `// \nvar import_node_fs = __toESM(require("fs"));\nimport("fs");\n(0, import_node_fs.default)();\n`) + assert.strictEqual(await tryTargetESM('node18,es6'), `// \nvar import_node_fs = __toESM(require("node:fs"));\nimport("node:fs");\n(0, import_node_fs.default)();\n`) }, async zipFile({ esbuild, testDir }) {