Skip to content
Merged
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
8 changes: 7 additions & 1 deletion tools/egg-bundler/src/lib/Bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,13 @@ export class Bundler {
#renderImportMetaObject(declarationKind: string, metaName: string): string {
return `${declarationKind} ${metaName} = (() => {
const filename = ${IMPORT_META_FILENAME_EXPR};
const dirname = typeof __dirname === "string" ? __dirname : filename.replace(/[\\\\/][^\\\\/]*$/, "");
const dirname = (() => {
const slashIndex = Math.max(filename.lastIndexOf("/"), filename.lastIndexOf("\\\\"));
if (slashIndex > 2 || (slashIndex > 0 && !/^[A-Za-z]:[\\\\/]/.test(filename))) return filename.slice(0, slashIndex);
if (slashIndex === 2 && /^[A-Za-z]:[\\\\/]/.test(filename)) return filename.slice(0, 3);
if (slashIndex === 0) return filename[0];
return ".";
})();
const url = (() => { const u = new URL("file:///"); u.pathname = filename.replace(/\\\\/g, "/"); return u.href; })();
return {
get url () {
Expand Down
47 changes: 47 additions & 0 deletions tools/egg-bundler/test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,53 @@ globalThis.__patchedMeta = {
expect(bm.chunks).not.toEqual(expect.arrayContaining([expect.stringContaining('.js.map')]));
});

it('patches import.meta chunks without touching a shadowed __dirname binding', async () => {
const shadowedDirnameMeta = `const __TURBOPACK__import$2e$meta__ = { get url () { return "file:///already-patched.js"; } };
globalThis.__patchedMeta = {
dirname: __TURBOPACK__import$2e$meta__.dirname
};
const __dirname = "/generated/shadow";
`;

const buildFunc: BuildFunc = async () => {
await fs.writeFile(path.join(tmpOutput, 'worker.js'), '// mock worker entry\n');
await fs.writeFile(path.join(tmpOutput, 'shadowed-dirname.js'), shadowedDirnameMeta);
};

await bundle({
baseDir: tmpApp,
outputDir: tmpOutput,
pack: { buildFunc },
});

interface Sandbox {
URL: typeof URL;
process: { argv: string[]; cwd: () => string };
globalThis: Sandbox;
__dirname: string;
__filename: string;
__patchedMeta?: { dirname: string };
}

const content = await fs.readFile(path.join(tmpOutput, 'shadowed-dirname.js'), 'utf8');
function runWithFilename(filename: string): { dirname: string } {
const sandbox = {
URL,
process: { argv: ['node', 'worker.js'], cwd: () => tmpOutput },
__filename: filename,
__dirname: path.dirname(filename),
} as Sandbox;
sandbox.globalThis = sandbox;
runInNewContext(content, sandbox);
return sandbox.__patchedMeta!;
}

const filename = path.join(tmpOutput, 'shadowed-dirname.js');
expect(runWithFilename(filename)).toEqual({ dirname: path.dirname(filename) });
expect(runWithFilename('/worker.js')).toEqual({ dirname: '/' });
expect(runWithFilename('C:\\worker.js')).toEqual({ dirname: 'C:\\' });
});

it('rejects Windows drive-absolute output paths before resolving bundle files', () => {
expect(() => sanitizeBundleOutputRelativePath('C:/foo.js')).toThrow(/Unsafe bundle output path/);
expect(() => sanitizeBundleOutputRelativePath('C:\\foo.js')).toThrow(/Unsafe bundle output path/);
Expand Down
Loading