devops: save battery by using chokidar instead of esbuild watch (#35867)

This commit is contained in:
Yury Semikhatsky 2025-05-07 14:33:50 -07:00 committed by GitHub
parent 83c5ee74da
commit bd76f7b1a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -21,6 +21,7 @@ const path = require('path');
const chokidar = require('chokidar'); const chokidar = require('chokidar');
const fs = require('fs'); const fs = require('fs');
const { workspace } = require('../workspace'); const { workspace } = require('../workspace');
const { build, context } = require('esbuild');
/** /**
* @typedef {{ * @typedef {{
@ -95,11 +96,13 @@ class Step {
this.concurrent = options.concurrent; this.concurrent = options.concurrent;
} }
/** @returns {Promise<void>|void} */
runSync() { runSync() {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
async runAsync() { /** @returns {Promise<void>|void} */
runConcurrently() {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
} }
@ -120,6 +123,7 @@ class ProgramStep extends Step {
this._options = options; this._options = options;
} }
/** @override */
runSync() { runSync() {
const step = this._options; const step = this._options;
console.log(`==== Running ${step.command} ${step.args.join(' ')} in ${step.cwd || process.cwd()}`); console.log(`==== Running ${step.command} ${step.args.join(' ')} in ${step.cwd || process.cwd()}`);
@ -136,7 +140,8 @@ class ProgramStep extends Step {
process.exit(out.status); process.exit(out.status);
} }
async runAsync() { /** @override */
runConcurrently() {
const step = this._options; const step = this._options;
const child = child_process.spawn(step.command, step.args, { const child = child_process.spawn(step.command, step.args, {
stdio: 'inherit', stdio: 'inherit',
@ -194,12 +199,12 @@ async function runWatch() {
for (const step of steps) { for (const step of steps) {
if (!step.concurrent) if (!step.concurrent)
step.runSync(); await step.runSync();
} }
for (const step of steps) { for (const step of steps) {
if (step.concurrent) if (step.concurrent)
step.runAsync(); await step.runConcurrently();
} }
for (const onChange of onChanges) for (const onChange of onChanges)
runOnChange(onChange); runOnChange(onChange);
@ -217,7 +222,7 @@ async function runBuild() {
watcher.close(); watcher.close();
} }
for (const step of steps) for (const step of steps)
step.runSync(); await step.runSync();
for (const onChange of onChanges) for (const onChange of onChanges)
runOnChangeSyncStep(onChange); runOnChangeSyncStep(onChange);
} }
@ -283,6 +288,61 @@ steps.push(new ProgramStep({
shell: true, shell: true,
})); }));
class EsbuildStep extends Step {
concurrent = true;
/** @type {import('esbuild').BuildOptions} */
constructor(options) {
super(options);
this._options = options;
}
/** @override */
async runSync() {
if (watchMode) {
await this._ensureWatching();
} else {
console.log('=== Running esbuild', this._options.entryPoints);
const start = Date.now();
await build(this._options);
console.log('=== Done in', Date.now() - start, 'ms');
}
}
/** @override */
async runConcurrently() {
// Running esbuild steps in parallel showed longer overall time.
await this.runSync();
}
async _ensureWatching() {
const start = Date.now();
if (this._context)
return;
this._context = await context(this._options);
const watcher = chokidar.watch(this._options.entryPoints);
await new Promise(x => watcher.once('ready', x));
watcher.on('all', () => this._rebuild());
await this._rebuild();
console.log('=== Esbuild watching', this._options.entryPoints, `(stared in ${Date.now() - start}ms)`);
}
async _rebuild() {
if (this._rebuilding) {
this._sourcesChanged = true;
return;
}
do {
this._sourcesChanged = false;
this._rebuilding = true;
await this._context?.rebuild();
this._rebuilding = false;
} while (this._sourcesChanged);
}
}
// Run esbuild. // Run esbuild.
for (const pkg of workspace.packages()) { for (const pkg of workspace.packages()) {
if (!fs.existsSync(path.join(pkg.path, 'src'))) if (!fs.existsSync(path.join(pkg.path, 'src')))
@ -290,19 +350,13 @@ for (const pkg of workspace.packages()) {
// These packages have their own build step. // These packages have their own build step.
if (['@playwright/client'].includes(pkg.name)) if (['@playwright/client'].includes(pkg.name))
continue; continue;
steps.push(new ProgramStep({
command: 'npx', steps.push(new EsbuildStep({
args: [ entryPoints: [path.join(pkg.path, 'src/**/*.ts')],
'esbuild', outdir: `${path.join(pkg.path, 'lib')}`,
quotePath(path.join(pkg.path, 'src/**/*.ts')), sourcemap: withSourceMaps ? 'linked' : false,
`--outdir=${quotePath(path.join(pkg.path, 'lib'))}`, platform: 'node',
...(withSourceMaps ? [`--sourcemap=linked`] : []), format: 'cjs',
...(watchMode ? ['--watch'] : []),
'--platform=node',
'--format=cjs',
],
shell: true,
concurrent: true,
})); }));
} }