mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 03:48:56 +00:00
Fix import.meta handling in CJS format
In CommonJS format, import.meta and import.meta.url need to be
transformed into valid CJS equivalents:
- import.meta -> {url: require('url').pathToFileURL(__filename).href}
- import.meta.url -> require('url').pathToFileURL(__filename).href
This change updates js_printer.zig to handle these transformations
when module_type is .cjs. The ESM format remains unchanged.
Added comprehensive tests to verify the transformation works correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2017,6 +2017,16 @@ fn NewPrinter(
|
||||
bun.assert(p.options.hmr_ref.isValid());
|
||||
p.printSymbol(p.options.hmr_ref);
|
||||
p.print(".importMeta");
|
||||
} else if (p.options.module_type == .cjs) {
|
||||
// In CJS format, import.meta should be transformed into an object
|
||||
// with at least the `url` property
|
||||
if (p.options.import_meta_ref.isValid()) {
|
||||
// Use the synthetic import.meta ref if available
|
||||
p.printSymbol(p.options.import_meta_ref);
|
||||
} else {
|
||||
// Create import.meta object inline
|
||||
p.print("{url: require('url').pathToFileURL(__filename).href}");
|
||||
}
|
||||
} else if (!p.options.import_meta_ref.isValid()) {
|
||||
// Most of the time, leave it in there
|
||||
p.print("import.meta");
|
||||
@@ -2026,10 +2036,6 @@ fn NewPrinter(
|
||||
//
|
||||
// This is currently only used in Bun's runtime for CommonJS modules
|
||||
// referencing import.meta
|
||||
//
|
||||
// TODO: This assertion trips when using `import.meta` with `--format=cjs`
|
||||
bun.debugAssert(p.options.module_type == .cjs);
|
||||
|
||||
p.printSymbol(p.options.import_meta_ref);
|
||||
}
|
||||
},
|
||||
@@ -2402,6 +2408,14 @@ fn NewPrinter(
|
||||
p.printInlinedEnum(inlined, e.name, level);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle import.meta.url in CJS format
|
||||
if (p.options.module_type == .cjs and e.target.data == .e_import_meta and strings.eqlComptime(e.name, "url")) {
|
||||
p.printSpaceBeforeIdentifier();
|
||||
p.addSourceMapping(expr.loc);
|
||||
p.print("require('url').pathToFileURL(__filename).href");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (flags.contains(.has_non_optional_chain_parent)) {
|
||||
wrap = true;
|
||||
|
||||
131
test/regression/issue/import-meta-cjs-format.test.ts
Normal file
131
test/regression/issue/import-meta-cjs-format.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
import { tmpdir } from "os";
|
||||
import { join } from "path";
|
||||
|
||||
describe("import.meta in CJS format", () => {
|
||||
test("import.meta should be transformed to object in CJS format", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "import-meta-cjs-"));
|
||||
|
||||
try {
|
||||
const entryFile = join(dir, "entry.js");
|
||||
const outFile = join(dir, "out.js");
|
||||
|
||||
writeFileSync(
|
||||
entryFile,
|
||||
`console.log(typeof import.meta);
|
||||
console.log(import.meta);`,
|
||||
);
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), "build", entryFile, "--format=cjs", `--outfile=${outFile}`],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
const output = await Bun.file(outFile).text();
|
||||
|
||||
// import.meta should be transformed into an object
|
||||
expect(output).toContain("{url: require('url').pathToFileURL(__filename).href}");
|
||||
expect(output).not.toContain("import.meta");
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("import.meta.url should be transformed in CJS format", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "import-meta-url-cjs-"));
|
||||
|
||||
try {
|
||||
const entryFile = join(dir, "entry.js");
|
||||
const outFile = join(dir, "out.js");
|
||||
|
||||
writeFileSync(entryFile, `console.log(import.meta.url);`);
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), "build", entryFile, "--format=cjs", `--outfile=${outFile}`],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
const output = await Bun.file(outFile).text();
|
||||
|
||||
// import.meta.url should be transformed
|
||||
expect(output).toContain("require('url').pathToFileURL(__filename).href");
|
||||
expect(output).not.toContain("import.meta.url");
|
||||
expect(output).not.toContain("import.meta");
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("multiple import.meta.url references should be transformed", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "import-meta-url-multiple-"));
|
||||
|
||||
try {
|
||||
const entryFile = join(dir, "entry.js");
|
||||
const outFile = join(dir, "out.js");
|
||||
|
||||
writeFileSync(
|
||||
entryFile,
|
||||
`const url1 = import.meta.url;
|
||||
const url2 = import.meta.url;
|
||||
console.log(url1, url2);`,
|
||||
);
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), "build", entryFile, "--format=cjs", `--outfile=${outFile}`],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
const output = await Bun.file(outFile).text();
|
||||
|
||||
// All import.meta.url should be transformed
|
||||
expect(output).not.toContain("import.meta");
|
||||
const matches = output.match(/require\('url'\)\.pathToFileURL\(__filename\)\.href/g);
|
||||
expect(matches).not.toBeNull();
|
||||
expect(matches!.length).toBe(2);
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("import.meta in ESM format should remain unchanged", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "import-meta-esm-"));
|
||||
|
||||
try {
|
||||
const entryFile = join(dir, "entry.js");
|
||||
const outFile = join(dir, "out.js");
|
||||
|
||||
writeFileSync(
|
||||
entryFile,
|
||||
`console.log(import.meta);
|
||||
console.log(import.meta.url);`,
|
||||
);
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), "build", entryFile, "--format=esm", `--outfile=${outFile}`],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
const output = await Bun.file(outFile).text();
|
||||
|
||||
// import.meta should remain in ESM format
|
||||
expect(output).toContain("import.meta");
|
||||
expect(output).not.toContain("require('url').pathToFileURL(__filename).href");
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user