From 31d31576f9aff98209c8e83cc098e23e8061f5a7 Mon Sep 17 00:00:00 2001 From: Sehoon Shon Date: Wed, 25 Mar 2026 03:19:07 -0400 Subject: [PATCH] perf(build): optimize build speed and parallelize asset copying --- package.json | 3 ++ packages/a2a-server/package.json | 3 +- packages/cli/package.json | 3 +- packages/cli/tsconfig.json | 1 + packages/core/package.json | 3 +- packages/devtools/package.json | 3 +- packages/devtools/tsconfig.build.json | 4 +- packages/sdk/package.json | 3 +- packages/test-utils/package.json | 3 +- packages/vscode-ide-companion/package.json | 8 ++-- packages/vscode-ide-companion/tsconfig.json | 9 ++--- scripts/build.js | 27 ++++++++++++- scripts/build_package.js | 42 ++++++++------------- scripts/copy_files.js | 8 ++++ tsconfig.json | 12 +++++- 15 files changed, 85 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index d66132c066..993f3c5bfc 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,9 @@ "docs:settings": "tsx ./scripts/generate-settings-doc.ts", "docs:keybindings": "tsx ./scripts/generate-keybindings-doc.ts", "build": "node scripts/build.js", + "build:assets": "npm run copy:assets --workspaces --if-present", + "build:clients": "npm run build:client --workspaces --if-present", + "build:devs": "npm run build:dev --workspaces --if-present", "build-and-start": "npm run build && npm run start --", "build:vscode": "node scripts/build_vscode_companion.js", "build:all": "npm run build && npm run build:sandbox && npm run build:vscode", diff --git a/packages/a2a-server/package.json b/packages/a2a-server/package.json index 5257e56240..0eec708fb6 100644 --- a/packages/a2a-server/package.json +++ b/packages/a2a-server/package.json @@ -13,7 +13,8 @@ "gemini-cli-a2a-server": "dist/a2a-server.mjs" }, "scripts": { - "build": "node ../../scripts/build_package.js", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "tsc -b && npm run copy:assets", "start": "node dist/src/http/server.js", "lint": "eslint . --ext .ts,.tsx", "format": "prettier --write .", diff --git a/packages/cli/package.json b/packages/cli/package.json index 40acd6cf88..f3417b180e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -13,7 +13,8 @@ "gemini": "dist/index.js" }, "scripts": { - "build": "node ../../scripts/build_package.js", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "tsc -b && npm run copy:assets", "start": "node dist/index.js", "debug": "node --inspect-brk dist/index.js", "lint": "eslint . --ext .ts,.tsx", diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index e361d7ffe0..15d360793a 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", + "composite": true, "jsx": "react-jsx", "lib": ["DOM", "DOM.Iterable", "ES2023"], "types": ["node", "vitest/globals"] diff --git a/packages/core/package.json b/packages/core/package.json index de105d4389..aea19d9008 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -11,7 +11,8 @@ "main": "dist/index.js", "scripts": { "bundle:browser-mcp": "node scripts/bundle-browser-mcp.mjs", - "build": "node ../../scripts/build_package.js", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "tsc -b && npm run copy:assets", "lint": "eslint . --ext .ts,.tsx", "format": "prettier --write .", "test": "vitest run", diff --git a/packages/devtools/package.json b/packages/devtools/package.json index ed3160b7f1..69463aa093 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -12,7 +12,8 @@ } }, "scripts": { - "build": "npm run build:client && tsc -p tsconfig.build.json", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "npm run build:client && tsc -b tsconfig.build.json && npm run copy:assets", "build:client": "node esbuild.client.js" }, "files": [ diff --git a/packages/devtools/tsconfig.build.json b/packages/devtools/tsconfig.build.json index f90fcb9cac..80b71abdda 100644 --- a/packages/devtools/tsconfig.build.json +++ b/packages/devtools/tsconfig.build.json @@ -2,11 +2,11 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist/src", + "composite": true, "declaration": true, "sourceMap": true, "noEmit": false, - "composite": false, - "incremental": false, + "incremental": true, "verbatimModuleSyntax": false }, "include": ["src"] diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 7bd9c62d51..093637bf1e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -11,7 +11,8 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "build": "node ../../scripts/build_package.js", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "tsc -b && npm run copy:assets", "lint": "eslint . --ext .ts,.tsx", "format": "prettier --write .", "test": "vitest run", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index caedd907e4..a5d097e2bd 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -6,7 +6,8 @@ "license": "Apache-2.0", "type": "module", "scripts": { - "build": "node ../../scripts/build_package.js", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "tsc -b && npm run copy:assets", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index ac47bbf0be..8755704f1b 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -106,14 +106,16 @@ "main": "./dist/extension.cjs", "type": "module", "scripts": { - "prepackage": "npm run generate:notices && npm run check-types && npm run lint && npm run build:prod", - "build": "npm run build:dev", - "build:dev": "npm run check-types && npm run lint && node esbuild.js", + "prepackage": "npm run generate:notices && npm run validate && npm run build:prod", + "copy:assets": "node ../../scripts/copy_files.js", + "build": "npm run build:dev && npm run copy:assets", + "build:dev": "node esbuild.js", "build:prod": "node esbuild.js --production", "generate:notices": "node ./scripts/generate-notices.js", "prepare": "npm run generate:notices", "check-types": "tsc --noEmit", "lint": "eslint src", + "validate": "npm run check-types && npm run lint", "watch": "npm-run-all2 -p watch:*", "watch:esbuild": "node esbuild.js --watch", "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", diff --git a/packages/vscode-ide-companion/tsconfig.json b/packages/vscode-ide-companion/tsconfig.json index f135706485..99106a5115 100644 --- a/packages/vscode-ide-companion/tsconfig.json +++ b/packages/vscode-ide-companion/tsconfig.json @@ -5,12 +5,9 @@ "target": "ES2022", "lib": ["ES2022", "dom"], "sourceMap": true, - /* - * skipLibCheck is necessary because the a2a-server package depends on - * @google-cloud/storage which pulls in @types/request which depends on - * tough-cookie@4.x while jsdom requires tough-cookie@5.x. This causes a - * type checking error in ../../node_modules/@types/request/index.d.ts. - */ + "composite": true, + "declaration": true, + "incremental": true, "skipLibCheck": true, "rootDir": "src", "strict": true /* enable all strict type-checking options */ diff --git a/scripts/build.js b/scripts/build.js index 8a525e98e3..a9027c0639 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -18,7 +18,7 @@ // limitations under the License. import { execSync } from 'node:child_process'; -import { existsSync } from 'node:fs'; +import { existsSync, writeFileSync, readdirSync, statSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -31,8 +31,19 @@ if (!existsSync(join(root, 'node_modules'))) { } // build all workspaces/packages +console.log('Generating commit info...'); execSync('npm run generate', { stdio: 'inherit', cwd: root }); -execSync('npm run build --workspaces', { stdio: 'inherit', cwd: root }); + +console.log('Building TypeScript packages (incremental)...'); +execSync('npx tsc -b', { stdio: 'inherit', cwd: root }); + +console.log( + 'Running asset copy and package-specific build steps in parallel...', +); +execSync('npx npm-run-all --parallel build:assets build:clients build:devs', { + stdio: 'inherit', + cwd: root, +}); // also build container image if sandboxing is enabled // skip (-s) npm install + build since we did that above @@ -53,3 +64,15 @@ try { } catch { // ignore } + +// Final step: update the .last_build timestamp for all packages to ensure +// they are newer than any files modified during the build (like git-commit.ts). +console.log('Updating build timestamps...'); +const packagesDir = join(root, 'packages'); +const packages = readdirSync(packagesDir); +for (const pkg of packages) { + const distDir = join(packagesDir, pkg, 'dist'); + if (existsSync(distDir) && statSync(distDir).isDirectory()) { + writeFileSync(join(distDir, '.last_build'), ''); + } +} diff --git a/scripts/build_package.js b/scripts/build_package.js index 279e46fa94..0c209d7dc6 100644 --- a/scripts/build_package.js +++ b/scripts/build_package.js @@ -18,41 +18,29 @@ // limitations under the License. import { execSync } from 'node:child_process'; -import { writeFileSync, existsSync, cpSync } from 'node:fs'; -import { join, basename } from 'node:path'; +import { writeFileSync, existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; if (!process.cwd().includes('packages')) { console.error('must be invoked from a package directory'); process.exit(1); } -const packageName = basename(process.cwd()); +// build typescript files incrementally +execSync('tsc -b', { stdio: 'inherit' }); -// build typescript files -execSync('tsc --build', { stdio: 'inherit' }); - -// Run package-specific bundling if the script exists -const bundleScript = join(process.cwd(), 'scripts', 'bundle-browser-mcp.mjs'); -if (packageName === 'core' && existsSync(bundleScript)) { - console.log('Running chrome devtools MCP bundling...'); - execSync('npm run bundle:browser-mcp', { - stdio: 'inherit', - }); -} - -// copy .{md,json} files -execSync('node ../../scripts/copy_files.js', { stdio: 'inherit' }); - -// Copy documentation for the core package -if (packageName === 'core') { - const docsSource = join(process.cwd(), '..', '..', 'docs'); - const docsTarget = join(process.cwd(), 'dist', 'docs'); - if (existsSync(docsSource)) { - cpSync(docsSource, docsTarget, { recursive: true, dereference: true }); - console.log('Copied documentation to dist/docs'); - } +// Check for copy:assets script in package.json +const packageJson = JSON.parse(readFileSync('package.json', 'utf8')); +if (packageJson.scripts && packageJson.scripts['copy:assets']) { + execSync('npm run copy:assets', { stdio: 'inherit' }); +} else { + // fallback to generic copy + execSync('node ../../scripts/copy_files.js', { stdio: 'inherit' }); } // touch dist/.last_build -writeFileSync(join(process.cwd(), 'dist', '.last_build'), ''); +const distDir = join(process.cwd(), 'dist'); +if (existsSync(distDir)) { + writeFileSync(join(distDir, '.last_build'), ''); +} process.exit(0); diff --git a/scripts/copy_files.js b/scripts/copy_files.js index d02070362f..01303ee771 100644 --- a/scripts/copy_files.js +++ b/scripts/copy_files.js @@ -81,6 +81,14 @@ if (packageName === 'core') { if (fs.existsSync(builtinSkillsSource)) { fs.cpSync(builtinSkillsSource, builtinSkillsTarget, { recursive: true }); } + + // Copy documentation for the core package + const docsSource = path.join(process.cwd(), '..', '..', 'docs'); + const docsTarget = path.join(process.cwd(), 'dist', 'docs'); + if (fs.existsSync(docsSource)) { + fs.cpSync(docsSource, docsTarget, { recursive: true, dereference: true }); + console.log('Copied documentation to dist/docs'); + } } console.log('Successfully copied files.'); diff --git a/tsconfig.json b/tsconfig.json index c4542cc833..8c39e2c6bc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,5 +27,15 @@ "target": "es2022", "types": ["node", "vitest/globals"], "jsx": "react-jsx" - } + }, + "files": [], + "references": [ + { "path": "packages/core" }, + { "path": "packages/cli" }, + { "path": "packages/sdk" }, + { "path": "packages/a2a-server" }, + { "path": "packages/test-utils" }, + { "path": "packages/devtools/tsconfig.build.json" }, + { "path": "packages/vscode-ide-companion" } + ] }