diff --git a/packages/playwright-client/build.js b/packages/playwright-client/build.js new file mode 100644 index 0000000000..0b7213708d --- /dev/null +++ b/packages/playwright-client/build.js @@ -0,0 +1,51 @@ +/** + * 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(); diff --git a/packages/playwright-client/package.json b/packages/playwright-client/package.json index 16dbee8b58..f2a834e2fa 100644 --- a/packages/playwright-client/package.json +++ b/packages/playwright-client/package.json @@ -25,8 +25,9 @@ "./package.json": "./package.json" }, "scripts": { - "build": "esbuild ./src/index.ts --outdir=lib --format=cjs --bundle --platform=node --target=ES2019", - "watch": "esbuild ./src/index.ts --outdir=lib --format=cjs --bundle --platform=node --target=ES2019 --watch" + "esbuild": "node build.js", + "build": "npm run esbuild", + "watch": "npm run esbuild -- --watch" }, "dependencies": { "playwright-core": "1.53.0-next" diff --git a/packages/playwright-core/bundles/utils/build.js b/packages/playwright-core/bundles/utils/build.js index c14196668a..fbd276deb5 100644 --- a/packages/playwright-core/bundles/utils/build.js +++ b/packages/playwright-core/bundles/utils/build.js @@ -21,31 +21,47 @@ const fs = require('fs'); const outdir = path.join(__dirname, '../../lib/utilsBundleImpl'); -if (!fs.existsSync(outdir)) - fs.mkdirSync(outdir); +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')); } -(async () => { - const ctx = await esbuild.context({ +/** + * @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: process.argv.includes('--sourcemap'), - minify: process.argv.includes('--minify'), - }); + 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 (process.argv.includes('--watch')) + if (watchMode) await ctx.watch(); else await ctx.dispose(); -})().catch(error => { - console.error(error); - process.exit(1); -}); +} + +module.exports = { + beforeEsbuild: copyXdgOpen, + esbuildOptions, +}; + +if (require.main === module) + main(); diff --git a/packages/playwright-core/bundles/utils/package.json b/packages/playwright-core/bundles/utils/package.json index e7f09cf3a0..4944b7b078 100644 --- a/packages/playwright-core/bundles/utils/package.json +++ b/packages/playwright-core/bundles/utils/package.json @@ -4,8 +4,8 @@ "private": true, "scripts": { "esbuild": "node build.js", - "build": "npm run esbuild -- --minify", - "watch": "npm run esbuild -- --watch --sourcemap", + "build": "npm run esbuild", + "watch": "npm run esbuild -- --watch", "generate-license": "node ../../../../utils/generate_third_party_notice.js" }, "dependencies": { diff --git a/packages/playwright-core/bundles/zip/build.js b/packages/playwright-core/bundles/zip/build.js index 6efadad71c..5eb79c66d8 100644 --- a/packages/playwright-core/bundles/zip/build.js +++ b/packages/playwright-core/bundles/zip/build.js @@ -18,23 +18,34 @@ const path = require('path'); const esbuild = require('esbuild'); -(async () => { - const ctx = await esbuild.context({ +/** + * @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: process.argv.includes('--sourcemap'), - minify: process.argv.includes('--minify'), - }); + sourcemap: watchMode, + minify: !watchMode, + }; +} + +async function main() { + const watchMode = process.argv.includes('--watch'); + const ctx = await esbuild.context(esbuildOptions(watchMode)); await ctx.rebuild(); - if (process.argv.includes('--watch')) + if (watchMode) await ctx.watch(); else await ctx.dispose(); -})().catch(error => { - console.error(error); - process.exit(1); -}); +} + +module.exports = { esbuildOptions }; + +if (require.main === module) + main(); diff --git a/packages/playwright-core/bundles/zip/package.json b/packages/playwright-core/bundles/zip/package.json index 64f75f7195..3e0124035b 100644 --- a/packages/playwright-core/bundles/zip/package.json +++ b/packages/playwright-core/bundles/zip/package.json @@ -4,8 +4,8 @@ "private": true, "scripts": { "esbuild": "node build.js", - "build": "npm run esbuild -- --minify", - "watch": "npm run esbuild -- --watch --sourcemap", + "build": "npm run esbuild", + "watch": "npm run esbuild -- --watch", "generate-license": "node ../../../../utils/generate_third_party_notice.js" }, "dependencies": { diff --git a/packages/playwright/bundles/babel/build.js b/packages/playwright/bundles/babel/build.js new file mode 100644 index 0000000000..c5cffa4baa --- /dev/null +++ b/packages/playwright/bundles/babel/build.js @@ -0,0 +1,52 @@ +/** + * 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(); diff --git a/packages/playwright/bundles/babel/package.json b/packages/playwright/bundles/babel/package.json index fca7b43012..969026a81a 100644 --- a/packages/playwright/bundles/babel/package.json +++ b/packages/playwright/bundles/babel/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "private": true, "scripts": { - "esbuild": "esbuild ./src/babelBundleImpl.ts --bundle --outdir=../../lib/transform --format=cjs --platform=node --target=ES2019 --external:playwright", - "build": "npm run esbuild -- --minify", - "watch": "npm run esbuild -- --watch --sourcemap", + "esbuild": "node build.js", + "build": "npm run esbuild", + "watch": "npm run esbuild -- --watch", "generate-license": "node ../../../../utils/generate_third_party_notice.js" }, "dependencies": { diff --git a/packages/playwright/bundles/expect/build.js b/packages/playwright/bundles/expect/build.js new file mode 100644 index 0000000000..18a37f60c8 --- /dev/null +++ b/packages/playwright/bundles/expect/build.js @@ -0,0 +1,51 @@ +/** + * 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(); diff --git a/packages/playwright/bundles/expect/package.json b/packages/playwright/bundles/expect/package.json index d9f436755f..3ce2d05ecc 100644 --- a/packages/playwright/bundles/expect/package.json +++ b/packages/playwright/bundles/expect/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "private": true, "scripts": { - "esbuild": "esbuild ./src/expectBundleImpl.ts --bundle --outdir=../../lib/common --format=cjs --platform=node --target=ES2019", - "build": "npm run esbuild -- --minify", - "watch": "npm run esbuild -- --watch --sourcemap", + "esbuild": "node build.js", + "build": "npm run esbuild", + "watch": "npm run esbuild -- --watch", "generate-license": "node ../../../../utils/generate_third_party_notice.js" }, "dependencies": { diff --git a/packages/playwright/bundles/utils/build.js b/packages/playwright/bundles/utils/build.js index 1feb97ea26..8bd29d74f7 100644 --- a/packages/playwright/bundles/utils/build.js +++ b/packages/playwright/bundles/utils/build.js @@ -18,8 +18,12 @@ const path = require('path'); const esbuild = require('esbuild'); -(async () => { - const ctx = await esbuild.context({ +/** + * @param {boolean} watchMode + * @returns {import('esbuild').BuildOptions} + */ +function esbuildOptions(watchMode) { + return { entryPoints: [path.join(__dirname, 'src/utilsBundleImpl.ts')], external: ['fsevents'], bundle: true, @@ -27,15 +31,22 @@ const esbuild = require('esbuild'); format: 'cjs', platform: 'node', target: 'ES2019', - sourcemap: process.argv.includes('--sourcemap'), - minify: process.argv.includes('--minify'), - }); + sourcemap: watchMode, + minify: !watchMode, + }; +} + +async function main() { + const watchMode = process.argv.includes('--watch'); + const ctx = await esbuild.context(esbuildOptions(watchMode)); await ctx.rebuild(); - if (process.argv.includes('--watch')) + if (watchMode) await ctx.watch(); else await ctx.dispose(); -})().catch(error => { - console.error(error); - process.exit(1); -}); +} + +module.exports = { esbuildOptions }; + +if (require.main === module) + main(); diff --git a/packages/playwright/bundles/utils/package.json b/packages/playwright/bundles/utils/package.json index 3fb09c1d17..63ee4858bb 100644 --- a/packages/playwright/bundles/utils/package.json +++ b/packages/playwright/bundles/utils/package.json @@ -4,8 +4,8 @@ "private": true, "scripts": { "esbuild": "node build.js", - "build": "npm run esbuild -- --minify", - "watch": "npm run esbuild -- --watch --sourcemap", + "build": "npm run esbuild", + "watch": "npm run esbuild -- --watch", "generate-license": "node ../../../../utils/generate_third_party_notice.js" }, "dependencies": { diff --git a/utils/build/build.js b/utils/build/build.js index fc21ba10b1..28ab8975dd 100644 --- a/utils/build/build.js +++ b/utils/build/build.js @@ -67,8 +67,7 @@ const onChanges = []; const copyFiles = []; const watchMode = process.argv.slice(2).includes('--watch'); -const lintMode = process.argv.slice(2).includes('--lint'); -const withSourceMaps = process.argv.slice(2).includes('--sourcemap') || watchMode; +const withSourceMaps = watchMode; const installMode = process.argv.slice(2).includes('--install'); const ROOT = path.join(__dirname, '..', '..'); @@ -292,7 +291,7 @@ class EsbuildStep extends Step { if (watchMode) { await this._ensureWatching(); } else { - console.log('==== Running esbuild', this._options.entryPoints.map(e => path.relative(ROOT, e)).join(', ')); + console.log('==== Running esbuild:', this._relativeEntryPoints().join(', ')); const start = Date.now(); await build(this._options); console.log('==== Done in', Date.now() - start, 'ms'); @@ -311,7 +310,7 @@ class EsbuildStep extends Step { watcher.on('all', () => this._rebuild()); await this._rebuild(); - console.log('==== Esbuild watching', this._options.entryPoints, `(started in ${Date.now() - start}ms)`); + console.log('==== Esbuild watching:', this._relativeEntryPoints().join(', '), `(started in ${Date.now() - start}ms)`); } async _rebuild() { @@ -332,15 +331,32 @@ class EsbuildStep extends Step { this._rebuilding = false; } while (this._sourcesChanged); } + + _relativeEntryPoints() { + return this._options.entryPoints.map(e => path.relative(ROOT, e)); + } +} + +class CustomCallbackStep extends Step { + constructor(callback) { + super({ concurrent: false }); + this._callback = callback; + } + + async run() { + await this._callback(); + } } // Run esbuild. for (const pkg of workspace.packages()) { if (!fs.existsSync(path.join(pkg.path, 'src'))) continue; - // These packages have their own build step. - if (['@playwright/client'].includes(pkg.name)) + // playwright-client has its own build step. + if (['@playwright/client'].includes(pkg.name)) { + loadBundleEsbuildStep(pkg.path); continue; + } steps.push(new EsbuildStep({ entryPoints: [path.join(pkg.path, 'src/**/*.ts')], @@ -352,32 +368,19 @@ for (const pkg of workspace.packages()) { } // Build/watch bundles. -for (const bundle of bundles) { - steps.push(new ProgramStep({ - command: 'npm', - args: [ - 'run', - watchMode ? 'watch' : 'build', - ...(withSourceMaps ? ['--', '--sourcemap'] : []) - ], - shell: true, - cwd: bundle, - concurrent: true, - })); -} +for (const bundle of bundles) + loadBundleEsbuildStep(bundle); -// Build/watch playwright-client. -steps.push(new ProgramStep({ - command: 'npm', - args: [ - 'run', - watchMode ? 'watch' : 'build', - ...(withSourceMaps ? ['--', '--sourcemap'] : []) - ], - shell: true, - cwd: path.join(__dirname, '..', '..', 'packages', 'playwright-client'), - concurrent: 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); + steps.push(new EsbuildStep(options)); +} // Build/watch trace viewer service worker. steps.push(new ProgramStep({ @@ -528,7 +531,7 @@ copyFiles.push({ to: 'packages/playwright-core/lib', }); -if (lintMode) { +if (watchMode) { // Run TypeScript for type checking. steps.push(new ProgramStep({ command: 'npx',