diff --git a/e2e/esbuild/src/esbuild.test.ts b/e2e/esbuild/src/esbuild.test.ts index 512b3638a3..c96f7ec874 100644 --- a/e2e/esbuild/src/esbuild.test.ts +++ b/e2e/esbuild/src/esbuild.test.ts @@ -178,41 +178,6 @@ describe('EsBuild Plugin', () => { expect(runCommand(`node dist/libs/${myPkg}`)).toMatch(/Hello/); }, 300_000); - it('should support new watch API in >= 0.17.0 and old watch API in < 0.17.0', async () => { - const myPkg = uniq('my-pkg'); - runCLI(`generate @nrwl/js:lib ${myPkg} --bundler=esbuild`); - updateFile(`libs/${myPkg}/src/index.ts`, `console.log('new API');\n`); - - let watchProcess = await runCommandUntil( - `build ${myPkg} --bundle=false --watch`, - (output) => { - return output.includes('build succeeded'); - } - ); - - watchProcess.kill(); - - // Check that the build is correct - expect(runCommand(`node dist/libs/${myPkg}`)).toMatch(/new API/); - - // Now install legacy esbuild and do a build watch - packageInstall('esbuild', undefined, '0.16.17'); - - rmDist(); - - watchProcess = await runCommandUntil( - `build ${myPkg} --bundle=false --watch`, - (output) => { - return output.includes('build succeeded'); - } - ); - - watchProcess.kill(); - - // Check that the build is correct - expect(runCommand(`node dist/libs/${myPkg}`)).toMatch(/new API/); - }, 120_000); - it('should support additional entry points', () => { const myPkg = uniq('my-pkg'); runCLI(`generate @nrwl/js:lib ${myPkg} --bundler=esbuild`); diff --git a/packages/esbuild/migrations.json b/packages/esbuild/migrations.json index 89666f68c8..89ae269295 100644 --- a/packages/esbuild/migrations.json +++ b/packages/esbuild/migrations.json @@ -22,6 +22,15 @@ "alwaysAddToPackageJson": false } } + }, + "16.0.0": { + "version": "16.0.0-beta.5", + "packages": { + "esbuild": { + "version": "0.17.17", + "alwaysAddToPackageJson": false + } + } } } } diff --git a/packages/esbuild/src/executors/esbuild/esbuild.impl.ts b/packages/esbuild/src/executors/esbuild/esbuild.impl.ts index 36b0f4c83b..6b680dc8e9 100644 --- a/packages/esbuild/src/executors/esbuild/esbuild.impl.ts +++ b/packages/esbuild/src/executors/esbuild/esbuild.impl.ts @@ -91,236 +91,103 @@ export async function* esbuildExecutor( packageJsonResult = await copyPackageJson(cpjOptions, context); } - if ('context' in esbuild) { - // 0.17.0+ adds esbuild.context and context.watch() - if (options.watch) { - return yield* createAsyncIterable<{ success: boolean; outfile?: string }>( - async ({ next, done }) => { - let hasTypeErrors = false; - const disposeFns = await Promise.all( - options.format.map(async (format, idx) => { - const esbuildOptions = buildEsbuildOptions( - format, - options, - context - ); - const ctx = await esbuild.context({ - ...esbuildOptions, - plugins: [ - // Only emit info on one of the watch processes. - idx === 0 - ? { - name: 'nx-watch-plugin', - setup(build: esbuild.PluginBuild) { - build.onEnd(async (result: esbuild.BuildResult) => { - if (!options.skipTypeCheck) { - const { errors } = await runTypeCheck( - options, - context - ); - hasTypeErrors = errors.length > 0; - } - const success = - result.errors.length === 0 && !hasTypeErrors; - - if (!success) { - logger.info(BUILD_WATCH_FAILED); - } else { - logger.info(BUILD_WATCH_SUCCEEDED); - } - - next({ - success, - // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. - outfile: join( - context.root, - getOutfile(format, options, context) - ), - }); - }); - }, - } - : null, - ].filter(Boolean), - }); - - await ctx.watch(); - return () => ctx.dispose(); - }) - ); - - registerCleanupCallback(() => { - assetsResult?.stop(); - packageJsonResult?.stop(); - disposeFns.forEach((fn) => fn()); - done(); // return from async iterable - }); - } - ); - } else { - // Run type-checks first and bail if they don't pass. - if (!options.skipTypeCheck) { - const { errors } = await runTypeCheck(options, context); - if (errors.length > 0) { - yield { success: false }; - return; - } - } - - // Emit a build event for each file format. - for (let i = 0; i < options.format.length; i++) { - const format = options.format[i]; - const esbuildOptions = buildEsbuildOptions(format, options, context); - const buildResult = await esbuild.build(esbuildOptions); - - if (options.metafile) { - const filename = - options.format.length === 1 - ? 'meta.json' - : `meta.${options.format[i]}.json`; - writeJsonSync( - joinPathFragments(options.outputPath, filename), - buildResult.metafile - ); - } - - yield { - success: buildResult.errors.length === 0, - // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. - // This field is needed for `@nx/js:node` executor to work. - outfile: join(context.root, getOutfile(format, options, context)), - }; - } - } - } else { - // TODO(jack): Remove in Nx 16 - // < 0.17.0 takes watch as an argument to build() - if (options.watch) { - return yield* createAsyncIterable<{ success: boolean; outfile?: string }>( - async ({ next, done }) => { - let hasTypeErrors = false; - const results = await Promise.all( - options.format.map(async (format, idx) => { - const esbuildOptions = buildEsbuildOptions( - format, - options, - context - ); - const watch = + if (options.watch) { + return yield* createAsyncIterable<{ success: boolean; outfile?: string }>( + async ({ next, done }) => { + let hasTypeErrors = false; + const disposeFns = await Promise.all( + options.format.map(async (format, idx) => { + const esbuildOptions = buildEsbuildOptions( + format, + options, + context + ); + const ctx = await esbuild.context({ + ...esbuildOptions, + plugins: [ // Only emit info on one of the watch processes. idx === 0 ? { - onRebuild: async ( - error: esbuild.BuildFailure, - result: esbuild.BuildResult - ) => { - if (!options.skipTypeCheck) { - const { errors } = await runTypeCheck( - options, - context - ); - hasTypeErrors = errors.length > 0; - } - const success = !error && !hasTypeErrors; + name: 'nx-watch-plugin', + setup(build: esbuild.PluginBuild) { + build.onEnd(async (result: esbuild.BuildResult) => { + if (!options.skipTypeCheck) { + const { errors } = await runTypeCheck( + options, + context + ); + hasTypeErrors = errors.length > 0; + } + const success = + result.errors.length === 0 && !hasTypeErrors; - if (!success) { - logger.info(BUILD_WATCH_FAILED); - } else { - logger.info(BUILD_WATCH_SUCCEEDED); - } + if (!success) { + logger.info(BUILD_WATCH_FAILED); + } else { + logger.info(BUILD_WATCH_SUCCEEDED); + } - next({ - success, - // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. - // This field is needed for `@nx/js:node` executor to work. - outfile: join( - context.root, - getOutfile(format, options, context) - ), + next({ + success, + // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. + outfile: join( + context.root, + getOutfile(format, options, context) + ), + }); }); }, } - : true; - try { - const result = await esbuild.build({ - ...esbuildOptions, - watch, - }); + : null, + ].filter(Boolean), + }); - next({ - success: true, - // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. - outfile: join( - context.root, - getOutfile(format, options, context) - ), - }); + await ctx.watch(); + return () => ctx.dispose(); + }) + ); - return result; - } catch { - next({ success: false }); - } - }) - ); + registerCleanupCallback(() => { + assetsResult?.stop(); + packageJsonResult?.stop(); + disposeFns.forEach((fn) => fn()); + done(); // return from async iterable + }); + } + ); + } else { + // Run type-checks first and bail if they don't pass. + if (!options.skipTypeCheck) { + const { errors } = await runTypeCheck(options, context); + if (errors.length > 0) { + yield { success: false }; + return; + } + } - registerCleanupCallback(() => { - assetsResult?.stop(); - packageJsonResult?.stop(); - results.forEach((r) => - // result.stop() is no in esbuild 0.17.0+ but it exists in earlier versions - r?.['stop']?.() - ); - done(); - }); + // Emit a build event for each file format. + for (let i = 0; i < options.format.length; i++) { + const format = options.format[i]; + const esbuildOptions = buildEsbuildOptions(format, options, context); + const buildResult = await esbuild.build(esbuildOptions); - if (!options.skipTypeCheck) { - const { errors } = await runTypeCheck(options, context); - hasTypeErrors = errors.length > 0; - } - - const success = - results.every((r) => r.errors?.length === 0) && !hasTypeErrors; - - if (!success) { - logger.info(BUILD_WATCH_FAILED); - } else { - logger.info(BUILD_WATCH_SUCCEEDED); - } - } - ); - } else { - // Run type-checks first and bail if they don't pass. - if (!options.skipTypeCheck) { - const { errors } = await runTypeCheck(options, context); - if (errors.length > 0) { - yield { success: false }; - return; - } + if (options.metafile) { + const filename = + options.format.length === 1 + ? 'meta.json' + : `meta.${options.format[i]}.json`; + writeJsonSync( + joinPathFragments(options.outputPath, filename), + buildResult.metafile + ); } - // Emit a build event for each file format. - for (let i = 0; i < options.format.length; i++) { - const format = options.format[i]; - const esbuildOptions = buildEsbuildOptions(format, options, context); - const buildResult = await (esbuild as EsBuild).build(esbuildOptions); - - if (options.metafile) { - const filename = - options.format.length === 1 - ? 'meta.json' - : `meta.${options.format[i]}.json`; - writeJsonSync( - joinPathFragments(options.outputPath, filename), - buildResult.metafile - ); - } - - yield { - success: buildResult.errors.length === 0, - // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. - outfile: join(context.root, getOutfile(format, options, context)), - }; - } + yield { + success: buildResult.errors.length === 0, + // Need to call getOutfile directly in the case of bundle=false and outfile is not set for esbuild. + // This field is needed for `@nx/js:node` executor to work. + outfile: join(context.root, getOutfile(format, options, context)), + }; } } } diff --git a/packages/js/src/utils/versions.ts b/packages/js/src/utils/versions.ts index c75920e684..d0b33474c5 100644 --- a/packages/js/src/utils/versions.ts +++ b/packages/js/src/utils/versions.ts @@ -1,6 +1,6 @@ export const nxVersion = require('../../package.json').version; -export const esbuildVersion = '^0.17.5'; +export const esbuildVersion = '^0.17.17'; export const prettierVersion = '^2.6.2'; export const swcCliVersion = '~0.1.62'; export const swcCoreVersion = '~1.3.51'; diff --git a/packages/node/src/generators/application/application.ts b/packages/node/src/generators/application/application.ts index 7fa379bb16..698e4f2547 100644 --- a/packages/node/src/generators/application/application.ts +++ b/packages/node/src/generators/application/application.ts @@ -30,7 +30,6 @@ import { join } from 'path'; import { initGenerator } from '../init/init'; import { - esbuildVersion, expressTypingsVersion, expressVersion, fastifyAutoloadVersion, @@ -46,6 +45,7 @@ import { setupDockerGenerator } from '../setup-docker/setup-docker'; import { Schema } from './schema'; import { mapLintPattern } from '@nx/linter/src/generators/lint-project/lint-project'; +import { esbuildVersion } from '@nx/js/src/utils/versions'; export interface NormalizedSchema extends Schema { appProjectRoot: string; diff --git a/packages/node/src/utils/versions.ts b/packages/node/src/utils/versions.ts index dfa91fab51..b2082d2d96 100644 --- a/packages/node/src/utils/versions.ts +++ b/packages/node/src/utils/versions.ts @@ -4,8 +4,6 @@ export const tslibVersion = '^2.3.0'; export const typesNodeVersion = '~18.7.1'; -export const esbuildVersion = '^0.17.5'; - export const expressVersion = '~4.18.1'; export const expressTypingsVersion = '~4.17.13';