diff --git a/crates/rspack_plugin_javascript/src/parser_plugin/node_stuff_plugin.rs b/crates/rspack_plugin_javascript/src/parser_plugin/node_stuff_plugin.rs index 8b78fc01ce0f..2ea5d325221d 100644 --- a/crates/rspack_plugin_javascript/src/parser_plugin/node_stuff_plugin.rs +++ b/crates/rspack_plugin_javascript/src/parser_plugin/node_stuff_plugin.rs @@ -281,7 +281,6 @@ impl NodeStuffPlugin { } /// Get the member replacement value for import.meta.filename/dirname - /// Returns None if the property should be preserved as-is, Some(replacement) otherwise fn get_import_meta_member_replacement( parser: &mut JavascriptParser, property: NodeMetaProperty, @@ -331,7 +330,7 @@ impl NodeStuffPlugin { .unwrap_or(false) { // Keep as import.meta.filename/dirname - runtime supports it - return None; + return Some(property.import_meta_name().to_string()); } Self::add_node_module_dependencies(parser, property); return Some(property.node_module_runtime_expr().to_string()); diff --git a/packages/rspack/etc/core.api.md b/packages/rspack/etc/core.api.md index bbabb4b3c281..6a5f826ee08b 100644 --- a/packages/rspack/etc/core.api.md +++ b/packages/rspack/etc/core.api.md @@ -2262,6 +2262,7 @@ export type Environment = { document?: boolean; dynamicImport?: boolean; dynamicImportInWorker?: boolean; + importMetaDirnameAndFilename?: boolean; forOf?: boolean; globalThis?: boolean; methodShorthand?: boolean; diff --git a/packages/rspack/src/config/adapter.ts b/packages/rspack/src/config/adapter.ts index e14a5e9516e6..b5e882c346d7 100644 --- a/packages/rspack/src/config/adapter.ts +++ b/packages/rspack/src/config/adapter.ts @@ -131,11 +131,15 @@ function getRawOutputEnvironment( destructuring: Boolean(environment.destructuring), document: Boolean(environment.document), dynamicImport: Boolean(environment.dynamicImport), + dynamicImportInWorker: Boolean(environment.dynamicImportInWorker), forOf: Boolean(environment.forOf), globalThis: Boolean(environment.globalThis), module: Boolean(environment.module), optionalChaining: Boolean(environment.optionalChaining), templateLiteral: Boolean(environment.templateLiteral), + importMetaDirnameAndFilename: Boolean( + environment.importMetaDirnameAndFilename, + ), }; } diff --git a/packages/rspack/src/config/browserslistTargetHandler.ts b/packages/rspack/src/config/browserslistTargetHandler.ts index 325b2d878cf8..b2b47cb38ea5 100644 --- a/packages/rspack/src/config/browserslistTargetHandler.ts +++ b/packages/rspack/src/config/browserslistTargetHandler.ts @@ -317,6 +317,11 @@ export const resolve = ( rawChecker({ node: [14, 18], }), + importMetaDirnameAndFilename: + nodeProperty && + rawChecker({ + node: [22, 16], + }), require: nodeProperty, }; }; diff --git a/packages/rspack/src/config/defaults.ts b/packages/rspack/src/config/defaults.ts index 85788f39886a..0831460bedcd 100644 --- a/packages/rspack/src/config/defaults.ts +++ b/packages/rspack/src/config/defaults.ts @@ -676,6 +676,13 @@ const applyOutputDefaults = ( 'nodePrefixForCoreModules', () => tp && optimistic(tp.nodePrefixForCoreModules), ); + F( + environment, + 'importMetaDirnameAndFilename', + () => + // No optimistic, because it is new + tp?.importMetaDirnameAndFilename, + ); F(environment, 'templateLiteral', () => tp && optimistic(tp.templateLiteral)); F(environment, 'dynamicImport', () => conditionallyOptimistic(tp?.dynamicImport, output.module), diff --git a/packages/rspack/src/config/target.ts b/packages/rspack/src/config/target.ts index dd82981024ff..54344a076680 100644 --- a/packages/rspack/src/config/target.ts +++ b/packages/rspack/src/config/target.ts @@ -63,6 +63,8 @@ export type ApiTargetProperties = { importScripts: boolean | null; /** has importScripts available when creating a worker */ importScriptsInWorker: boolean | null; + /** node.js allows to use `import.meta.dirname` and `import.meta.filename` */ + importMetaDirnameAndFilename: boolean | null; /** has fetch function available for WebAssembly */ fetchWasm: boolean | null; /** has global variable available */ @@ -235,6 +237,9 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis nodeBuiltins: true, // v16.0.0, v14.18.0 nodePrefixForCoreModules: +major < 15 ? v(14, 18) : v(16), + // Added in: v21.2.0, v20.11.0, but Node.js will output experimental warning, we don't want it + // v24.0.0, v22.16.0 - This property is no longer experimental. + importMetaDirnameAndFilename: v(22, 16), global: true, document: false, fetchWasm: false, @@ -281,6 +286,8 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis // 15.0.0 - Node.js v16.5 // 14.0.0 - Mode.js v14.17, but prefixes only since v14.18 nodePrefixForCoreModules: v(15), + // 37.0.0 - Node.js v22.16 + importMetaDirnameAndFilename: v(37), require: true, document: context === 'renderer', diff --git a/packages/rspack/src/config/types.ts b/packages/rspack/src/config/types.ts index 6c0f7b4bf59c..a40ee1172401 100644 --- a/packages/rspack/src/config/types.ts +++ b/packages/rspack/src/config/types.ts @@ -415,6 +415,9 @@ export type Environment = { /** The environment supports an async import() when creating a worker, only for web targets at the moment. */ dynamicImportInWorker?: boolean; + /** The environment supports `import.meta.dirname` and `import.meta.filename`. */ + importMetaDirnameAndFilename?: boolean; + /** The environment supports 'for of' iteration ('for (const x of array) { ... }'). */ forOf?: boolean; diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env-extends/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env-extends/rspack.config.js index de79550e9a66..e63be3a689d0 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env-extends/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env-extends/rspack.config.js @@ -20,6 +20,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env/rspack.config.js index aee6f92cc110..f0b24661ecd5 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-config-env/rspack.config.js @@ -18,6 +18,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-config-extends/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-config-extends/rspack.config.js index d909b6d2439c..2e366b954b89 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-config-extends/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-config-extends/rspack.config.js @@ -20,6 +20,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-config/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-config/rspack.config.js index cff7528f113c..b00db18a7bdf 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-config/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-config/rspack.config.js @@ -18,6 +18,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-env/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-env/rspack.config.js index 1d64b70727d3..54e7429720b6 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-env/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-env/rspack.config.js @@ -18,6 +18,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-extends/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-extends/rspack.config.js index 4f792c91ab00..faf23d9ced29 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-extends/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-extends/rspack.config.js @@ -18,6 +18,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-query-with-config-file/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-query-with-config-file/rspack.config.js index 2a9c8fcb2748..409938a8eb76 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-query-with-config-file/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-query-with-config-file/rspack.config.js @@ -18,6 +18,7 @@ module.exports = { dynamicImportInWorker: false, forOf: true, globalThis: true, + importMetaDirnameAndFilename: false, methodShorthand: true, module: true, nodePrefixForCoreModules: true, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist-query/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist-query/rspack.config.js index ee38e453e89b..540445b67dc0 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist-query/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist-query/rspack.config.js @@ -16,6 +16,7 @@ module.exports = { dynamicImportInWorker: false, forOf: false, globalThis: false, + importMetaDirnameAndFilename: false, methodShorthand: false, module: false, nodePrefixForCoreModules: false, diff --git a/tests/rspack-test/configCases/ecmaVersion/browserslist/rspack.config.js b/tests/rspack-test/configCases/ecmaVersion/browserslist/rspack.config.js index 10393169139d..3d76506ffe8d 100644 --- a/tests/rspack-test/configCases/ecmaVersion/browserslist/rspack.config.js +++ b/tests/rspack-test/configCases/ecmaVersion/browserslist/rspack.config.js @@ -16,6 +16,7 @@ module.exports = { dynamicImportInWorker: false, forOf: true, globalThis: true, + importMetaDirnameAndFilename: false, methodShorthand: true, module: true, nodePrefixForCoreModules: true, diff --git a/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/index.js b/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/index.js new file mode 100644 index 000000000000..0efc24ace34e --- /dev/null +++ b/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/index.js @@ -0,0 +1,15 @@ +import path from "path"; +import fs from "fs"; + +it("should use custom name", () => { + expect(__dirname).toBe(__STATS__.outputPath); + + const bundleFile = path.join(__STATS__.outputPath, "./bundle0.mjs"); + + expect(__filename).toBe(bundleFile); + + const content = fs.readFileSync(bundleFile, "utf8"); + + expect(content.includes("custom.dirname")).toBe(true); + expect(content.includes("custom.filename")).toBe(true); +}); diff --git a/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/rspack.config.js b/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/rspack.config.js new file mode 100644 index 000000000000..7b15e7c135b4 --- /dev/null +++ b/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/rspack.config.js @@ -0,0 +1,20 @@ +"use strict"; + +/** @type {import("@rspack/core").Configuration} */ +module.exports = { + target: "node", + experiments: { + outputModule: true + }, + output: { + module: true, + importMetaName: "custom", + environment: { + importMetaDirnameAndFilename: true + } + }, + node: { + __filename: "node-module", + __dirname: "node-module" + } +}; diff --git a/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/test.config.js b/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/test.config.js new file mode 100644 index 000000000000..9a1340356b95 --- /dev/null +++ b/tests/rspack-test/configCases/node/filename-and-dirname-node-module-meta-dirname-and-filename/test.config.js @@ -0,0 +1,20 @@ +"use strict"; + +const path = require("path"); +const { pathToFileURL } = require("url"); + +let counter = 0; + +module.exports = { + moduleScope(scope, _stats, options) { + const bundleFilename = path.join( + options.output.path, + `bundle${counter++}.mjs` + ); + scope.custom = { + url: pathToFileURL(bundleFilename).toString(), + dirname: path.dirname(bundleFilename), + filename: bundleFilename + }; + } +}; diff --git a/tests/rspack-test/configCases/node/filename-and-dirname/rspack.config.js b/tests/rspack-test/configCases/node/filename-and-dirname/rspack.config.js index 4c27b552ee1a..54080c471089 100644 --- a/tests/rspack-test/configCases/node/filename-and-dirname/rspack.config.js +++ b/tests/rspack-test/configCases/node/filename-and-dirname/rspack.config.js @@ -28,7 +28,7 @@ config.push( })) ); -// // ES modules +// ES modules config.push( ...values.map((value) => ({ target: "node", diff --git a/tests/rspack-test/defaultsCases/default/base.js b/tests/rspack-test/defaultsCases/default/base.js index 7a071595afe0..fd55eed78936 100644 --- a/tests/rspack-test/defaultsCases/default/base.js +++ b/tests/rspack-test/defaultsCases/default/base.js @@ -86,6 +86,7 @@ module.exports = { dynamicImportInWorker: undefined, forOf: true, globalThis: undefined, + importMetaDirnameAndFilename: undefined, methodShorthand: true, module: undefined, nodePrefixForCoreModules: true, @@ -337,6 +338,7 @@ module.exports = { dynamicImportInWorker: undefined, forOf: true, globalThis: undefined, + importMetaDirnameAndFilename: undefined, methodShorthand: true, module: undefined, nodePrefixForCoreModules: true, diff --git a/website/docs/en/config/output.mdx b/website/docs/en/config/output.mdx index afa3dd66a86d..88a36f62c44e 100644 --- a/website/docs/en/config/output.mdx +++ b/website/docs/en/config/output.mdx @@ -426,6 +426,8 @@ type Environment = { dynamicImport?: boolean; /** The environment supports an async import() when creating a worker, only for web targets at the moment. */ dynamicImportInWorker?: boolean; + /** The environment supports `import.meta.dirname` and `import.meta.filename`. */ + importMetaDirnameAndFilename?: boolean; /** The environment supports 'for of' iteration ('for (const x of array) { ... }'). */ forOf?: boolean; /** The environment supports 'globalThis'. */ diff --git a/website/docs/zh/config/output.mdx b/website/docs/zh/config/output.mdx index 10f55aedaaba..a57f7bc404a9 100644 --- a/website/docs/zh/config/output.mdx +++ b/website/docs/zh/config/output.mdx @@ -422,6 +422,8 @@ type Environment = { dynamicImport?: boolean; /** The environment supports an async import() when creating a worker, only for web targets at the moment. */ dynamicImportInWorker?: boolean; + /** The environment supports `import.meta.dirname` and `import.meta.filename`. */ + importMetaDirnameAndFilename?: boolean; /** The environment supports 'for of' iteration ('for (const x of array) { ... }'). */ forOf?: boolean; /** The environment supports 'globalThis'. */