fix: resolve extension dependency missing in shared chunks (#765) (#771)

This commit is contained in:
paisley
2026-04-07 10:04:03 +08:00
committed by GitHub
Unverified
parent c866205eac
commit 0cdd12cd40
2 changed files with 132 additions and 1 deletions

View File

@@ -266,6 +266,65 @@ for (const [realPath, pkgName] of collected) {
}
}
// 5b. Merge built-in extension node_modules into top-level node_modules
//
// OpenClaw 3.31+ ships built-in extensions (telegram, discord, etc.) under
// dist/extensions/<ext>/node_modules/. The Rollup bundler creates shared
// chunks at dist/ root (e.g. sticker-cache-*.js) that eagerly import
// extension-specific packages like "grammy". Node.js resolves bare
// specifiers from the importing file's directory upward:
// dist/ → openclaw/ → openclaw/node_modules/
// It does NOT search dist/extensions/telegram/node_modules/.
//
// Fix: copy extension deps into the top-level node_modules/ so they are
// resolvable from shared chunks. Skip-if-exists preserves version priority
// (openclaw's own deps take precedence over extension deps).
const extensionsDir = path.join(OUTPUT, 'dist', 'extensions');
let mergedExtCount = 0;
if (fs.existsSync(extensionsDir)) {
for (const extEntry of fs.readdirSync(extensionsDir, { withFileTypes: true })) {
if (!extEntry.isDirectory()) continue;
const extNM = path.join(extensionsDir, extEntry.name, 'node_modules');
if (!fs.existsSync(extNM)) continue;
for (const pkgEntry of fs.readdirSync(extNM, { withFileTypes: true })) {
if (!pkgEntry.isDirectory() || pkgEntry.name === '.bin') continue;
const srcPkg = path.join(extNM, pkgEntry.name);
if (pkgEntry.name.startsWith('@')) {
// Scoped package — iterate sub-entries
let scopeEntries;
try { scopeEntries = fs.readdirSync(srcPkg, { withFileTypes: true }); } catch { continue; }
for (const scopeEntry of scopeEntries) {
if (!scopeEntry.isDirectory()) continue;
const scopedName = `${pkgEntry.name}/${scopeEntry.name}`;
if (copiedNames.has(scopedName)) continue;
const srcScoped = path.join(srcPkg, scopeEntry.name);
const destScoped = path.join(outputNodeModules, pkgEntry.name, scopeEntry.name);
try {
fs.mkdirSync(normWin(path.dirname(destScoped)), { recursive: true });
fs.cpSync(normWin(srcScoped), normWin(destScoped), { recursive: true, dereference: true });
copiedNames.add(scopedName);
mergedExtCount++;
} catch { /* skip on copy error */ }
}
} else {
if (copiedNames.has(pkgEntry.name)) continue;
const destPkg = path.join(outputNodeModules, pkgEntry.name);
try {
fs.cpSync(normWin(srcPkg), normWin(destPkg), { recursive: true, dereference: true });
copiedNames.add(pkgEntry.name);
mergedExtCount++;
} catch { /* skip on copy error */ }
}
}
}
}
if (mergedExtCount > 0) {
echo` Merged ${mergedExtCount} extension packages into top-level node_modules`;
}
// 6. Clean up the bundle to reduce package size
//
// This removes platform-agnostic waste: dev artifacts, docs, source maps,