Skip to content

Commit

Permalink
feat(bundling): add for esbuild to enable/disable package.json genera…
Browse files Browse the repository at this point in the history
…tion (#15777)
  • Loading branch information
jaysoo committed Mar 21, 2023
1 parent f10ecc1 commit 7ebca51
Show file tree
Hide file tree
Showing 15 changed files with 305 additions and 69 deletions.
5 changes: 5 additions & 0 deletions docs/generated/packages/esbuild/executors/esbuild.json
Expand Up @@ -147,6 +147,11 @@
"default": false,
"x-priority": "internal"
},
"generatePackageJson": {
"type": "boolean",
"description": "Generates a `package.json` and pruned lock file with the project's `node_module` dependencies populated for installing in a container. If a `package.json` exists in the project's directory, it will be reused with dependencies populated.",
"default": false
},
"thirdParty": {
"type": "boolean",
"description": "Includes third-party packages in the bundle (i.e. npm packages).",
Expand Down
14 changes: 14 additions & 0 deletions e2e/esbuild/src/esbuild.test.ts
Expand Up @@ -34,13 +34,27 @@ describe('EsBuild Plugin', () => {
updateFile(`libs/${myPkg}/assets/a.md`, 'file a');
updateFile(`libs/${myPkg}/assets/b.md`, 'file b');

// Copy package.json as asset rather than generate with Nx-detected fields.
runCLI(`build ${myPkg} --generatePackageJson=false`);
const packageJson = readJson(`libs/${myPkg}/package.json`);
// This is the file that is generated by lib generator (no deps, no main, etc.).
expect(packageJson).toEqual({
name: `@proj/${myPkg}`,
version: '0.0.1',
type: 'commonjs',
});

// Build normally with package.json generation.
runCLI(`build ${myPkg}`);

expect(runCommand(`node dist/libs/${myPkg}/index.js`)).toMatch(/Hello/);
// main field should be set correctly in package.json
checkFilesExist(`dist/libs/${myPkg}/package.json`);
expect(runCommand(`node dist/libs/${myPkg}`)).toMatch(/Hello/);

expect(runCommand(`node dist/libs/${myPkg}/index.js`)).toMatch(/Hello/);
// main field should be set correctly in package.json

expect(readFile(`dist/libs/${myPkg}/assets/a.md`)).toMatch(/file a/);
expect(readFile(`dist/libs/${myPkg}/assets/b.md`)).toMatch(/file b/);

Expand Down
9 changes: 8 additions & 1 deletion packages/esbuild/migrations.json
@@ -1,5 +1,12 @@
{
"generators": {},
"generators": {
"set-generate-package-json": {
"cli": "nx",
"version": "15.8.7-beta.0",
"description": "Set generatePackageJson to true to maintain existing behavior of generating package.json in output path.",
"factory": "./src/migrations/update-15-8-7/set-generate-package-json"
}
},
"packageJsonUpdates": {
"15.7.0": {
"version": "15.7.0-beta.0",
Expand Down
35 changes: 19 additions & 16 deletions packages/esbuild/src/executors/esbuild/esbuild.impl.ts
Expand Up @@ -41,7 +41,7 @@ export async function* esbuildExecutor(
_options: EsBuildExecutorOptions,
context: ExecutorContext
) {
const options = normalizeOptions(_options);
const options = normalizeOptions(_options, context);
if (options.deleteOutputPath) removeSync(options.outputPath);

const assetsResult = await copyAssets(options, context);
Expand Down Expand Up @@ -70,24 +70,27 @@ export async function* esbuildExecutor(
}
}

const cpjOptions: CopyPackageJsonOptions = {
...options,
// TODO(jack): make types generate with esbuild
skipTypings: true,
outputFileExtensionForCjs: getOutExtension('cjs', options),
excludeLibsInPackageJson: !options.thirdParty,
updateBuildableProjectDepsInPackageJson: externalDependencies.length > 0,
};
let packageJsonResult;
if (options.generatePackageJson) {
const cpjOptions: CopyPackageJsonOptions = {
...options,
// TODO(jack): make types generate with esbuild
skipTypings: true,
outputFileExtensionForCjs: getOutExtension('cjs', options),
excludeLibsInPackageJson: !options.thirdParty,
updateBuildableProjectDepsInPackageJson: externalDependencies.length > 0,
};

// If we're bundling third-party packages, then any extra deps from external should be the only deps in package.json
if (options.thirdParty && externalDependencies.length > 0) {
cpjOptions.overrideDependencies = externalDependencies;
} else {
cpjOptions.extraDependencies = externalDependencies;
}

// If we're bundling third-party packages, then any extra deps from external should be the only deps in package.json
if (options.thirdParty && externalDependencies.length > 0) {
cpjOptions.overrideDependencies = externalDependencies;
} else {
cpjOptions.extraDependencies = externalDependencies;
packageJsonResult = await copyPackageJson(cpjOptions, context);
}

const packageJsonResult = await copyPackageJson(cpjOptions, context);

if ('context' in esbuild) {
// 0.17.0+ adds esbuild.context and context.watch()
if (options.watch) {
Expand Down
Expand Up @@ -45,7 +45,6 @@ describe('buildEsbuildOptions', () => {
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
outputFileName: 'index.js',
singleEntry: true,
Expand Down Expand Up @@ -82,7 +81,6 @@ describe('buildEsbuildOptions', () => {
additionalEntryPoints: ['apps/myapp/src/extra-entry.ts'],
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
outputFileName: 'index.js',
singleEntry: false,
Expand Down Expand Up @@ -118,7 +116,6 @@ describe('buildEsbuildOptions', () => {
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
outputFileName: 'index.js',
singleEntry: true,
Expand Down Expand Up @@ -154,7 +151,6 @@ describe('buildEsbuildOptions', () => {
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
outputFileName: 'index.js',
singleEntry: true,
Expand Down Expand Up @@ -187,7 +183,6 @@ describe('buildEsbuildOptions', () => {
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,
Expand Down Expand Up @@ -223,7 +218,6 @@ describe('buildEsbuildOptions', () => {
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,
Expand Down Expand Up @@ -260,7 +254,6 @@ describe('buildEsbuildOptions', () => {
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,
Expand Down Expand Up @@ -298,10 +291,9 @@ describe('buildEsbuildOptions', () => {
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,
outputFileName: 'index.js',
external: ['foo'],
esbuildOptions: {
external: ['bar'],
Expand Down Expand Up @@ -334,8 +326,6 @@ describe('buildEsbuildOptions', () => {
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: ['foo'],
Expand Down Expand Up @@ -367,7 +357,40 @@ describe('buildEsbuildOptions', () => {
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,
sourcemap: true,
external: [],
},
context
)
).toEqual({
bundle: false,
entryNames: '[dir]/[name]',
entryPoints: ['apps/myapp/src/index.ts'],
format: 'esm',
platform: 'node',
outdir: 'dist/apps/myapp',
tsconfig: 'apps/myapp/tsconfig.app.json',
external: undefined,
sourcemap: true,
outExtension: {
'.js': '.js',
},
});
});

it('should set sourcemap', () => {
expect(
buildEsbuildOptions(
'esm',
{
bundle: false,
platform: 'node',
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
outputFileName: 'index.js',
assets: [],
singleEntry: true,
Expand Down
127 changes: 92 additions & 35 deletions packages/esbuild/src/executors/esbuild/lib/normalize.spec.ts
@@ -1,21 +1,45 @@
import { normalizeOptions } from './normalize';
import { ExecutorContext } from '@nrwl/devkit';

describe('normalizeOptions', () => {
const context: ExecutorContext = {
root: '/',
cwd: '/',
isVerbose: false,
projectName: 'myapp',
projectGraph: {
nodes: {
myapp: {
type: 'app',
name: 'myapp',
data: {
root: 'apps/myapp',
files: [],
},
},
},
dependencies: {},
},
};

it('should handle single entry point options', () => {
expect(
normalizeOptions({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
})
normalizeOptions(
{
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
generatePackageJson: true,
assets: [],
},
context
)
).toEqual({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
generatePackageJson: true,
outputFileName: 'index.js',
singleEntry: true,
external: [],
Expand All @@ -24,20 +48,23 @@ describe('normalizeOptions', () => {

it('should handle multiple entry point options', () => {
expect(
normalizeOptions({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
additionalEntryPoints: ['apps/myapp/src/extra-entry.ts'],
})
normalizeOptions(
{
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
assets: [],
generatePackageJson: true,
additionalEntryPoints: ['apps/myapp/src/extra-entry.ts'],
},
context
)
).toEqual({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
generatePackageJson: true,
outputFileName: 'index.js',
additionalEntryPoints: ['apps/myapp/src/extra-entry.ts'],
singleEntry: false,
Expand All @@ -47,20 +74,23 @@ describe('normalizeOptions', () => {

it('should support custom output file name', () => {
expect(
normalizeOptions({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
outputFileName: 'test.js',
})
normalizeOptions(
{
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
assets: [],
generatePackageJson: true,
outputFileName: 'test.js',
},
context
)
).toEqual({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
generatePackageJson: true,
outputFileName: 'test.js',
singleEntry: true,
external: [],
Expand All @@ -69,15 +99,42 @@ describe('normalizeOptions', () => {

it('should validate against multiple entry points + outputFileName', () => {
expect(() =>
normalizeOptions({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
project: 'apps/myapp/package.json',
assets: [],
additionalEntryPoints: ['apps/myapp/src/extra-entry.ts'],
outputFileName: 'test.js',
})
normalizeOptions(
{
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
assets: [],
generatePackageJson: true,
additionalEntryPoints: ['apps/myapp/src/extra-entry.ts'],
outputFileName: 'test.js',
},
context
)
).toThrow(/Cannot use/);
});

it('should add package.json to assets array if generatePackageJson is false', () => {
expect(
normalizeOptions(
{
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
generatePackageJson: false,
assets: [],
},
context
)
).toEqual({
main: 'apps/myapp/src/index.ts',
outputPath: 'dist/apps/myapp',
tsConfig: 'apps/myapp/tsconfig.app.json',
assets: ['apps/myapp/package.json'],
generatePackageJson: false,
outputFileName: 'index.js',
singleEntry: true,
external: [],
});
});
});

1 comment on commit 7ebca51

@vercel
Copy link

@vercel vercel bot commented on 7ebca51 Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app

Please sign in to comment.