From e20b308557d285d6ea4a1797b1f1412da69850bb Mon Sep 17 00:00:00 2001 From: "MK (fengmk2)" Date: Mon, 1 Jun 2026 13:05:30 +0800 Subject: [PATCH 1/3] fix bundled tsdown picomatch require --- .../package.json | 10 ++ .../pnpm-workspace.yaml | 1 + .../snap.txt | 7 ++ .../src/index.ts | 1 + .../steps.json | 11 +++ .../core/build-support/find-create-require.ts | 93 +++++++++++++------ 6 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/package.json create mode 100644 packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/pnpm-workspace.yaml create mode 100644 packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt create mode 100644 packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/src/index.ts create mode 100644 packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/package.json b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/package.json new file mode 100644 index 0000000000..11394423a1 --- /dev/null +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/package.json @@ -0,0 +1,10 @@ +{ + "name": "command-pack-picomatch-hoist-false", + "version": "1.0.0", + "type": "module", + "devDependencies": { + "typescript": "^6.0.3", + "vite-plus": "0.1.23" + }, + "packageManager": "pnpm@11.5.0" +} diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/pnpm-workspace.yaml b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/pnpm-workspace.yaml new file mode 100644 index 0000000000..9b21cd4885 --- /dev/null +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/pnpm-workspace.yaml @@ -0,0 +1 @@ +hoist: false diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt new file mode 100644 index 0000000000..5d09c5b959 --- /dev/null +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt @@ -0,0 +1,7 @@ +> pnpm install --ignore-scripts +> vp pack src/index.ts 2>&1 +ℹ entry: src/index.ts +ℹ Build start +ℹ dist/index.mjs kB │ gzip: kB +ℹ 1 files, total: kB +✔ Build complete in ms diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/src/index.ts b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/src/index.ts new file mode 100644 index 0000000000..efeee5db16 --- /dev/null +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/src/index.ts @@ -0,0 +1 @@ +export const value = 1; diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json new file mode 100644 index 0000000000..18a51b85c1 --- /dev/null +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json @@ -0,0 +1,11 @@ +{ + "linkCheckoutPackages": true, + "commands": [ + { + "command": "pnpm install --ignore-scripts", + "ignoreOutput": true, + "timeout": 120000 + }, + "vp pack src/index.ts 2>&1" + ] +} diff --git a/packages/core/build-support/find-create-require.ts b/packages/core/build-support/find-create-require.ts index 81e376d2eb..5834310c6c 100644 --- a/packages/core/build-support/find-create-require.ts +++ b/packages/core/build-support/find-create-require.ts @@ -54,14 +54,11 @@ export async function replaceThirdPartyCjsRequires( const thirdPartyModules = new Set(); // Find all createRequire patterns and their require calls - const results = [ - findCreateRequireInStaticImports(ast), - findCreateRequireInGlobalModule(ast), - ].filter((result): result is { requireVarName: string; calls: RequireCall[] } => Boolean(result)); + const results = [findCreateRequireInStaticImports(ast), findCreateRequireInGlobalModule(ast)]; // Collect all third-party require calls const replacements: RequireCall[] = []; - for (const { calls } of results) { + for (const calls of results) { for (const call of calls) { if (isThirdPartyModule(call.module)) { const parts = call.module.split('/'); @@ -129,20 +126,60 @@ function findRequireCalls(ast: ParseResult, requireVarName: string): RequireCall return calls; } +function getLiteralRequireArgument(node: CallExpression): RequireCall | undefined { + if (node.arguments.length === 0) { + return undefined; + } + const arg = node.arguments[0]; + if (arg.type !== 'Literal') { + return undefined; + } + const value = (arg as { value: unknown; start: number; end: number }).value; + if (typeof value !== 'string') { + return undefined; + } + return { + module: value, + start: arg.start, + end: arg.end, + }; +} + +function findDirectCreateRequireCalls( + ast: ParseResult, + isCreateRequireCall: (node: CallExpression) => boolean, +): RequireCall[] { + const calls: RequireCall[] = []; + + const visitor = new Visitor({ + CallExpression(node: CallExpression) { + if (node.callee.type !== 'CallExpression' || !isCreateRequireCall(node.callee)) { + return; + } + + const call = getLiteralRequireArgument(node); + if (call) { + calls.push(call); + } + }, + }); + + visitor.visit(ast.program); + return calls; +} + /** * Find createRequire from static imports and return the require variable name + all require calls * Handles: `import { createRequire } from "node:module"` then `const require = createRequire(...)` */ -function findCreateRequireInStaticImports( - ast: ParseResult, -): { requireVarName: string; calls: RequireCall[] } | undefined { +function findCreateRequireInStaticImports(ast: ParseResult): RequireCall[] { // Find import from 'module' or 'node:module' const importFromModule = ast.module.staticImports.find((imt) => { const { value } = imt.moduleRequest; return value === 'node:module' || value === 'module'; }); if (!importFromModule) { - return undefined; + return []; } // Find the createRequire import entry @@ -150,7 +187,7 @@ function findCreateRequireInStaticImports( return entry.importName.name === 'createRequire'; }); if (!createRequireEntry) { - return undefined; + return []; } const createRequireLocalName = createRequireEntry.localName.value; @@ -174,14 +211,14 @@ function findCreateRequireInStaticImports( }); varVisitor.visit(ast.program); - if (!requireVarName) { - return undefined; - } - - // Find all calls to the require variable - const calls = findRequireCalls(ast, requireVarName); + const calls = requireVarName ? findRequireCalls(ast, requireVarName) : []; + calls.push( + ...findDirectCreateRequireCalls(ast, (node) => { + return node.callee.type === 'Identifier' && node.callee.name === createRequireLocalName; + }), + ); - return { requireVarName, calls }; + return calls; } // Helper to check if an expression is `process` or `globalThis.process` @@ -240,9 +277,7 @@ function isGetBuiltinModuleCall(expr: Expression): boolean { * Handles: `const require = globalThis.process.getBuiltinModule("module").createRequire(import.meta.url)` * Or: `const require = process.getBuiltinModule("module").createRequire(import.meta.url)` */ -function findCreateRequireInGlobalModule( - ast: ParseResult, -): { requireVarName: string; calls: RequireCall[] } | undefined { +function findCreateRequireInGlobalModule(ast: ParseResult): RequireCall[] { let requireVarName: string | undefined; const visitor = new Visitor({ @@ -276,12 +311,16 @@ function findCreateRequireInGlobalModule( visitor.visit(ast.program); - if (!requireVarName) { - return undefined; - } - - // Find all calls to the require variable - const calls = findRequireCalls(ast, requireVarName); + const calls = requireVarName ? findRequireCalls(ast, requireVarName) : []; + calls.push( + ...findDirectCreateRequireCalls(ast, (node) => { + if (node.callee.type !== 'MemberExpression' || node.callee.computed) { + return false; + } + const callee = node.callee as StaticMemberExpression; + return callee.property.name === 'createRequire' && isGetBuiltinModuleCall(callee.object); + }), + ); - return { requireVarName, calls }; + return calls; } From 8863c94781af57ec469cad1426c24307ee1b9474 Mon Sep 17 00:00:00 2001 From: "MK (fengmk2)" Date: Mon, 1 Jun 2026 14:40:21 +0800 Subject: [PATCH 2/3] test pack picomatch with vp install --- .../command-pack-picomatch-hoist-false/snap.txt | 2 +- .../command-pack-picomatch-hoist-false/steps.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt index 5d09c5b959..d34c3488b2 100644 --- a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/snap.txt @@ -1,4 +1,4 @@ -> pnpm install --ignore-scripts +> vp install --ignore-scripts > vp pack src/index.ts 2>&1 ℹ entry: src/index.ts ℹ Build start diff --git a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json index 18a51b85c1..7b95ee9a26 100644 --- a/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json +++ b/packages/cli/snap-tests-global/command-pack-picomatch-hoist-false/steps.json @@ -2,7 +2,7 @@ "linkCheckoutPackages": true, "commands": [ { - "command": "pnpm install --ignore-scripts", + "command": "vp install --ignore-scripts", "ignoreOutput": true, "timeout": 120000 }, From 97317a78a0b7761f585fec87f98ca60dff78e5a0 Mon Sep 17 00:00:00 2001 From: "MK (fengmk2)" Date: Mon, 1 Jun 2026 14:52:23 +0800 Subject: [PATCH 3/3] dedupe require argument extraction --- .../core/build-support/find-create-require.ts | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/packages/core/build-support/find-create-require.ts b/packages/core/build-support/find-create-require.ts index 5834310c6c..40cb631d45 100644 --- a/packages/core/build-support/find-create-require.ts +++ b/packages/core/build-support/find-create-require.ts @@ -103,21 +103,9 @@ function findRequireCalls(ast: ParseResult, requireVarName: string): RequireCall return; } - // Extract the first argument (module specifier) - if (node.arguments.length === 0) { - return; - } - const arg = node.arguments[0]; - if (arg.type !== 'Literal') { - return; - } - const value = (arg as { value: unknown; start: number; end: number }).value; - if (typeof value === 'string') { - calls.push({ - module: value, - start: arg.start, - end: arg.end, - }); + const call = getLiteralRequireArgument(node); + if (call) { + calls.push(call); } }, });