diff --git a/src/js_parser/fold.rs b/src/js_parser/fold.rs index 911e1e76de30..58e22a1dc902 100644 --- a/src/js_parser/fold.rs +++ b/src/js_parser/fold.rs @@ -678,7 +678,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O } if name == b"accept" { if !enabled { - p.method_call_must_be_replaced_with_undefined = true; + if identifier_opts.is_call_target() { + p.method_call_must_be_replaced_with_undefined = true; + } return Some(Expr { data: js_ast::ExprData::EUndefined(E::Undefined), loc, @@ -712,7 +714,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O loc, )); } else { - p.method_call_must_be_replaced_with_undefined = true; + if identifier_opts.is_call_target() { + p.method_call_must_be_replaced_with_undefined = true; + } return Some(Expr { data: js_ast::ExprData::EUndefined(E::Undefined), loc, diff --git a/test/bundler/bundler_minify.test.ts b/test/bundler/bundler_minify.test.ts index f6220592d6d9..cbc6544fb9ef 100644 --- a/test/bundler/bundler_minify.test.ts +++ b/test/bundler/bundler_minify.test.ts @@ -667,6 +667,61 @@ describe("bundler", () => { api.expectFile("/out.js").not.toContain("import.meta.hot"); }, }); + // Reading an `import.meta.hot` method without calling it must not cause the + // next unrelated call expression to be dropped from the output. + itBundled("minify/ImportMetaHotReadWithoutCall", { + files: { + "/entry.ts": ` + globalThis.sink = import.meta.hot.accept; + console.log("after-accept"); + globalThis.sink = import.meta.hot.dispose; + console.log("after-dispose"); + globalThis.sink = [ + import.meta.hot.decline, + import.meta.hot.prune, + import.meta.hot.invalidate, + import.meta.hot.on, + import.meta.hot.off, + import.meta.hot.send, + ]; + console.log("after-array"); + // Direct calls are still stripped. + import.meta.hot.accept(() => console.log("FAIL-accept-call")); + import.meta.hot.dispose(() => console.log("FAIL-dispose-call")); + console.log("after-calls"); + `, + }, + outfile: "/out.js", + run: { + stdout: "after-accept\nafter-dispose\nafter-array\nafter-calls", + }, + onAfterBundle(api) { + const out = api.readFile("/out.js"); + expect(out).toContain("after-accept"); + expect(out).toContain("after-dispose"); + expect(out).toContain("after-array"); + expect(out).toContain("after-calls"); + expect(out).not.toContain("FAIL"); + expect(out).not.toContain("import.meta.hot"); + }, + }); + itBundled("minify/ImportMetaHotReadWithoutCallNoBundle", { + files: { + "/entry.ts": ` + globalThis.sink = import.meta.hot.accept; + console.log("after-accept"); + globalThis.sink = import.meta.hot.dispose; + console.log("after-dispose"); + `, + }, + bundling: false, + outfile: "/out.js", + onAfterBundle(api) { + const out = api.readFile("/out.js"); + expect(out).toContain("after-accept"); + expect(out).toContain("after-dispose"); + }, + }); itBundled("minify/ProductionMode", { files: { "/entry.jsx": `