devops: consolidate build.js files (#35935)

This commit is contained in:
Yury Semikhatsky 2025-05-12 19:22:14 -07:00 committed by GitHub
parent f38ee4e212
commit d8193ca947
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 92 additions and 379 deletions

View File

@ -1,51 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
const path = require('path');
const esbuild = require('esbuild');
/**
* @param {boolean} watchMode
* @returns {import('esbuild').BuildOptions}
*/
function esbuildOptions(watchMode) {
return {
entryPoints: [path.join(__dirname, 'src/index.ts')],
bundle: true,
outdir: path.join(__dirname, 'lib'),
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
};
}
async function main() {
const watchMode = process.argv.includes('--watch');
const ctx = await esbuild.context(esbuildOptions(watchMode));
await ctx.rebuild();
if (watchMode)
await ctx.watch();
else
await ctx.dispose();
}
module.exports = { esbuildOptions };
if (require.main === module)
main();

View File

@ -1,67 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
const path = require('path');
const esbuild = require('esbuild');
const fs = require('fs');
const outdir = path.join(__dirname, '../../lib/utilsBundleImpl');
function copyXdgOpen() {
if (!fs.existsSync(outdir))
fs.mkdirSync(outdir, { recursive: true });
// 'open' package requires 'xdg-open' binary to be present, which does not get bundled by esbuild.
fs.copyFileSync(path.join(__dirname, 'node_modules/open/xdg-open'), path.join(outdir, 'xdg-open'));
console.log('==== Copied xdg-open to', path.join(outdir, 'xdg-open'));
}
/**
* @param {boolean} watchMode
* @returns {import('esbuild').BuildOptions}
*/
function esbuildOptions(watchMode) {
return {
entryPoints: [path.join(__dirname, 'src/utilsBundleImpl.ts')],
bundle: true,
outfile: path.join(outdir, 'index.js'),
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
minify: !watchMode,
};
}
async function main() {
copyXdgOpen();
const watchMode = process.argv.includes('--watch');
const ctx = await esbuild.context(esbuildOptions(watchMode));
await ctx.rebuild();
if (watchMode)
await ctx.watch();
else
await ctx.dispose();
}
module.exports = {
beforeEsbuild: copyXdgOpen,
esbuildOptions,
};
if (require.main === module)
main();

View File

@ -2,12 +2,6 @@
"name": "utils-bundle",
"version": "0.0.1",
"private": true,
"scripts": {
"esbuild": "node build.js",
"build": "npm run esbuild",
"watch": "npm run esbuild -- --watch",
"generate-license": "node ../../../../utils/generate_third_party_notice.js"
},
"dependencies": {
"colors": "1.4.0",
"commander": "8.3.0",

View File

@ -1,51 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
const path = require('path');
const esbuild = require('esbuild');
/**
* @param {boolean} watchMode
* @returns {import('esbuild').BuildOptions}
*/
function esbuildOptions(watchMode) {
return {
entryPoints: [path.join(__dirname, 'src/zipBundleImpl.ts')],
bundle: true,
outdir: path.join(__dirname, '../../lib'),
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
minify: !watchMode,
};
}
async function main() {
const watchMode = process.argv.includes('--watch');
const ctx = await esbuild.context(esbuildOptions(watchMode));
await ctx.rebuild();
if (watchMode)
await ctx.watch();
else
await ctx.dispose();
}
module.exports = { esbuildOptions };
if (require.main === module)
main();

View File

@ -2,12 +2,6 @@
"name": "zip-bundle",
"version": "0.0.1",
"private": true,
"scripts": {
"esbuild": "node build.js",
"build": "npm run esbuild",
"watch": "npm run esbuild -- --watch",
"generate-license": "node ../../../../utils/generate_third_party_notice.js"
},
"dependencies": {
"debug": "^4.1.1",
"get-stream": "^5.1.0",

View File

@ -1,52 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
const path = require('path');
const esbuild = require('esbuild');
/**
* @param {boolean} watchMode
* @returns {import('esbuild').BuildOptions}
*/
function esbuildOptions(watchMode) {
return {
entryPoints: [path.join(__dirname, 'src/babelBundleImpl.ts')],
external: ['playwright'],
bundle: true,
outdir: path.join(__dirname, '../../lib/transform'),
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
minify: !watchMode,
};
}
async function main() {
const watchMode = process.argv.includes('--watch');
const ctx = await esbuild.context(esbuildOptions(watchMode));
await ctx.rebuild();
if (watchMode)
await ctx.watch();
else
await ctx.dispose();
}
module.exports = { esbuildOptions };
if (require.main === module)
main();

View File

@ -2,12 +2,6 @@
"name": "babel-bundle",
"version": "0.0.1",
"private": true,
"scripts": {
"esbuild": "node build.js",
"build": "npm run esbuild",
"watch": "npm run esbuild -- --watch",
"generate-license": "node ../../../../utils/generate_third_party_notice.js"
},
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/core": "^7.26.10",

View File

@ -1,51 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
const path = require('path');
const esbuild = require('esbuild');
/**
* @param {boolean} watchMode
* @returns {import('esbuild').BuildOptions}
*/
function esbuildOptions(watchMode) {
return {
entryPoints: [path.join(__dirname, 'src/expectBundleImpl.ts')],
bundle: true,
outdir: path.join(__dirname, '../../lib/common'),
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
minify: !watchMode,
};
}
async function main() {
const watchMode = process.argv.includes('--watch');
const ctx = await esbuild.context(esbuildOptions(watchMode));
await ctx.rebuild();
if (watchMode)
await ctx.watch();
else
await ctx.dispose();
}
module.exports = { esbuildOptions };
if (require.main === module)
main();

View File

@ -2,12 +2,6 @@
"name": "expect-bundle",
"version": "0.0.1",
"private": true,
"scripts": {
"esbuild": "node build.js",
"build": "npm run esbuild",
"watch": "npm run esbuild -- --watch",
"generate-license": "node ../../../../utils/generate_third_party_notice.js"
},
"dependencies": {
"@jest/expect-utils": "29.7.0",
"jest-get-type": "29.6.3",

View File

@ -1,52 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
const path = require('path');
const esbuild = require('esbuild');
/**
* @param {boolean} watchMode
* @returns {import('esbuild').BuildOptions}
*/
function esbuildOptions(watchMode) {
return {
entryPoints: [path.join(__dirname, 'src/utilsBundleImpl.ts')],
external: ['fsevents'],
bundle: true,
outdir: path.join(__dirname, '../../lib'),
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
minify: !watchMode,
};
}
async function main() {
const watchMode = process.argv.includes('--watch');
const ctx = await esbuild.context(esbuildOptions(watchMode));
await ctx.rebuild();
if (watchMode)
await ctx.watch();
else
await ctx.dispose();
}
module.exports = { esbuildOptions };
if (require.main === module)
main();

View File

@ -2,12 +2,6 @@
"name": "utils-bundle",
"version": "0.0.1",
"private": true,
"scripts": {
"esbuild": "node build.js",
"build": "npm run esbuild",
"watch": "npm run esbuild -- --watch",
"generate-license": "node ../../../../utils/generate_third_party_notice.js"
},
"dependencies": {
"chokidar": "3.6.0",
"enquirer": "2.3.6",

View File

@ -228,16 +228,60 @@ function copyFile(file, from, to) {
fs.copyFileSync(file, destination);
}
/**
* @typedef {{
* modulePath: string,
* entryPoints: string[],
* external?: string[],
* outdir?: string,
* outfile?: string,
* minify?: boolean,
* }} BundleOptions
*/
/** @type {BundleOptions[]} */
const bundles = [];
for (const pkg of workspace.packages()) {
const bundlesDir = path.join(pkg.path, 'bundles');
if (!fs.existsSync(bundlesDir))
continue;
for (const bundle of fs.readdirSync(bundlesDir)) {
if (fs.existsSync(path.join(bundlesDir, bundle, 'package.json')))
bundles.push(path.join(bundlesDir, bundle));
}
}
bundles.push({
modulePath: 'packages/playwright/bundles/babel',
outdir: 'packages/playwright/lib/transform',
entryPoints: ['src/babelBundleImpl.ts'],
external: ['playwright'],
});
bundles.push({
modulePath: 'packages/playwright/bundles/expect',
outdir: 'packages/playwright/lib/common',
entryPoints: ['src/expectBundleImpl.ts'],
});
bundles.push({
modulePath: 'packages/playwright/bundles/utils',
outdir: 'packages/playwright/lib',
entryPoints: ['src/utilsBundleImpl.ts'],
external: ['fsevents'],
});
bundles.push({
modulePath: 'packages/playwright-core/bundles/utils',
outfile: 'packages/playwright-core/lib/utilsBundleImpl/index.js',
entryPoints: ['src/utilsBundleImpl.ts'],
});
bundles.push({
modulePath: 'packages/playwright-core/bundles/zip',
outdir: 'packages/playwright-core/lib',
entryPoints: ['src/zipBundleImpl.ts'],
});
// @playwright/client
bundles.push({
modulePath: 'packages/playwright-client',
outdir: 'packages/playwright-client/lib',
entryPoints: ['src/index.ts'],
minify: false,
});
class GroupStep extends Step {
/** @param {Step[]} steps */
@ -269,11 +313,18 @@ updateSteps.push(new ProgramStep({
// Update bundles.
for (const bundle of bundles) {
// Do not update @playwright/client, it has not its own deps.
if (bundle.modulePath === 'packages/playwright-client')
continue;
const packageJson = path.join(filePath(bundle.modulePath), 'package.json');
if (!fs.existsSync(packageJson))
throw new Error(`${packageJson} does not exist`);
updateSteps.push(new ProgramStep({
command: 'npm',
args: ['ci', '--save=false', '--fund=false', '--audit=false', '--omit=optional'],
shell: true,
cwd: bundle,
cwd: filePath(bundle.modulePath),
concurrent: true,
}));
}
@ -375,11 +426,9 @@ class CustomCallbackStep extends Step {
for (const pkg of workspace.packages()) {
if (!fs.existsSync(path.join(pkg.path, 'src')))
continue;
// playwright-client has its own build step.
if (['@playwright/client'].includes(pkg.name)) {
loadBundleEsbuildStep(pkg.path);
// playwright-client is built as a bundle.
if (['@playwright/client'].includes(pkg.name))
continue;
}
steps.push(new EsbuildStep({
entryPoints: [path.join(pkg.path, 'src/**/*.ts')],
@ -390,18 +439,36 @@ for (const pkg of workspace.packages()) {
}));
}
// Build/watch bundles.
for (const bundle of bundles)
loadBundleEsbuildStep(bundle);
function copyXdgOpen() {
const outdir = filePath('packages/playwright-core/lib/utilsBundleImpl');
if (!fs.existsSync(outdir))
fs.mkdirSync(outdir, { recursive: true });
function loadBundleEsbuildStep(bundle) {
const buildFile = path.join(bundle, 'build.js');
if (!fs.existsSync(buildFile))
throw new Error(`Build file ${buildFile} does not exist`);
const { esbuildOptions, beforeEsbuild } = require(buildFile);
if (beforeEsbuild)
steps.push(new CustomCallbackStep(beforeEsbuild));
const options = esbuildOptions(watchMode);
// 'open' package requires 'xdg-open' binary to be present, which does not get bundled by esbuild.
fs.copyFileSync(filePath('packages/playwright-core/bundles/utils/node_modules/open/xdg-open'), path.join(outdir, 'xdg-open'));
console.log('==== Copied xdg-open to', path.join(outdir, 'xdg-open'));
}
// Copy xdg-open after bundles 'npm ci' has finished.
steps.push(new CustomCallbackStep(copyXdgOpen));
// Build/watch bundles.
for (const bundle of bundles) {
/** @type {import('esbuild').BuildOptions} */
const options = {
bundle: true,
format: 'cjs',
platform: 'node',
target: 'ES2019',
sourcemap: watchMode,
minify: !watchMode,
entryPoints: bundle.entryPoints.map(e => path.join(filePath(bundle.modulePath), e)),
...(bundle.outdir ? { outdir: filePath(bundle.outdir) } : {}),
...(bundle.outfile ? { outfile: filePath(bundle.outfile) } : {}),
...(bundle.external ? { external: bundle.external } : {}),
...(bundle.minify !== undefined ? { minify: bundle.minify } : {}),
};
steps.push(new EsbuildStep(options));
}