diff --git a/crates/rspack_plugin_javascript/src/parser_plugin/import_meta_plugin.rs b/crates/rspack_plugin_javascript/src/parser_plugin/import_meta_plugin.rs index e2f70846b0ad..1ac655fd5966 100644 --- a/crates/rspack_plugin_javascript/src/parser_plugin/import_meta_plugin.rs +++ b/crates/rspack_plugin_javascript/src/parser_plugin/import_meta_plugin.rs @@ -79,11 +79,24 @@ impl JavascriptParserPlugin for ImportMetaPlugin { if for_name == expr_name::IMPORT_META_VERSION { Some(eval::evaluate_to_number(5_f64, start, end)) } else if for_name == expr_name::IMPORT_META_URL { - Some(eval::evaluate_to_string( - self.import_meta_url(parser), - start, - end, - )) + if parser.is_esm { + if parser + .compiler_options + .output + .environment + .supports_document() + { + None + } else { + Some(eval::evaluate_to_string( + self.import_meta_url(parser), + start, + end, + )) + } + } else { + None + } } else { None } @@ -172,7 +185,18 @@ impl JavascriptParserPlugin for ImportMetaPlugin { let mut content = vec![]; for prop in referenced_properties_in_destructuring.iter() { if prop.id == "url" { - content.push(format!(r#"url: "{}""#, self.import_meta_url(parser))) + if parser.is_esm + && parser + .compiler_options + .output + .environment + .supports_document() + { + // Preserve import.meta.url for web targets in ES modules using a getter + content.push(r#"get url() { return import.meta.url; }"#.to_string()) + } else { + content.push(format!(r#"url: "{}""#, self.import_meta_url(parser))) + } } else if prop.id == "webpack" { content.push(format!(r#"webpack: {}"#, self.import_meta_version())); } else { @@ -226,12 +250,25 @@ impl JavascriptParserPlugin for ImportMetaPlugin { ) -> Option { if for_name == expr_name::IMPORT_META_URL { // import.meta.url - parser.add_presentational_dependency(Box::new(ConstDependency::new( - member_expr.span().into(), - format!("'{}'", self.import_meta_url(parser)).into(), - None, - ))); - Some(true) + if !parser.is_esm { + // import.meta.url is only available in ES modules + return None; + } + if parser + .compiler_options + .output + .environment + .supports_document() + { + Some(true) + } else { + parser.add_presentational_dependency(Box::new(ConstDependency::new( + member_expr.span().into(), + format!("'{}'", self.import_meta_url(parser)).into(), + None, + ))); + Some(true) + } } else if for_name == expr_name::IMPORT_META_VERSION { // import.meta.webpack parser.add_presentational_dependency(Box::new(ConstDependency::new( diff --git a/tests/rspack-test/configCases/parsing/import-meta-url-web/index.js b/tests/rspack-test/configCases/parsing/import-meta-url-web/index.js new file mode 100644 index 000000000000..64746759c092 --- /dev/null +++ b/tests/rspack-test/configCases/parsing/import-meta-url-web/index.js @@ -0,0 +1,13 @@ +export {}; + +it("should not be replaced by file path", function() { + // import.meta.url should be preserved in the bundle (not replaced with a file:// URL string) + // When preserved, it will be resolved by the runtime environment + // In Node.js test environment, it resolves to file:// URL, but in browser it would be http:// + // The important thing is that it's not replaced during build time + const url = import.meta.url; + // Just verify it's a string (not undefined, which would mean it was replaced with unsupported comment) + expect(typeof url).toBe("string"); + // The actual URL format depends on the runtime environment, but it should exist + expect(url).toBeTruthy(); +}); diff --git a/tests/rspack-test/configCases/parsing/import-meta-url-web/rspack.config.js b/tests/rspack-test/configCases/parsing/import-meta-url-web/rspack.config.js new file mode 100644 index 000000000000..b016ee93c0ea --- /dev/null +++ b/tests/rspack-test/configCases/parsing/import-meta-url-web/rspack.config.js @@ -0,0 +1,10 @@ +module.exports = { + target: "web", + experiments: { + outputModule: true + }, + output: { + module: true, + chunkFormat: "module" + } +}; diff --git a/tests/rspack-test/configCases/parsing/import-meta-url-web/test.config.js b/tests/rspack-test/configCases/parsing/import-meta-url-web/test.config.js new file mode 100644 index 000000000000..1c96551e405f --- /dev/null +++ b/tests/rspack-test/configCases/parsing/import-meta-url-web/test.config.js @@ -0,0 +1,6 @@ +module.exports = { + moduleScope(scope) { + scope.pseudoImport = { meta: { url: "http://test.cases/path/index.js" } }; + } +}; +