fix(package): restore npm package size headroom (#129782)

* fix(package): externalize diffs build outputs

* chore: remove release-owned changelog entry

* fix(build): generate selected plugin assets before Docker staging

---------

Co-authored-by: Dallin Romney <dallinromney@gmail.com>
This commit is contained in:
Vincent Koc
2026-08-26 12:40:27 +08:00
committed by GitHub
parent a5f36aef39
commit 2b06180bb5
10 changed files with 73 additions and 46 deletions
@@ -28,6 +28,7 @@
"build": "node --import tsx ../../scripts/build-diffs-viewer-runtime.mts full"
},
"build": {
"bundledDist": false,
"openclawVersion": "2026.8.1",
"staticAssets": [
{
+1
View File
@@ -34,6 +34,7 @@
"build": "node --import tsx ../../scripts/build-diffs-viewer-runtime.mts curated"
},
"build": {
"bundledDist": false,
"openclawVersion": "2026.8.1",
"staticAssets": [
{
+1 -1
View File
@@ -1517,7 +1517,7 @@
"audit:seams": "node --import tsx scripts/audit-seams.mts",
"build": "node --import tsx scripts/build-all.mts",
"build:ci-artifacts": "node --import tsx scripts/build-all.mts ciArtifacts",
"build:docker": "node --import tsx scripts/tsdown-build.mts && node --import tsx scripts/check-cli-bootstrap-imports.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/build-stamp.mts && node --import tsx scripts/runtime-postbuild-stamp.mts && pnpm plugins:assets:build && pnpm plugins:assets:copy && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts",
"build:docker": "pnpm plugins:assets:build && node --import tsx scripts/tsdown-build.mts && node --import tsx scripts/check-cli-bootstrap-imports.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/build-stamp.mts && node --import tsx scripts/runtime-postbuild-stamp.mts && pnpm plugins:assets:copy && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-startup-metadata.ts",
"build:package": "node --import tsx scripts/build-all.mts package",
"build:plugin-sdk:dts": "node scripts/run-tsgo.mjs -p tsconfig.plugin-sdk.dts.json --declaration true",
"build:plugin-sdk:strict-smoke": "node --import tsx scripts/tsdown-build.mts && node scripts/runtime-postbuild.mjs && node --import tsx scripts/run-with-env.mts OPENCLAW_PLUGIN_SDK_CANONICAL_DTS=1 -- node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/check-plugin-sdk-exports.mts",
+1
View File
@@ -14,6 +14,7 @@ export type BundledPluginBuildEntryParams = {
export const NON_PACKAGED_BUNDLED_PLUGIN_DIRS: Set<string>;
export const DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV: string;
export function parseDockerSelectedPluginBuildIdFilter(env?: NodeJS.ProcessEnv): Set<string> | null;
export function collectPluginSourceEntries(packageJson: unknown): string[];
export function collectTopLevelPublicSurfaceEntries(pluginDir: string): string[];
export function collectRootPackageExcludedExtensionDirs(
+1 -1
View File
@@ -37,7 +37,7 @@ function parseBundledPluginBuildIdFilter(env = process.env) {
);
}
function parseDockerSelectedPluginBuildIdFilter(env = process.env) {
export function parseDockerSelectedPluginBuildIdFilter(env = process.env) {
const raw = env[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV];
if (typeof raw !== "string" || raw.trim() === "") {
return null;
+18 -4
View File
@@ -2,6 +2,7 @@
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { parseDockerSelectedPluginBuildIdFilter } from "./bundled-plugin-build-entries.mjs";
import { isRecord } from "./record-shared.mjs";
type StaticExtensionAsset = {
@@ -13,6 +14,7 @@ type StaticExtensionAsset = {
type StaticExtensionAssetParams = {
rootDir?: string;
fs?: typeof fs;
env?: NodeJS.ProcessEnv;
includeExternalPlugins?: boolean;
assets?: StaticExtensionAsset[];
warn?: (message: string) => void;
@@ -164,6 +166,7 @@ export function discoverStaticExtensionAssets(params: StaticExtensionAssetParams
const rootDir = params.rootDir ?? process.cwd();
const fsImpl = params.fs ?? fs;
const includeExternalPlugins = params.includeExternalPlugins ?? false;
const dockerSelectedPluginIds = parseDockerSelectedPluginBuildIdFilter(params.env ?? process.env);
const assets: StaticExtensionAsset[] = [];
for (const { dirName, hasPackageJson, packageJsonPath } of listExtensionPackageDirs(
rootDir,
@@ -173,7 +176,11 @@ export function discoverStaticExtensionAssets(params: StaticExtensionAssetParams
continue;
}
const packageJson = readJsonFile(packageJsonPath, fsImpl);
if (!includeExternalPlugins && isExternalDistPackage(packageJson)) {
if (
!includeExternalPlugins &&
isExternalDistPackage(packageJson) &&
!dockerSelectedPluginIds?.has(dirName)
) {
continue;
}
for (const entry of readPackageStaticAssetEntries(packageJson)) {
@@ -196,7 +203,8 @@ function discoverStaticExtensionRuntimeOverlayAssets(params: StaticExtensionAsse
const rootDir = params.rootDir ?? process.cwd();
const fsImpl = params.fs ?? fs;
const assetsByDest = new Map<string, StaticExtensionAsset>();
for (const asset of params.assets ?? discoverStaticExtensionAssets({ rootDir, fs: fsImpl })) {
for (const asset of params.assets ??
discoverStaticExtensionAssets({ rootDir, fs: fsImpl, env: params.env })) {
assetsByDest.set(asset.dest, asset);
}
for (const { dirName, packageDir } of listDistExtensionPackageDirs(rootDir, fsImpl)) {
@@ -278,7 +286,8 @@ export function listGeneratedExtensionAssetSources(params: StaticExtensionAssetP
export function copyStaticExtensionAssets(params: StaticExtensionAssetParams = {}) {
const rootDir = params.rootDir ?? process.cwd();
const fsImpl = params.fs ?? fs;
const assets = params.assets ?? discoverStaticExtensionAssets({ rootDir, fs: fsImpl });
const assets =
params.assets ?? discoverStaticExtensionAssets({ rootDir, fs: fsImpl, env: params.env });
const warn = params.warn ?? console.warn;
for (const { src, dest } of assets) {
const srcPath = path.join(rootDir, src);
@@ -332,7 +341,12 @@ export function copyStaticExtensionAssetsForPackage(
const fsImpl = params.fs ?? fs;
const assets =
params.assets ??
discoverStaticExtensionAssets({ rootDir, fs: fsImpl, includeExternalPlugins: true });
discoverStaticExtensionAssets({
rootDir,
fs: fsImpl,
env: params.env,
includeExternalPlugins: true,
});
const packagePrefix = `extensions/${params.pluginDir}/`;
const rootDistPrefix = `dist/extensions/${params.pluginDir}/`;
const copied: string[] = [];
+11
View File
@@ -182,6 +182,17 @@ describe("package scripts", () => {
);
});
it("builds generated plugin assets before Docker runtime postbuild", () => {
const commands = expectDefined(
readPackageJson().scripts["build:docker"],
"package script build:docker",
).split(" && ");
expect(commands.indexOf("pnpm plugins:assets:build")).toBeLessThan(
commands.indexOf("node scripts/runtime-postbuild.mjs"),
);
});
it("cleans package builds before validating release contents", () => {
const scripts = readPackageJson().scripts;
@@ -13,9 +13,15 @@ describe("external plugin local dist build", () => {
const packageDirs = listExternalPluginLocalDistPackageDirs();
const excludedPluginIds = collectRootPackageExcludedExtensionDirs();
expect(packageDirs).toHaveLength(61);
expect(packageDirs).toHaveLength(63);
expect(packageDirs).toEqual(
expect.arrayContaining(["extensions/slack", "extensions/sms", "extensions/mxc"]),
expect.arrayContaining([
"extensions/diffs",
"extensions/diffs-language-pack",
"extensions/slack",
"extensions/sms",
"extensions/mxc",
]),
);
expect(packageDirs).not.toContain("extensions/whatsapp");
expect(
@@ -196,7 +196,14 @@ describe("bundled plugin build entries", () => {
const entries = listBundledPluginBuildEntries();
const artifacts = listBundledPluginPackArtifacts();
for (const pluginId of ["copilot", "openshell", "slack", "tokenjuice"]) {
for (const pluginId of [
"copilot",
"diffs",
"diffs-language-pack",
"openshell",
"slack",
"tokenjuice",
]) {
expectNoPrefixMatches(Object.keys(entries), `extensions/${pluginId}/`);
expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`);
}
+23 -37
View File
@@ -108,8 +108,6 @@ describe("runtime postbuild static assets", () => {
"dist/extensions/acpx/mcp-command-line.mjs",
"dist/extensions/acpx/mcp-proxy.mjs",
"dist/extensions/crabbox/assets/openclaw-worker-wallpaper.png",
"dist/extensions/diffs-language-pack/assets/viewer-runtime.js",
"dist/extensions/diffs/assets/viewer-runtime.js",
"dist/extensions/discord/assets/embedded-app-sdk.mjs",
"dist/extensions/onepassword/onepassword-op-path.js",
"dist/extensions/onepassword/onepassword-secret-id.js",
@@ -117,8 +115,10 @@ describe("runtime postbuild static assets", () => {
"dist/extensions/vault/vault-secret-id.js",
"dist/extensions/vault/vault-secret-ref-resolver.js",
]);
expect(payload.sources).toContain("extensions/diffs-language-pack/assets/viewer-runtime.js");
expect(payload.sources).toContain("extensions/diffs/assets/viewer-runtime.js");
expect(payload.sources).not.toContain(
"extensions/diffs-language-pack/assets/viewer-runtime.js",
);
expect(payload.sources).not.toContain("extensions/diffs/assets/viewer-runtime.js");
expect(payload.sources).toContain("extensions/discord/assets/embedded-app-sdk.mjs");
expect(payload.sources).toContain("extensions/crabbox/assets/openclaw-worker-wallpaper.png");
});
@@ -177,7 +177,15 @@ describe("runtime postbuild static assets", () => {
expect(discoverStaticExtensionAssets({ rootDir })).toEqual([]);
});
it("excludes external plugin (bundledDist: false) static assets by default", async () => {
it.each([
{ name: "normal root build", params: {}, included: false },
{ name: "isolated external build", params: { includeExternalPlugins: true }, included: true },
{
name: "Docker-selected build",
params: { env: { OPENCLAW_INTERNAL_DOCKER_BUILD_PLUGIN_IDS: "external-demo" } },
included: true,
},
])("$name handles external plugin assets", async ({ params, included }) => {
const rootDir = createTempDir("openclaw-runtime-postbuild-");
const packageDir = path.join(rootDir, "extensions", "external-demo");
await fs.mkdir(packageDir, { recursive: true });
@@ -200,39 +208,17 @@ describe("runtime postbuild static assets", () => {
"utf8",
);
expect(discoverStaticExtensionAssets({ rootDir })).toEqual([]);
});
it("includes external plugin (bundledDist: false) static assets when includeExternalPlugins is true", async () => {
const rootDir = createTempDir("openclaw-runtime-postbuild-");
const packageDir = path.join(rootDir, "extensions", "external-demo");
await fs.mkdir(packageDir, { recursive: true });
await fs.writeFile(
path.join(packageDir, "package.json"),
JSON.stringify({
name: "@openclaw/external-demo",
openclaw: {
build: {
bundledDist: false,
staticAssets: [
{
source: "./assets/runtime.js",
output: "assets/runtime.js",
},
],
},
},
}),
"utf8",
expect(discoverStaticExtensionAssets({ rootDir, ...params })).toEqual(
included
? [
{
pluginDir: "external-demo",
src: "extensions/external-demo/assets/runtime.js",
dest: "dist/extensions/external-demo/assets/runtime.js",
},
]
: [],
);
expect(discoverStaticExtensionAssets({ rootDir, includeExternalPlugins: true })).toEqual([
{
pluginDir: "external-demo",
src: "extensions/external-demo/assets/runtime.js",
dest: "dist/extensions/external-demo/assets/runtime.js",
},
]);
});
it("copies declared static assets into root and package dist", async () => {