Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rspack_core::{
use rspack_error::{Diagnostic, Severity};
use rspack_util::{SpanExt, json_stringify_str};
use swc_atoms::Atom;
use swc_experimental_allocator::CloneIn;
use swc_experimental_ecma_ast::{
AssignExpr, AssignOp, CallExpr, Callee, Expr, ExprOrSpread, GetSpan, Ident, Lit, MemberExpr,
MemberProp, NewExpr, Span, UnaryExpr, UnaryOp, VarDeclarator,
Expand Down Expand Up @@ -60,16 +61,16 @@ struct CreateRequireArgument {
}

#[derive(Default)]
pub struct CreatedRequireReferencesState {
pending: rustc_hash::FxHashMap<Span, PendingCreatedRequire>,
pub struct CreatedRequireReferencesState<'a> {
pending: rustc_hash::FxHashMap<Span, PendingCreatedRequire<'a>>,
exported_locals: rustc_hash::FxHashSet<Atom>,
}

struct PendingCreatedRequire {
struct PendingCreatedRequire<'a> {
must_keep: bool,
callee: DeferredCreateRequireCallee,
arg_span: Span,
arg_value: String,
// Deferred calls skip this expression until their keep/strip state is known.
argument: Expr<'a>,
}

struct DeferredCreateRequireCallee {
Expand All @@ -82,13 +83,12 @@ struct DeferredCreateRequireCallee {
branch_guard: Option<DependencyBranchGuard>,
}

impl CreatedRequireReferencesState {
impl<'a> CreatedRequireReferencesState<'a> {
fn add_pending(
&mut self,
call_span: Span,
callee: DeferredCreateRequireCallee,
arg_span: Span,
arg_value: String,
argument: Expr<'a>,
) {
// Normal walk refreshes provisional pre-walk data after earlier references may mark it.
let must_keep = self
Expand All @@ -100,8 +100,7 @@ impl CreatedRequireReferencesState {
PendingCreatedRequire {
must_keep,
callee,
arg_span,
arg_value,
argument,
},
);
}
Expand All @@ -112,7 +111,7 @@ impl CreatedRequireReferencesState {
}
}

fn take_pending(&mut self) -> Vec<(Span, PendingCreatedRequire)> {
fn take_pending(&mut self) -> Vec<(Span, PendingCreatedRequire<'a>)> {
let mut pending = std::mem::take(&mut self.pending)
.into_iter()
.collect::<Vec<_>>();
Expand Down Expand Up @@ -1071,29 +1070,17 @@ fn add_deferred_create_require_callee_dependency(
);
}

fn keep_deferred_create_require_call(
parser: &mut JavascriptParser,
pending: PendingCreatedRequire,
fn keep_deferred_create_require_call<'a>(
parser: &mut JavascriptParser<'a>,
pending: PendingCreatedRequire<'a>,
) {
add_deferred_create_require_callee_dependency(parser, pending.callee);
if parser.compiler_options.output.module {
let import_meta_name = &parser.compiler_options.output.import_meta_name;
if import_meta_name != expr_name::IMPORT_META {
parser.add_presentational_dependency(Box::new(ConstDependency::new(
pending.arg_span.into(),
format!("{import_meta_name}.url").into(),
)));
}
} else {
parser.add_presentational_dependency(Box::new(ConstDependency::new(
pending.arg_span.into(),
json_stringify_str(&pending.arg_value).into(),
)));
}
// Let the regular parser plugins own children of a call that survives.
parser.walk_expression(&pending.argument);
}

fn pre_tag_created_require_declarator(
parser: &mut JavascriptParser,
fn pre_tag_created_require_declarator<'a>(
parser: &mut JavascriptParser<'a>,
declarator: &VarDeclarator,
declaration: VariableDeclaration<'_>,
) {
Expand Down Expand Up @@ -1124,7 +1111,7 @@ fn pre_tag_created_require_declarator(
return;
};
let CreateRequireArgument {
value,
value: _,
context,
replace_argument: _,
} = argument;
Expand All @@ -1143,15 +1130,14 @@ fn pre_tag_created_require_declarator(
parser.created_require_references.add_pending(
call.span,
deferred_callee,
call.args[0].expr.span(),
value,
call.args[0].expr.clone_in(parser.ast.allocator),
);
}

#[cold]
#[inline(never)]
fn tag_created_require_declarator(
parser: &mut JavascriptParser,
fn tag_created_require_declarator<'a>(
parser: &mut JavascriptParser<'a>,
binding: &Ident,
call_span: Span,
clear_call: bool,
Expand All @@ -1178,9 +1164,11 @@ fn tag_created_require_declarator(
}),
);
if let Some(callee) = deferred_callee {
parser
.created_require_references
.add_pending(call_span, callee, args[0].expr.span(), value);
parser.created_require_references.add_pending(
call_span,
callee,
args[0].expr.clone_in(parser.ast.allocator),
);
} else if clear_call {
clear_create_require_call(parser, call_span);
} else if replace_argument {
Expand Down Expand Up @@ -2671,7 +2659,10 @@ impl<'p, 'a> JavascriptParserPlugin<'p, 'a> for CommonJsImportsParserPlugin {
}
}

for (call_span, pending) in parser.created_require_references.take_pending() {
let mut created_require_references = std::mem::take(&mut parser.created_require_references);
let pending_calls = created_require_references.take_pending();
parser.created_require_references = created_require_references;
for (call_span, pending) in pending_calls {
if pending.must_keep {
keep_deferred_create_require_call(parser, pending);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use concat_string::concat_string;
use cow_utils::CowUtils;
use itertools::Itertools;
use rspack_core::{
ArcComputed, ConstDependency, ContextDependency, ContextMode, ContextOptions, DependencyCategory,
DependencyRange, ImportMeta, ImportMetaKnownProperties, ResolvedModuleOptions, RscMeta,
RscModuleType, RuntimeGlobals, RuntimeRequirementsDependency, property_access,
};
use rspack_error::{Error, Severity};
use rspack_util::SpanExt;
use rspack_util::{SpanExt, json_stringify_str};
use swc_atoms::Atom;
use swc_experimental_ecma_ast::{
AssignExpr, CallExpr, Expr, GetSpan, MemberExpr, MemberProp, MetaPropKind, OptChainBase,
Expand Down Expand Up @@ -39,6 +40,12 @@ use crate::{
},
};

fn single_quoted_string(value: &str) -> String {
let json = json_stringify_str(value);
let escaped = json[1..json.len() - 1].cow_replace('\'', "\\'");
concat_string!("'", escaped, "'")
}

fn create_import_meta_resolve_context_dependency(
parser: &mut JavascriptParser,
param: &BasicEvaluatedExpression,
Expand Down Expand Up @@ -252,7 +259,7 @@ impl ImportMetaBuiltinProperty {
}

let replacement = match self.property {
ImportMetaKnownProperties::URL => concat_string!("'", plugin.import_meta_url(parser), "'"),
ImportMetaKnownProperties::URL => single_quoted_string(&plugin.import_meta_url(parser)),
ImportMetaKnownProperties::WEBPACK => plugin.import_meta_version(),
ImportMetaKnownProperties::MAIN => plugin.import_meta_main(parser),
ImportMetaKnownProperties::FILENAME | ImportMetaKnownProperties::DIRNAME => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ pub struct JavascriptParser<'parser> {
pub(crate) destructuring_assignment_properties: DestructuringAssignmentPropertiesMap,
pub(crate) dynamic_import_references: ImportsReferencesState,
pub(crate) common_js_require_references: RequireReferencesState,
pub(crate) created_require_references: CreatedRequireReferencesState,
pub(crate) created_require_references: CreatedRequireReferencesState<'parser>,
pub(crate) worker_index: u32,
pub(crate) parser_exports_state: Option<bool>,
pub(crate) local_modules: Vec<LocalModule>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,34 @@ const req = /* createRequire() */ undefined;

const bundledValue = __webpack_require__(/*! ./dep.js */ "./dep.js");

// ./preserve-import-meta.js


const preserve_import_meta_req = (0,external_node_module_namespaceObject.createRequire)(import.meta.url);

const preservedResolved = preserve_import_meta_req.resolve("path");

// ./index.js



const index_req = (0,external_node_module_namespaceObject.createRequire)(import.meta.url);

const index_req = (0,external_node_module_namespaceObject.createRequire)('<ROOT>/tests/rspack-test/esmOutputCases/create-require/import-meta-url-resolve-disabled/index.js');

const resolved = index_req.resolve("path");

it("should preserve import.meta.url when requireResolve is disabled", async () => {
it("should delegate import.meta.url parsing when requireResolve is disabled", async () => {
const fs = await import(/* webpackIgnore: true */ "node:fs");
const path = await import(/* webpackIgnore: true */ "node:path");
const source = fs.readFileSync(path.join(__rspack_import_meta_dirname__, "main.mjs"), "utf-8");
const runtimeCreateRequire =
"(0,external_node_module_namespaceObject." + "createRequire)(import.meta.url)";

expect(source.split(runtimeCreateRequire)).toHaveLength(2);
expect(source).not.toContain("file:" + "//");
expect(source).toContain("file:" + "//");
expect(source).toContain("/* createRequire() */ undefined");
expect(resolved).toBe("path");
expect(preservedResolved).toBe("path");
expect(bundledValue).toBe("dep");
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,34 @@ const req = /* createRequire() */ undefined;

const bundledValue = __rspack_context.r(/*! ./dep.js */ "./dep.js");

// ./preserve-import-meta.js


const preserve_import_meta_req = (0,external_node_module_namespaceObject.createRequire)(import.meta.url);

const preservedResolved = preserve_import_meta_req.resolve("path");

// ./index.js



const index_req = (0,external_node_module_namespaceObject.createRequire)(import.meta.url);

const index_req = (0,external_node_module_namespaceObject.createRequire)('<ROOT>/tests/rspack-test/esmOutputCases/create-require/import-meta-url-resolve-disabled/index.js');

const resolved = index_req.resolve("path");

it("should preserve import.meta.url when requireResolve is disabled", async () => {
it("should delegate import.meta.url parsing when requireResolve is disabled", async () => {
const fs = await import(/* webpackIgnore: true */ "node:fs");
const path = await import(/* webpackIgnore: true */ "node:path");
const source = fs.readFileSync(path.join(__rspack_import_meta_dirname__, "main.mjs"), "utf-8");
const runtimeCreateRequire =
"(0,external_node_module_namespaceObject." + "createRequire)(import.meta.url)";

expect(source.split(runtimeCreateRequire)).toHaveLength(2);
expect(source).not.toContain("file:" + "//");
expect(source).toContain("file:" + "//");
expect(source).toContain("/* createRequire() */ undefined");
expect(resolved).toBe("path");
expect(preservedResolved).toBe("path");
expect(bundledValue).toBe("dep");
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { createRequire } from "node:module";
import { bundledValue } from "./only-require.js";
import { preservedResolved } from "./preserve-import-meta.js";

const req = createRequire(import.meta.url);

export const resolved = req.resolve("path");

it("should preserve import.meta.url when requireResolve is disabled", async () => {
it("should delegate import.meta.url parsing when requireResolve is disabled", async () => {
const fs = await import(/* webpackIgnore: true */ "node:fs");
const path = await import(/* webpackIgnore: true */ "node:path");
const source = fs.readFileSync(path.join(__dirname, "main.mjs"), "utf-8");
const runtimeCreateRequire =
"(0,external_node_module_namespaceObject." + "createRequire)(import.meta.url)";

expect(source.split(runtimeCreateRequire)).toHaveLength(2);
expect(source).not.toContain("file:" + "//");
expect(source).toContain("file:" + "//");
expect(source).toContain("/* createRequire() */ undefined");
expect(resolved).toBe("path");
expect(preservedResolved).toBe("path");
expect(bundledValue).toBe("dep");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createRequire } from "node:module";

const req = createRequire(import.meta.url);

export const preservedResolved = req.resolve("path");
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,13 @@ module.exports = {
requireResolve: false,
},
},
rules: [
{
test: /preserve-import-meta\.js$/,
parser: {
importMeta: false,
},
},
],
},
};
Loading
Loading