diff --git a/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.spec.ts b/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.spec.ts index 6332c562c8005..414bac03030dd 100644 --- a/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.spec.ts +++ b/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.spec.ts @@ -159,4 +159,112 @@ describe('buildEsbuildOptions', () => { }, }); }); + + it('should respect user defined outExtension', () => { + expect( + buildEsbuildOptions( + 'esm', + { + platform: 'node', + main: 'apps/myapp/src/index.ts', + outputPath: 'dist/apps/myapp', + tsConfig: 'apps/myapp/tsconfig.app.json', + project: 'apps/myapp/package.json', + outputFileName: 'index.js', + assets: [], + singleEntry: true, + external: [], + esbuildOptions: { + outExtension: { + '.js': '.mjs', + }, + }, + }, + context + ) + ).toEqual({ + bundle: true, + entryNames: '[dir]/[name]', + entryPoints: ['apps/myapp/src/index.ts'], + format: 'esm', + platform: 'node', + outfile: 'dist/apps/myapp/index.mjs', + tsconfig: 'apps/myapp/tsconfig.app.json', + external: [], + outExtension: { + '.js': '.mjs', + }, + }); + + expect( + buildEsbuildOptions( + 'cjs', + { + platform: 'node', + main: 'apps/myapp/src/index.ts', + outputPath: 'dist/apps/myapp', + tsConfig: 'apps/myapp/tsconfig.app.json', + project: 'apps/myapp/package.json', + outputFileName: 'index.js', + assets: [], + singleEntry: true, + external: [], + esbuildOptions: { + outExtension: { + '.js': '.js', + }, + }, + }, + context + ) + ).toEqual({ + bundle: true, + entryNames: '[dir]/[name]', + entryPoints: ['apps/myapp/src/index.ts'], + format: 'cjs', + platform: 'node', + outfile: 'dist/apps/myapp/index.js', + tsconfig: 'apps/myapp/tsconfig.app.json', + external: [], + outExtension: { + '.js': '.js', + }, + }); + + // ESM cannot be mapped to .cjs so ignore + expect( + buildEsbuildOptions( + 'esm', + { + platform: 'node', + main: 'apps/myapp/src/index.ts', + outputPath: 'dist/apps/myapp', + tsConfig: 'apps/myapp/tsconfig.app.json', + project: 'apps/myapp/package.json', + outputFileName: 'index.js', + assets: [], + singleEntry: true, + external: [], + esbuildOptions: { + outExtension: { + '.js': '.cjs', + }, + }, + }, + context + ) + ).toEqual({ + bundle: true, + entryNames: '[dir]/[name]', + entryPoints: ['apps/myapp/src/index.ts'], + format: 'esm', + platform: 'node', + outfile: 'dist/apps/myapp/index.js', + tsconfig: 'apps/myapp/tsconfig.app.json', + external: [], + outExtension: { + '.js': '.js', + }, + }); + }); }); diff --git a/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.ts b/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.ts index 3a9b96623af5c..441f945c97f0c 100644 --- a/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.ts +++ b/packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.ts @@ -31,7 +31,9 @@ export function buildEsbuildOptions( metafile: options.metafile, tsconfig: options.tsConfig, format, - outExtension: { '.js': getOutExtension(format) }, + outExtension: { + '.js': getOutExtension(format, options), + }, }; if (options.platform === 'browser') { @@ -47,8 +49,21 @@ export function buildEsbuildOptions( return esbuildOptions; } -function getOutExtension(format: 'cjs' | 'esm') { - return format === 'esm' ? ESM_FILE_EXTENSION : CJS_FILE_EXTENSION; +function getOutExtension( + format: 'cjs' | 'esm', + options: EsBuildExecutorOptions +): string { + const userDefinedExt = options.esbuildOptions?.outExtension?.['.js']; + // Allow users to change the output extensions from default CJS and ESM extensions. + // CJS -> .js + // ESM -> .mjs + return userDefinedExt === '.js' && format === 'cjs' + ? '.js' + : userDefinedExt === '.mjs' && format === 'esm' + ? '.mjs' + : format === 'esm' + ? ESM_FILE_EXTENSION + : CJS_FILE_EXTENSION; } function getOutfile( @@ -56,11 +71,11 @@ function getOutfile( options: EsBuildExecutorOptions, context: ExecutorContext ) { + const ext = getOutExtension(format, options); const candidate = joinPathFragments( context.target.options.outputPath, options.outputFileName ); - const ext = getOutExtension(format); const { dir, name } = parse(candidate); return `${dir}/${name}${ext}`; }