From 95f5a085fab57d2a98a18ff65c4ad16f913c3154 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Wed, 23 Feb 2022 16:59:03 -0500 Subject: [PATCH] feat(node): consolidate js and node plugins (#9086) * chore(node): update docs after consolidating js and node plugins * feat(node): consolidate js and node plugins --- .../api-js/generators/application.md | 166 --------- docs/generated/api-node/executors/execute.md | 68 ---- .../{api-js => api-node}/executors/node.md | 8 +- docs/generated/api-node/executors/package.md | 102 ------ .../executors/{build.md => webpack.md} | 8 +- docs/map.json | 27 +- e2e/js/src/js.test.ts | 165 ++++----- e2e/node/src/node.test.ts | 285 +-------------- packages/js/executors.json | 10 - packages/js/generators.json | 14 - packages/js/migrations.json | 9 +- .../application/application.spec.ts | 89 ----- .../src/generators/application/application.ts | 21 -- .../generators/application/files/README.md | 19 - .../application/files/package.json__tmpl__ | 5 - .../src/app/__fileName__.spec.ts__tmpl__ | 7 - .../files/src/app/__fileName__.ts__tmpl__ | 3 - .../application/files/src/index.ts__tmpl__ | 3 - .../files/tsconfig.app.json__tmpl__ | 10 - .../application/files/tsconfig.json__tmpl__ | 14 - .../js/src/generators/application/schema.json | 99 ----- packages/js/src/generators/library/library.ts | 313 +++++++++++++++- packages/js/src/index.ts | 1 - .../update-node-executor.spec.ts | 66 ++++ .../update-13-9-0/update-node-executor.ts | 36 ++ packages/js/src/utils/project-generator.ts | 319 ---------------- packages/js/src/utils/schema.d.ts | 5 - .../generators/lint-project/lint-project.ts | 8 +- .../src/generators/library/lib/add-project.ts | 2 +- packages/node/executors.json | 38 +- packages/node/migrations.json | 18 + packages/node/package.json | 1 + packages/node/src/executors/build/compat.ts | 5 - packages/node/src/executors/execute/compat.ts | 5 - .../executors/execute/execute.impl.spec.ts | 335 ----------------- .../src/executors/execute/execute.impl.ts | 182 ---------- .../node/src/executors/execute/schema.json | 71 ---- .../{js => node}/src/executors/node/compat.ts | 0 .../node/node-with-require-overrides.ts | 0 .../src/executors/node/node.impl.ts | 6 +- .../src/executors/node/schema.d.ts | 0 .../src/executors/node/schema.json | 0 packages/node/src/executors/package/compat.ts | 5 - .../executors/package/package.impl.spec.ts | 341 ------------------ .../src/executors/package/package.impl.ts | 87 ----- .../node/src/executors/package/schema.json | 137 ------- .../node/src/executors/package/utils/cli.ts | 30 -- .../package/utils/compile-typescript-files.ts | 74 ---- .../src/executors/package/utils/models.ts | 27 -- .../package/utils/normalize-options.ts | 47 --- .../package/utils/update-package-json.ts | 24 -- packages/node/src/executors/webpack/compat.ts | 5 + .../executors/{build => webpack}/schema.json | 0 .../webpack.impl.spec.ts} | 10 +- .../build.impl.ts => webpack/webpack.impl.ts} | 4 +- .../application/application.spec.ts | 2 +- .../src/generators/application/application.ts | 2 +- .../rename-build-to-webpack.spec.ts | 49 +++ .../update-13-9-0/rename-build-to-webpack.ts | 20 + .../rename-execute-to-node.spec.ts | 49 +++ .../update-13-9-0/rename-execute-to-node.ts | 20 + .../update-package-to-tsc.spec.ts | 70 ++++ .../update-13-9-0/update-package-to-tsc.ts | 42 +++ packages/nx-plugin/package.json | 2 +- .../src/generators/executor/executor.spec.ts | 2 +- .../generators/generator/generator.spec.ts | 2 +- .../generators/migration/migration.spec.ts | 2 +- .../src/generators/plugin/plugin.spec.ts | 6 +- .../nx-plugin/src/generators/plugin/plugin.ts | 9 +- 69 files changed, 823 insertions(+), 2788 deletions(-) delete mode 100644 docs/generated/api-js/generators/application.md delete mode 100644 docs/generated/api-node/executors/execute.md rename docs/generated/{api-js => api-node}/executors/node.md (88%) delete mode 100644 docs/generated/api-node/executors/package.md rename docs/generated/api-node/executors/{build.md => webpack.md} (94%) delete mode 100644 packages/js/src/generators/application/application.spec.ts delete mode 100644 packages/js/src/generators/application/application.ts delete mode 100644 packages/js/src/generators/application/files/README.md delete mode 100644 packages/js/src/generators/application/files/package.json__tmpl__ delete mode 100644 packages/js/src/generators/application/files/src/app/__fileName__.spec.ts__tmpl__ delete mode 100644 packages/js/src/generators/application/files/src/app/__fileName__.ts__tmpl__ delete mode 100644 packages/js/src/generators/application/files/src/index.ts__tmpl__ delete mode 100644 packages/js/src/generators/application/files/tsconfig.app.json__tmpl__ delete mode 100644 packages/js/src/generators/application/files/tsconfig.json__tmpl__ delete mode 100644 packages/js/src/generators/application/schema.json create mode 100644 packages/js/src/migrations/update-13-9-0/update-node-executor.spec.ts create mode 100644 packages/js/src/migrations/update-13-9-0/update-node-executor.ts delete mode 100644 packages/js/src/utils/project-generator.ts delete mode 100644 packages/node/src/executors/build/compat.ts delete mode 100644 packages/node/src/executors/execute/compat.ts delete mode 100644 packages/node/src/executors/execute/execute.impl.spec.ts delete mode 100644 packages/node/src/executors/execute/execute.impl.ts delete mode 100644 packages/node/src/executors/execute/schema.json rename packages/{js => node}/src/executors/node/compat.ts (100%) rename packages/{js => node}/src/executors/node/node-with-require-overrides.ts (100%) rename packages/{js => node}/src/executors/node/node.impl.ts (98%) rename packages/{js => node}/src/executors/node/schema.d.ts (100%) rename packages/{js => node}/src/executors/node/schema.json (100%) delete mode 100644 packages/node/src/executors/package/compat.ts delete mode 100644 packages/node/src/executors/package/package.impl.spec.ts delete mode 100644 packages/node/src/executors/package/package.impl.ts delete mode 100644 packages/node/src/executors/package/schema.json delete mode 100644 packages/node/src/executors/package/utils/cli.ts delete mode 100644 packages/node/src/executors/package/utils/compile-typescript-files.ts delete mode 100644 packages/node/src/executors/package/utils/models.ts delete mode 100644 packages/node/src/executors/package/utils/normalize-options.ts delete mode 100644 packages/node/src/executors/package/utils/update-package-json.ts create mode 100644 packages/node/src/executors/webpack/compat.ts rename packages/node/src/executors/{build => webpack}/schema.json (100%) rename packages/node/src/executors/{build/build.impl.spec.ts => webpack/webpack.impl.spec.ts} (95%) rename packages/node/src/executors/{build/build.impl.ts => webpack/webpack.impl.ts} (97%) create mode 100644 packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.spec.ts create mode 100644 packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.ts create mode 100644 packages/node/src/migrations/update-13-9-0/rename-execute-to-node.spec.ts create mode 100644 packages/node/src/migrations/update-13-9-0/rename-execute-to-node.ts create mode 100644 packages/node/src/migrations/update-13-9-0/update-package-to-tsc.spec.ts create mode 100644 packages/node/src/migrations/update-13-9-0/update-package-to-tsc.ts diff --git a/docs/generated/api-js/generators/application.md b/docs/generated/api-js/generators/application.md deleted file mode 100644 index a86645904ba58..0000000000000 --- a/docs/generated/api-js/generators/application.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: '@nrwl/js:application generator' -description: 'Create a application' ---- - -# @nrwl/js:application - -Create a application - -## Usage - -```bash -nx generate application ... -``` - -```bash -nx g app ... # same -``` - -By default, Nx will search for `application` in the default collection provisioned in `workspace.json`. - -You can specify the collection explicitly as follows: - -```bash -nx g @nrwl/js:application ... -``` - -Show what will be generated without writing to disk: - -```bash -nx g application ... --dry-run -``` - -### Examples - -Generate libs/myapp/mylib: - -```bash -nx g lib mylib --directory=myapp -``` - -## Options - -### name (_**required**_) - -Type: `string` - -Library name - -### compiler - -Default: `tsc` - -Type: `string` - -Possible values: `tsc`, `swc` - -The compiler used by the build and test targets - -### config - -Default: `project` - -Type: `string` - -Possible values: `workspace`, `project`, `npm-scripts` - -Determines whether the project's executors should be configured in workspace.json, project.json or as npm scripts - -### directory - -Type: `string` - -A directory where the lib is placed - -### importPath - -Type: `string` - -The library name used to import it, like @myorg/my-awesome-lib - -### js - -Default: `false` - -Type: `boolean` - -Generate JavaScript files rather than TypeScript files - -### linter - -Default: `eslint` - -Type: `string` - -Possible values: `eslint`, `none` - -The tool to use for running lint checks. - -### pascalCaseFiles - -Alias(es): P - -Default: `false` - -Type: `boolean` - -Use pascal case file names. - -### setParserOptionsProject - -Default: `false` - -Type: `boolean` - -Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons. - -### skipFormat - -Default: `false` - -Type: `boolean` - -Skip formatting files - -### skipTsConfig - -Default: `false` - -Type: `boolean` - -Do not update tsconfig.json for development experience. - -### strict - -Default: `true` - -Type: `boolean` - -Whether to enable tsconfig strict mode or not. - -### tags - -Type: `string` - -Add tags to the library (used for linting) - -### testEnvironment - -Default: `jsdom` - -Type: `string` - -Possible values: `jsdom`, `node` - -The test environment to use if unitTestRunner is set to jest - -### unitTestRunner - -Default: `jest` - -Type: `string` - -Possible values: `jest`, `none` - -Test runner to use for unit tests diff --git a/docs/generated/api-node/executors/execute.md b/docs/generated/api-node/executors/execute.md deleted file mode 100644 index b90e8bedd7aa2..0000000000000 --- a/docs/generated/api-node/executors/execute.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: '@nrwl/node:execute executor' -description: 'Execute a Node application' ---- - -# @nrwl/node:execute - -Execute a Node application - -Options can be configured in `workspace.json` when defining the executor, or when invoking it. Read more about how to configure targets and executors here: https://nx.dev/configuration/projectjson#targets. - -## Options - -### buildTarget (_**required**_) - -Type: `string` - -The target to run to build you the app - -### args - -Type: `array` - -Extra args when starting the app - -### host - -Default: `localhost` - -Type: `string` - -The host to inspect the process on - -### inspect - -Default: `inspect` - -Type: `string | boolean ` - -Ensures the app is starting with debugging - -### port - -Default: `9229` - -Type: `number` - -The port to inspect the process on. Setting port to 0 will assign random free ports to all forked processes. - -### runtimeArgs - -Type: `array` - -Extra args passed to the node process - -### waitUntilTargets - -Type: `array` - -The targets to run to before starting the node app - -### watch - -Default: `true` - -Type: `boolean` - -Run build when files change diff --git a/docs/generated/api-js/executors/node.md b/docs/generated/api-node/executors/node.md similarity index 88% rename from docs/generated/api-js/executors/node.md rename to docs/generated/api-node/executors/node.md index 3f8d56c1c6411..a53b2dbed4870 100644 --- a/docs/generated/api-js/executors/node.md +++ b/docs/generated/api-node/executors/node.md @@ -1,11 +1,11 @@ --- -title: '@nrwl/js:node executor' -description: 'Build Node.js applications' +title: '@nrwl/node:node executor' +description: 'Execute a Node application' --- -# @nrwl/js:node +# @nrwl/node:node -Build Node.js applications +Execute a Node application Options can be configured in `workspace.json` when defining the executor, or when invoking it. Read more about how to configure targets and executors here: https://nx.dev/configuration/projectjson#targets. diff --git a/docs/generated/api-node/executors/package.md b/docs/generated/api-node/executors/package.md deleted file mode 100644 index 8791c8fb39a4f..0000000000000 --- a/docs/generated/api-node/executors/package.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: '@nrwl/node:package executor' -description: 'Package a Node library' ---- - -# @nrwl/node:package - -Package a Node library - -Options can be configured in `workspace.json` when defining the executor, or when invoking it. Read more about how to configure targets and executors here: https://nx.dev/configuration/projectjson#targets. - -## Options - -### main (_**required**_) - -Type: `string` - -The name of the main entry-point file. - -### tsConfig (_**required**_) - -Type: `string` - -The name of the Typescript configuration file. - -### assets - -Type: `array` - -List of static library assets. - -### buildableProjectDepsInPackageJsonType - -Default: `dependencies` - -Type: `string` - -Possible values: `dependencies`, `peerDependencies` - -When updateBuildableProjectDepsInPackageJson is true, this adds dependencies to either `peerDependencies` or `dependencies` - -### cli - -Type: `boolean` - -Adds a CLI wrapper to main entry-point file. - -### deleteOutputPath - -Default: `true` - -Type: `boolean` - -Delete the output path before building. - -### outputPath - -Type: `string` - -The output path of the generated files. - -### packageJson - -Type: `string` - -The name of the package.json file - -### sourceMap - -Default: `true` - -Type: `boolean` - -Output sourcemaps. - -### srcRootForCompilationRoot - -Type: `string` - -Sets the rootDir for TypeScript compilation. When not defined, it uses the project's root property - -### tsPlugins - -Type: `array` - -List of TypeScript Compiler Plugins. - -### updateBuildableProjectDepsInPackageJson - -Default: `true` - -Type: `boolean` - -Update buildable project dependencies in package.json - -### watch - -Default: `false` - -Type: `boolean` - -Enable re-building when files change. diff --git a/docs/generated/api-node/executors/build.md b/docs/generated/api-node/executors/webpack.md similarity index 94% rename from docs/generated/api-node/executors/build.md rename to docs/generated/api-node/executors/webpack.md index e7334603f1bf2..2a5755cfb4a01 100644 --- a/docs/generated/api-node/executors/build.md +++ b/docs/generated/api-node/executors/webpack.md @@ -1,11 +1,11 @@ --- -title: '@nrwl/node:build executor' -description: 'Build a Node application' +title: '@nrwl/node:webpack executor' +description: 'Build a Node application using webpack' --- -# @nrwl/node:build +# @nrwl/node:webpack -Build a Node application +Build a Node application using webpack Options can be configured in `workspace.json` when defining the executor, or when invoking it. Read more about how to configure targets and executors here: https://nx.dev/configuration/projectjson#targets. diff --git a/docs/map.json b/docs/map.json index 6e3cee138623b..51d6916309220 100644 --- a/docs/map.json +++ b/docs/map.json @@ -534,11 +534,6 @@ "searchResultsName": "@nrwl/js Overview", "file": "shared/js-plugin" }, - { - "name": "application generator", - "id": "application", - "file": "generated/api-js/generators/application" - }, { "name": "library generator", "id": "library", @@ -549,11 +544,6 @@ "id": "convert-to-swc", "file": "generated/api-js/generators/convert-to-swc" }, - { - "name": "node executor", - "id": "node", - "file": "generated/api-js/executors/node" - }, { "name": "tsc executor", "id": "tsc", @@ -969,19 +959,14 @@ "file": "generated/api-node/generators/library" }, { - "name": "build executor", - "id": "build", - "file": "generated/api-node/executors/build" - }, - { - "name": "execute executor", - "id": "execute", - "file": "generated/api-node/executors/execute" + "name": "webpack executor", + "id": "webpack", + "file": "generated/api-node/executors/webpack" }, { - "name": "package executor", - "id": "package", - "file": "generated/api-node/executors/package" + "name": "node executor", + "id": "node", + "file": "generated/api-node/executors/node" } ] }, diff --git a/e2e/js/src/js.test.ts b/e2e/js/src/js.test.ts index f8646a6848f82..51af7b938263a 100644 --- a/e2e/js/src/js.test.ts +++ b/e2e/js/src/js.test.ts @@ -14,7 +14,7 @@ import { } from '../../utils'; describe('js e2e', () => { - it('should create libs and apps with npm scripts', () => { + it('should create libs with npm scripts', () => { const scope = newProject(); const npmScriptsLib = uniq('npmscriptslib'); runCLI(`generate @nrwl/js:lib ${npmScriptsLib} --config=npm-scripts`); @@ -24,21 +24,13 @@ describe('js e2e', () => { expect(runCLI(`test ${npmScriptsLib}`)).toContain('implement test'); expect(runCLI(`test ${npmScriptsLib}`)).toContain('match the cache'); - const npmScriptsApp = uniq('npmscriptsapp'); - runCLI(`generate @nrwl/js:app ${npmScriptsApp} --config=npm-scripts`); - const appPackageJson = readJson(`apps/${npmScriptsApp}/package.json`); - expect(appPackageJson.scripts.test).toBeDefined(); - expect(appPackageJson.scripts.build).toBeDefined(); - expect(runCLI(`test ${npmScriptsApp}`)).toContain('implement test'); - expect(runCLI(`test ${npmScriptsApp}`)).toContain('match the cache'); - const tsconfig = readJson(`tsconfig.base.json`); expect(tsconfig.compilerOptions.paths).toEqual({ [`@${scope}/${npmScriptsLib}`]: [`libs/${npmScriptsLib}/src/index.ts`], }); }, 120000); - it('should create libs and apps with js executors (--compiler=tsc)', async () => { + it('should create libs with js executors (--compiler=tsc)', async () => { const scope = newProject(); const lib = uniq('lib'); runCLI(`generate @nrwl/js:lib ${lib} --buildable --compiler=tsc`); @@ -96,106 +88,99 @@ describe('js e2e', () => { ).resolves.not.toThrow(); libBuildProcess.kill(); - const app = uniq('app'); - runCLI(`generate @nrwl/js:app ${app} --buildable --compiler=tsc`); - const appPackageJson = readJson(`apps/${app}/package.json`); - expect(appPackageJson.scripts).toBeUndefined(); - expect((await runCLIAsync(`test ${app}`)).combinedOutput).toContain( + const parentLib = uniq('parentlib'); + runCLI(`generate @nrwl/js:lib ${parentLib} --buildable --compiler=tsc`); + const parentLibPackageJson = readJson(`libs/${parentLib}/package.json`); + expect(parentLibPackageJson.scripts).toBeUndefined(); + expect((await runCLIAsync(`test ${parentLib}`)).combinedOutput).toContain( 'Ran all test suites' ); - expect((await runCLIAsync(`test ${app}`)).combinedOutput).toContain( + expect((await runCLIAsync(`test ${parentLib}`)).combinedOutput).toContain( 'match the cache' ); - expect(runCLI(`build ${app}`)).toContain('Done compiling TypeScript files'); - checkFilesExist( - `dist/apps/${app}/package.json`, - `dist/apps/${app}/src/index.js`, - `dist/apps/${app}/src/app/${app}.js` + expect(runCLI(`build ${parentLib}`)).toContain( + 'Done compiling TypeScript files' ); - - expect(runCommand(`node dist/apps/${app}/src/index.js`)).toContain( - `Running ${app}` + checkFilesExist( + `dist/libs/${parentLib}/package.json`, + `dist/libs/${parentLib}/src/index.js`, + `dist/libs/${parentLib}/src/lib/${parentLib}.js` ); const tsconfig = readJson(`tsconfig.base.json`); expect(tsconfig.compilerOptions.paths).toEqual({ [`@${scope}/${lib}`]: [`libs/${lib}/src/index.ts`], + [`@${scope}/${parentLib}`]: [`libs/${parentLib}/src/index.ts`], }); - updateFile(`apps/${app}/src/index.ts`, () => { + updateFile(`libs/${parentLib}/src/index.ts`, () => { return ` import { ${lib} } from '@${scope}/${lib}' - console.log('Running ' + ${lib}()) `; }); - const output = runCLI(`build ${app}`); + const output = runCLI(`build ${parentLib}`); expect(output).toContain('1 task(s) it depends on'); expect(output).toContain('Done compiling TypeScript files'); - - expect(runCLI(`serve ${app} --no-watch`)).toContain(`Running ${lib}`); }, 120000); - // reenable when once ci runs on node 16 - // it('should create libs and apps with js executors (--compiler=swc)', async () => { - // const scope = newProject(); - // const lib = uniq('lib'); - // runCLI(`generate @nrwl/js:lib ${lib} --buildable --compiler=swc`); - // const libPackageJson = readJson(`libs/${lib}/package.json`); - // expect(libPackageJson.scripts).toBeUndefined(); - // expect((await runCLIAsync(`test ${lib}`)).combinedOutput).toContain( - // 'Ran all test suites' - // ); - // expect((await runCLIAsync(`test ${lib}`)).combinedOutput).toContain( - // 'match the cache' - // ); - // - // expect(runCLI(`build ${lib}`)).toContain('Successfully compiled: 2 files with swc'); - // checkFilesExist( - // `dist/libs/${lib}/package.json`, - // `dist/libs/${lib}/src/index.js`, - // `dist/libs/${lib}/src/lib/${lib}.js` - // ); - // - // const app = uniq('app'); - // runCLI(`generate @nrwl/js:app ${app} --buildable --compiler=swc`); - // const appPackageJson = readJson(`apps/${app}/package.json`); - // expect(appPackageJson.scripts).toBeUndefined(); - // expect((await runCLIAsync(`test ${app}`)).combinedOutput).toContain( - // 'Ran all test suites' - // ); - // expect((await runCLIAsync(`test ${app}`)).combinedOutput).toContain( - // 'match the cache' - // ); - // - // expect(runCLI(`build ${app}`)).toContain('Successfully compiled: 2 files with swc'); - // checkFilesExist( - // `dist/apps/${app}/package.json`, - // `dist/apps/${app}/src/index.js`, - // `dist/apps/${app}/src/app/${app}.js` - // ); - // - // expect(runCommand(`node dist/apps/${app}/src/index.js`)).toContain( - // `Running ${app}` - // ); - // - // const tsconfig = readJson(`tsconfig.base.json`); - // expect(tsconfig.compilerOptions.paths).toEqual({ - // [`@${scope}/${lib}`]: [`libs/${lib}/src/index.ts`], - // }); - // - // updateFile(`apps/${app}/src/index.ts`, () => { - // return ` - // import { ${lib} } from '@${scope}/${lib}' - // console.log('Running ' + ${lib}()) - // `; - // }); - // - // const output = runCLI(`build ${app}`); - // expect(output).toContain('1 task(s) it depends on'); - // expect(output).toContain('Successfully compiled: 2 files with swc'); - // - // expect(runCommand(`serve ${app} --watch=false`)).toContain(`Running ${lib}`) - // }, 120000); + it('should create libs with js executors (--compiler=swc)', async () => { + const scope = newProject(); + const lib = uniq('lib'); + runCLI(`generate @nrwl/js:lib ${lib} --buildable --compiler=swc`); + const libPackageJson = readJson(`libs/${lib}/package.json`); + expect(libPackageJson.scripts).toBeUndefined(); + expect((await runCLIAsync(`test ${lib}`)).combinedOutput).toContain( + 'Ran all test suites' + ); + expect((await runCLIAsync(`test ${lib}`)).combinedOutput).toContain( + 'match the cache' + ); + + expect(runCLI(`build ${lib}`)).toContain( + 'Successfully compiled: 2 files with swc' + ); + checkFilesExist( + `dist/libs/${lib}/package.json`, + `dist/libs/${lib}/src/index.js`, + `dist/libs/${lib}/src/lib/${lib}.js` + ); + + const parentLib = uniq('parentlib'); + runCLI(`generate @nrwl/js:lib ${parentLib} --buildable --compiler=swc`); + const parentLibPackageJson = readJson(`libs/${parentLib}/package.json`); + expect(parentLibPackageJson.scripts).toBeUndefined(); + expect((await runCLIAsync(`test ${parentLib}`)).combinedOutput).toContain( + 'Ran all test suites' + ); + expect((await runCLIAsync(`test ${parentLib}`)).combinedOutput).toContain( + 'match the cache' + ); + + expect(runCLI(`build ${parentLib}`)).toContain( + 'Successfully compiled: 2 files with swc' + ); + checkFilesExist( + `dist/libs/${parentLib}/package.json`, + `dist/libs/${parentLib}/src/index.js`, + `dist/libs/${parentLib}/src/lib/${parentLib}.js` + ); + + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [`@${scope}/${lib}`]: [`libs/${lib}/src/index.ts`], + [`@${scope}/${parentLib}`]: [`libs/${parentLib}/src/index.ts`], + }); + + updateFile(`libs/${parentLib}/src/index.ts`, () => { + return ` + import { ${lib} } from '@${scope}/${lib}' + `; + }); + + const output = runCLI(`build ${parentLib}`); + expect(output).toContain('1 task(s) it depends on'); + expect(output).toContain('Successfully compiled: 2 files with swc'); + }, 120000); }); diff --git a/e2e/node/src/node.test.ts b/e2e/node/src/node.test.ts index 623d5a03bb05a..03fdd4fe35903 100644 --- a/e2e/node/src/node.test.ts +++ b/e2e/node/src/node.test.ts @@ -4,13 +4,11 @@ import * as http from 'http'; import { checkFilesDoNotExist, checkFilesExist, - createFile, killPorts, newProject, packageInstall, promisifiedTreeKill, readFile, - readJson, removeFile, runCLI, runCLIAsync, @@ -20,7 +18,6 @@ import { updateFile, updateProjectConfig, } from '@nrwl/e2e/utils'; -import { accessSync, constants } from 'fs-extra'; function getData(port): Promise { return new Promise((resolve) => { @@ -353,177 +350,6 @@ exports.FooDto = FooDto; }); }); -describe('Node Libraries', () => { - it('should be able to generate a node library', async () => { - newProject(); - const nodelib = uniq('nodelib'); - - runCLI(`generate @nrwl/node:lib ${nodelib}`); - - const lintResults = runCLI(`lint ${nodelib}`); - expect(lintResults).toContain('All files pass linting.'); - - const jestResult = await runCLIAsync(`test ${nodelib}`); - expect(jestResult.combinedOutput).toContain( - 'Test Suites: 1 passed, 1 total' - ); - - checkFilesDoNotExist(`libs/${nodelib}/package.json`); - }, 300000); - - it('should be able to generate a publishable node library', async () => { - const proj = newProject(); - - const nodeLib = uniq('nodelib'); - runCLI( - `generate @nrwl/node:lib ${nodeLib} --publishable --importPath=@${proj}/${nodeLib}` - ); - checkFilesExist(`libs/${nodeLib}/package.json`); - const tslibConfig = readJson(`libs/${nodeLib}/tsconfig.lib.json`); - expect(tslibConfig).toEqual({ - extends: './tsconfig.json', - compilerOptions: { - module: 'commonjs', - outDir: '../../dist/out-tsc', - declaration: true, - types: ['node'], - }, - exclude: ['**/*.spec.ts', '**/*.test.ts'], - include: ['**/*.ts'], - }); - await runCLIAsync(`build ${nodeLib}`); - checkFilesExist( - `dist/libs/${nodeLib}/src/index.js`, - `dist/libs/${nodeLib}/src/index.d.ts`, - `dist/libs/${nodeLib}/package.json` - ); - - expect(readJson(`dist/libs/${nodeLib}/package.json`)).toEqual({ - name: `@${proj}/${nodeLib}`, - version: '0.0.1', - main: './src/index.js', - typings: './src/index.d.ts', - }); - - // Copying package.json from assets - updateProjectConfig(nodeLib, (config) => { - config.targets.build.options.assets.push(`libs/${nodeLib}/package.json`); - return config; - }); - createFile(`dist/libs/${nodeLib}/_should_remove.txt`); // Output directory should be removed - await runCLIAsync(`build ${nodeLib}`); - expect(readJson(`dist/libs/${nodeLib}/package.json`)).toEqual({ - name: `@${proj}/${nodeLib}`, - version: '0.0.1', - main: './src/index.js', - typings: './src/index.d.ts', - }); - }, 300000); - - it('should be able to generate a publishable node library with CLI wrapper', async () => { - const proj = newProject(); - - const nodeLib = uniq('nodelib'); - runCLI( - `generate @nrwl/node:lib ${nodeLib} --publishable --importPath=@${proj}/${nodeLib}` - ); - - updateProjectConfig(nodeLib, (config) => { - config.targets.build.options.cli = true; - return config; - }); - - await runCLIAsync(`build ${nodeLib}`); - - const binFile = `dist/libs/${nodeLib}/index.bin.js`; - checkFilesExist(binFile); - expect(() => - accessSync(tmpProjPath(binFile), constants.X_OK) - ).not.toThrow(); - - expect(readJson(`dist/libs/${nodeLib}/package.json`).bin).toEqual({ - [nodeLib]: './index.bin.js', - }); - checkFilesDoNotExist(`dist/libs/${nodeLib}/_should_remove.txt`); - - // Support not deleting output path before build - createFile(`dist/libs/${nodeLib}/_should_keep.txt`); - await runCLIAsync(`build ${nodeLib} --delete-output-path=false`); - checkFilesExist(`dist/libs/${nodeLib}/_should_keep.txt`); - }, 300000); - - it('should support --js flag', async () => { - const proj = newProject(); - - const nodeLib = uniq('nodelib'); - runCLI( - `generate @nrwl/node:lib ${nodeLib} --publishable --importPath=@${proj}/${nodeLib} --js` - ); - checkFilesExist( - `libs/${nodeLib}/package.json`, - `libs/${nodeLib}/src/index.js`, - `libs/${nodeLib}/src/lib/${nodeLib}.js`, - `libs/${nodeLib}/src/lib/${nodeLib}.spec.js` - ); - checkFilesDoNotExist( - `libs/${nodeLib}/src/index.ts`, - `libs/${nodeLib}/src/lib/${nodeLib}.ts`, - `libs/${nodeLib}/src/lib/${nodeLib}.spec.ts` - ); - await runCLIAsync(`build ${nodeLib}`); - checkFilesExist( - `dist/libs/${nodeLib}/src/index.js`, - `dist/libs/${nodeLib}/package.json` - ); - }, 300000); - - it('should be able to copy assets', () => { - const proj = newProject(); - const nodelib = uniq('nodelib'); - const nglib = uniq('nglib'); - - // Generating two libraries just to have a lot of files to copy - runCLI( - `generate @nrwl/node:lib ${nodelib} --publishable --importPath=@${proj}/${nodelib}` - ); - /** - * The angular lib contains a lot sub directories that would fail without - * `nodir: true` in the package.impl.ts - */ - runCLI( - `generate @nrwl/angular:lib ${nglib} --publishable --importPath=@${proj}/${nglib}` - ); - - updateProjectConfig(nodelib, (config) => { - config.targets.build.options.assets.push({ - input: `./dist/libs/${nglib}`, - glob: '**/*', - output: '.', - }); - return config; - }); - - runCLI(`build ${nglib}`); - runCLI(`build ${nodelib}`); - checkFilesExist(`./dist/libs/${nodelib}/esm2020/index.mjs`); - }, 300000); - - it('should fail when trying to compile typescript files that are invalid', () => { - const proj = newProject(); - const nodeLib = uniq('nodelib'); - runCLI( - `generate @nrwl/node:lib ${nodeLib} --publishable --importPath=@${proj}/${nodeLib}` - ); - updateFile( - `libs/${nodeLib}/src/index.ts`, - stripIndents` - const temp: number = 'should fail' - ` - ); - expect(() => runCLI(`build ${nodeLib}`)).toThrow(); - }); -}); - describe('nest libraries', function () { beforeEach(() => newProject()); @@ -607,7 +433,7 @@ describe('nest libraries', function () { packageInstall('@nestjs/swagger', undefined, '4.8.2'); updateProjectConfig(nestlib, (config) => { - config.targets.build.options.tsPlugins = [ + config.targets.build.options.transformers = [ { name: '@nestjs/swagger/plugin', options: { @@ -658,112 +484,3 @@ exports.FooModel = FooModel; ).not.toThrow(); }, 1000000); }); - -describe('with dependencies', () => { - /** - * Graph: - * - * childLib - * / - * app => parentLib => - * \ - * \ - * childLib2 - * - */ - let app: string; - let parentLib: string; - let childLib: string; - let childLib2: string; - let proj: string; - - beforeEach(() => { - app = uniq('app'); - parentLib = uniq('parentlib'); - childLib = uniq('childlib'); - childLib2 = uniq('childlib2'); - - proj = newProject(); - - runCLI(`generate @nrwl/express:app ${app}`); - runCLI(`generate @nrwl/node:lib ${parentLib} --buildable=true`); - runCLI(`generate @nrwl/node:lib ${childLib} --buildable=true`); - runCLI(`generate @nrwl/node:lib ${childLib2} --buildable=true`); - - // create dependencies by importing - const createDep = (parent, children: string[]) => { - updateFile( - `libs/${parent}/src/lib/${parent}.ts`, - ` - ${children - .map( - (entry) => `import { ${entry} } from '@${proj}/${entry}';` - ) - .join('\n')} - - export function ${parent}(): string { - return '${parent}' + ' ' + ${children - .map((entry) => `${entry}()`) - .join('+')} - } - ` - ); - }; - - createDep(parentLib, [childLib, childLib2]); - - updateFile( - `apps/${app}/src/main.ts`, - ` - import "@${proj}/${parentLib}"; - ` - ); - }); - - it('should build a library without dependencies', () => { - const childLibOutput = runCLI(`build ${childLib}`); - - expect(childLibOutput).toContain( - `Done compiling TypeScript files for project "${childLib}"` - ); - }); - - it('should build a parent library if the dependent libraries have been built before', () => { - const childLibOutput = runCLI(`build ${childLib}`); - expect(childLibOutput).toContain( - `Done compiling TypeScript files for project "${childLib}"` - ); - - const childLib2Output = runCLI(`build ${childLib2}`); - expect(childLib2Output).toContain( - `Done compiling TypeScript files for project "${childLib2}"` - ); - - const parentLibOutput = runCLI(`build ${parentLib}`); - expect(parentLibOutput).toContain( - `Done compiling TypeScript files for project "${parentLib}"` - ); - - // assert package.json deps have been set - const assertPackageJson = ( - parent: string, - lib: string, - version: string - ) => { - const jsonFile = readJson(`dist/libs/${parent}/package.json`); - const childDependencyVersion = jsonFile.dependencies[`@${proj}/${lib}`]; - expect(childDependencyVersion).toBe(version); - }; - - assertPackageJson(parentLib, childLib, '0.0.1'); - assertPackageJson(parentLib, childLib2, '0.0.1'); - }); - - it('should build an app composed out of buildable libs', () => { - const buildWithDeps = runCLI( - `build ${app} --with-deps --buildLibsFromSource=false` - ); - expect(buildWithDeps).toContain('Successfully ran target build'); - checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`); - }, 1000000); -}); diff --git a/packages/js/executors.json b/packages/js/executors.json index 85d485ab067ca..82fc5612b80e9 100644 --- a/packages/js/executors.json +++ b/packages/js/executors.json @@ -10,11 +10,6 @@ "implementation": "./src/executors/swc/swc.impl", "schema": "./src/executors/swc/schema.json", "description": "Build a project using SWC" - }, - "node": { - "implementation": "./src/executors/node/node.impl", - "schema": "./src/executors/node/schema.json", - "description": "Build Node.js applications" } }, "builders": { @@ -27,11 +22,6 @@ "implementation": "./src/executors/swc/compat", "schema": "./src/executors/swc/schema.json", "description": "Build a project using SWC" - }, - "node": { - "implementation": "./src/executors/node/compat", - "schema": "./src/executors/node/schema.json", - "description": "Build Node.js applications" } } } diff --git a/packages/js/generators.json b/packages/js/generators.json index 3287dbeebc49d..2d122d36a453b 100644 --- a/packages/js/generators.json +++ b/packages/js/generators.json @@ -9,13 +9,6 @@ "x-type": "library", "description": "Create a library" }, - "application": { - "factory": "./src/generators/application/application#applicationSchematic", - "schema": "./src/generators/application/schema.json", - "aliases": ["app"], - "x-type": "application", - "description": "Create a application" - }, "convert-to-swc": { "factory": "./src/generators/convert-to-swc/convert-to-swc#convertToSwcSchematic", "schema": "./src/generators/convert-to-swc/schema.json", @@ -32,13 +25,6 @@ "x-type": "library", "description": "Create a library" }, - "application": { - "factory": "./src/generators/application/application#applicationGenerator", - "schema": "./src/generators/application/schema.json", - "aliases": ["app"], - "x-type": "application", - "description": "Create a application" - }, "convert-to-swc": { "factory": "./src/generators/convert-to-swc/convert-to-swc#convertToSwcGenerator", "schema": "./src/generators/convert-to-swc/schema.json", diff --git a/packages/js/migrations.json b/packages/js/migrations.json index f9d34cef28c2c..063e15a289d04 100644 --- a/packages/js/migrations.json +++ b/packages/js/migrations.json @@ -1,4 +1,11 @@ { - "generators": {}, + "generators": { + "update-node-executor": { + "cli": "nx", + "version": "13.9.0-beta.1", + "description": "Renames @nrwl/js:node to @nrwl/node:node", + "factory": "./src/migrations/update-13-9-0/update-node-executor" + } + }, "packageJsonUpdates": {} } diff --git a/packages/js/src/generators/application/application.spec.ts b/packages/js/src/generators/application/application.spec.ts deleted file mode 100644 index d41a3a3ae88d9..0000000000000 --- a/packages/js/src/generators/application/application.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit'; -import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { GeneratorSchema } from '../../utils/schema'; -import applicationGenerator from './application'; - -// most of the functionality is tested via the library generator because the library and application share -// most of the code -// only testing the difference here -describe('app', () => { - let tree: Tree; - const defaultOptions: Omit = { - skipTsConfig: false, - unitTestRunner: 'jest', - skipFormat: false, - linter: 'eslint', - testEnvironment: 'jsdom', - js: false, - pascalCaseFiles: false, - strict: true, - config: 'project', - compiler: 'tsc', - }; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(2); - }); - - it('should generate an empty ts app using --config=npm-scripts', async () => { - await applicationGenerator(tree, { - ...defaultOptions, - name: 'myApp', - config: 'npm-scripts', - }); - expect(readJson(tree, '/apps/my-app/package.json')).toEqual({ - name: '@proj/my-app', - version: '0.0.1', - type: 'commonjs', - scripts: { - build: "echo 'implement build'", - test: "echo 'implement test'", - }, - }); - - expect(tree.exists('apps/my-app/src/index.ts')).toBeTruthy(); - expect(tree.exists('apps/my-app/src/app/my-app.ts')).toBeTruthy(); - - // unitTestRunner property is ignored. - // It only works with our executors. - expect(tree.exists('apps/my-app/src/app/my-app.spec.ts')).toBeFalsy(); - const workspaceJson = readJson(tree, '/workspace.json'); - // Blocked on Craigory merging optional config PR - // expect(workspaceJson.projects['my-app']).toBeUndefined(); - // expect(tree.exists('apps/my-app/project.json')).toBeFalsy(); - }); - - it('should generate an empty ts app using --config=project', async () => { - await applicationGenerator(tree, { - ...defaultOptions, - name: 'my-app', - config: 'project', - }); - const projectConfig = readProjectConfiguration(tree, 'my-app'); - expect(projectConfig.root).toEqual('apps/my-app'); - expect(projectConfig.targets.build).toEqual({ - executor: '@nrwl/js:tsc', - options: { - assets: ['apps/my-app/*.md'], - main: 'apps/my-app/src/index.ts', - outputPath: 'dist/apps/my-app', - tsConfig: 'apps/my-app/tsconfig.app.json', - }, - outputs: ['{options.outputPath}'], - }); - }); - - it('should generate a "serve" target', async () => { - await applicationGenerator(tree, { - ...defaultOptions, - name: 'my-app', - }); - const projectConfig = readProjectConfiguration(tree, 'my-app'); - expect(projectConfig.targets.serve).toEqual({ - executor: `@nrwl/js:node`, - options: { - buildTarget: `my-app:build`, - }, - }); - }); -}); diff --git a/packages/js/src/generators/application/application.ts b/packages/js/src/generators/application/application.ts deleted file mode 100644 index ba8a087219c4b..0000000000000 --- a/packages/js/src/generators/application/application.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { convertNxGenerator, getWorkspaceLayout, Tree } from '@nrwl/devkit'; -import { join } from 'path'; -import { projectGenerator } from '../../utils/project-generator'; -import { GeneratorSchema } from '../../utils/schema'; - -export async function applicationGenerator( - tree: Tree, - schema: GeneratorSchema -) { - const { appsDir } = getWorkspaceLayout(tree); - return projectGenerator( - tree, - { ...schema, buildable: true, skipTsConfig: true }, - appsDir, - join(__dirname, './files'), - 'application' - ); -} - -export default applicationGenerator; -export const applicationSchematic = convertNxGenerator(applicationGenerator); diff --git a/packages/js/src/generators/application/files/README.md b/packages/js/src/generators/application/files/README.md deleted file mode 100644 index 698e419c88f68..0000000000000 --- a/packages/js/src/generators/application/files/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# <%= name %> - -This application was generated with [Nx](https://nx.dev). - -## Building - -Run `<%= cliCommand %> build <%= name %>` to build the application. - -## Starting - -Run `<%= cliCommand %> start <%= name %>` to start/run the application. - -<% if (hasUnitTestRunner) { %> - -## Running unit tests - -Run `<%= cliCommand %> test <%= name %>` to execute the unit tests via [Jest](https://jestjs.io). - -<% } %> diff --git a/packages/js/src/generators/application/files/package.json__tmpl__ b/packages/js/src/generators/application/files/package.json__tmpl__ deleted file mode 100644 index 7ede38f8da1ed..0000000000000 --- a/packages/js/src/generators/application/files/package.json__tmpl__ +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "<%= importPath %>", - "version": "0.0.1", - "type": "commonjs" -} diff --git a/packages/js/src/generators/application/files/src/app/__fileName__.spec.ts__tmpl__ b/packages/js/src/generators/application/files/src/app/__fileName__.spec.ts__tmpl__ deleted file mode 100644 index 35b0948b95087..0000000000000 --- a/packages/js/src/generators/application/files/src/app/__fileName__.spec.ts__tmpl__ +++ /dev/null @@ -1,7 +0,0 @@ -import { <%= propertyName %> } from './<%= fileName %>'; - -describe('<%= propertyName %>', () => { - it('should work', () => { - expect(<%= propertyName %>()).toEqual('<%= name %>'); - }) -}) \ No newline at end of file diff --git a/packages/js/src/generators/application/files/src/app/__fileName__.ts__tmpl__ b/packages/js/src/generators/application/files/src/app/__fileName__.ts__tmpl__ deleted file mode 100644 index ae311e3ac41f0..0000000000000 --- a/packages/js/src/generators/application/files/src/app/__fileName__.ts__tmpl__ +++ /dev/null @@ -1,3 +0,0 @@ -export function <%= propertyName %>(): string { - return '<%= name %>'; -} diff --git a/packages/js/src/generators/application/files/src/index.ts__tmpl__ b/packages/js/src/generators/application/files/src/index.ts__tmpl__ deleted file mode 100644 index 430add4c85584..0000000000000 --- a/packages/js/src/generators/application/files/src/index.ts__tmpl__ +++ /dev/null @@ -1,3 +0,0 @@ -import {<%= propertyName %>} from './app/<%= fileName %>'; - -console.log(`Running ${<%= propertyName %>()}`) diff --git a/packages/js/src/generators/application/files/tsconfig.app.json__tmpl__ b/packages/js/src/generators/application/files/tsconfig.app.json__tmpl__ deleted file mode 100644 index 6bbdeba123c5e..0000000000000 --- a/packages/js/src/generators/application/files/tsconfig.app.json__tmpl__ +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "<%= offsetFromRoot %>dist/out-tsc", - "declaration": true, - "types": [] - }, - "include": ["**/*.ts"<% if (js) { %>, "**/*.js"<% } %>], - "exclude": ["**/*.spec.ts", "**/*.test.ts"<% if (js) { %>, "**/*.spec.js", "**/*.test.js"<% } %>] -} diff --git a/packages/js/src/generators/application/files/tsconfig.json__tmpl__ b/packages/js/src/generators/application/files/tsconfig.json__tmpl__ deleted file mode 100644 index 2e4627cddc3a9..0000000000000 --- a/packages/js/src/generators/application/files/tsconfig.json__tmpl__ +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "<%= offsetFromRoot %>tsconfig.base.json", - "compilerOptions": { - "module": "CommonJS"<% if (js) { %>, - "allowJs": true<% } %> - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - } - ] -} diff --git a/packages/js/src/generators/application/schema.json b/packages/js/src/generators/application/schema.json deleted file mode 100644 index 2879fcfca0112..0000000000000 --- a/packages/js/src/generators/application/schema.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "$id": "NxTypescriptApplication", - "cli": "nx", - "title": "Create a TypeScript application", - "type": "object", - "examples": [ - { - "command": "g lib mylib --directory=myapp", - "description": "Generate libs/myapp/mylib" - } - ], - "properties": { - "name": { - "type": "string", - "description": "Library name", - "$default": { - "$source": "argv", - "index": 0 - }, - "x-prompt": "What name would you like to use for the library?", - "pattern": "^[a-zA-Z].*$" - }, - "directory": { - "type": "string", - "description": "A directory where the lib is placed" - }, - "linter": { - "description": "The tool to use for running lint checks.", - "type": "string", - "enum": ["eslint", "none"], - "default": "eslint" - }, - "unitTestRunner": { - "type": "string", - "enum": ["jest", "none"], - "description": "Test runner to use for unit tests", - "default": "jest" - }, - "tags": { - "type": "string", - "description": "Add tags to the library (used for linting)" - }, - "skipFormat": { - "description": "Skip formatting files", - "type": "boolean", - "default": false - }, - "skipTsConfig": { - "type": "boolean", - "description": "Do not update tsconfig.json for development experience.", - "default": false - }, - "testEnvironment": { - "type": "string", - "enum": ["jsdom", "node"], - "description": "The test environment to use if unitTestRunner is set to jest", - "default": "jsdom" - }, - "importPath": { - "type": "string", - "description": "The library name used to import it, like @myorg/my-awesome-lib" - }, - "pascalCaseFiles": { - "type": "boolean", - "description": "Use pascal case file names.", - "alias": "P", - "default": false - }, - "js": { - "type": "boolean", - "description": "Generate JavaScript files rather than TypeScript files", - "default": false - }, - "strict": { - "type": "boolean", - "description": "Whether to enable tsconfig strict mode or not.", - "default": true - }, - "setParserOptionsProject": { - "type": "boolean", - "description": "Whether or not to configure the ESLint \"parserOptions.project\" option. We do not do this by default for lint performance reasons.", - "default": false - }, - "config": { - "type": "string", - "enum": ["workspace", "project", "npm-scripts"], - "default": "project", - "description": "Determines whether the project's executors should be configured in workspace.json, project.json or as npm scripts" - }, - "compiler": { - "type": "string", - "enum": ["tsc", "swc"], - "default": "tsc", - "description": "The compiler used by the build and test targets" - } - }, - "required": ["name"] -} diff --git a/packages/js/src/generators/library/library.ts b/packages/js/src/generators/library/library.ts index e6579faca145d..997f1e324510f 100644 --- a/packages/js/src/generators/library/library.ts +++ b/packages/js/src/generators/library/library.ts @@ -1,17 +1,312 @@ -import { convertNxGenerator, getWorkspaceLayout, Tree } from '@nrwl/devkit'; +import { + addProjectConfiguration, + convertNxGenerator, + formatFiles, + generateFiles, + GeneratorCallback, + getWorkspaceLayout, + joinPathFragments, + names, + offsetFromRoot, + ProjectConfiguration, + toJS, + Tree, + updateJson, +} from '@nrwl/devkit'; import { join } from 'path'; -import { projectGenerator } from '../../utils/project-generator'; import { GeneratorSchema } from '../../utils/schema'; +import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { Linter, lintProjectGenerator } from '@nrwl/linter'; +import { jestProjectGenerator } from '@nrwl/jest'; +import { addSwcDependencies } from '../../utils/swc/add-swc-dependencies'; +import { addSwcConfig } from '../../utils/swc/add-swc-config'; export async function libraryGenerator(tree: Tree, schema: GeneratorSchema) { const { libsDir } = getWorkspaceLayout(tree); - return projectGenerator( - tree, - schema, - libsDir, - join(__dirname, './files'), - 'library' - ); + return projectGenerator(tree, schema, libsDir, join(__dirname, './files')); +} + +export async function projectGenerator( + tree: Tree, + schema: GeneratorSchema, + destinationDir: string, + filesDir: string +) { + const options = normalizeOptions(tree, schema, destinationDir); + + createFiles(tree, options, filesDir); + + addProject(tree, options, destinationDir); + + if (!schema.skipTsConfig) { + updateRootTsConfig(tree, options); + } + + const tasks: GeneratorCallback[] = []; + + if (options.linter !== 'none') { + const lintCallback = await addLint(tree, options); + tasks.push(lintCallback); + } + if (options.unitTestRunner === 'jest') { + const jestCallback = await addJest(tree, options); + tasks.push(jestCallback); + } + + if (!options.skipFormat) { + await formatFiles(tree); + } + + return runTasksInSerial(...tasks); +} + +export interface NormalizedSchema extends GeneratorSchema { + name: string; + fileName: string; + projectRoot: string; + projectDirectory: string; + parsedTags: string[]; + importPath?: string; +} + +function addProject( + tree: Tree, + options: NormalizedSchema, + destinationDir: string +) { + const projectConfiguration: ProjectConfiguration = { + root: options.projectRoot, + sourceRoot: joinPathFragments(options.projectRoot, 'src'), + targets: {}, + tags: options.parsedTags, + }; + + if (options.buildable && options.config != 'npm-scripts') { + projectConfiguration.targets.build = { + executor: `@nrwl/js:${options.compiler}`, + outputs: ['{options.outputPath}'], + options: { + outputPath: `dist/${destinationDir}/${options.projectDirectory}`, + main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'), + tsConfig: `${options.projectRoot}/tsconfig.lib.json`, + assets: [`${options.projectRoot}/*.md`], + }, + }; + + if (options.compiler === 'swc' && options.skipTypeCheck) { + projectConfiguration.targets.build.options.skipTypeCheck = true; + } + } + + if (options.config === 'workspace') { + addProjectConfiguration(tree, options.name, projectConfiguration, false); + } else if (options.config === 'project') { + addProjectConfiguration(tree, options.name, projectConfiguration, true); + } else { + addProjectConfiguration( + tree, + options.name, + { + root: projectConfiguration.root, + tags: projectConfiguration.tags, + targets: {}, + }, + true + ); + } +} + +export function addLint( + tree: Tree, + options: NormalizedSchema +): Promise { + return lintProjectGenerator(tree, { + project: options.name, + linter: options.linter, + skipFormat: true, + tsConfigPaths: [ + joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), + ], + eslintFilePatterns: [ + `${options.projectRoot}/**/*.${options.js ? 'js' : 'ts'}`, + ], + setParserOptionsProject: options.setParserOptionsProject, + }); +} + +function updateTsConfig(tree: Tree, options: NormalizedSchema) { + updateJson(tree, join(options.projectRoot, 'tsconfig.json'), (json) => { + if (options.strict) { + json.compilerOptions = { + ...json.compilerOptions, + forceConsistentCasingInFileNames: true, + strict: true, + noImplicitOverride: true, + noPropertyAccessFromIndexSignature: true, + noImplicitReturns: true, + noFallthroughCasesInSwitch: true, + }; + } + + return json; + }); +} + +function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) { + const { className, name, propertyName } = names(options.name); + + generateFiles(tree, filesDir, options.projectRoot, { + ...options, + dot: '.', + className, + name, + propertyName, + js: !!options.js, + cliCommand: 'nx', + strict: undefined, + tmpl: '', + offsetFromRoot: offsetFromRoot(options.projectRoot), + buildable: options.buildable === true, + hasUnitTestRunner: options.unitTestRunner !== 'none', + }); + + if (options.buildable && options.compiler === 'swc') { + addSwcDependencies(tree); + addSwcConfig(tree, options.projectRoot); + } + + if (options.unitTestRunner === 'none') { + tree.delete( + join(options.projectRoot, 'src/lib', `${options.fileName}.spec.ts`) + ); + tree.delete( + join(options.projectRoot, 'src/app', `${options.fileName}.spec.ts`) + ); + } + + if (options.js) { + toJS(tree); + } + + const packageJsonPath = join(options.projectRoot, 'package.json'); + if (options.config === 'npm-scripts') { + updateJson(tree, packageJsonPath, (json) => { + json.scripts = { + build: "echo 'implement build'", + test: "echo 'implement test'", + }; + return json; + }); + } else if (!options.buildable) { + tree.delete(packageJsonPath); + } + + updateTsConfig(tree, options); +} + +async function addJest( + tree: Tree, + options: NormalizedSchema +): Promise { + return await jestProjectGenerator(tree, { + project: options.name, + setupFile: 'none', + supportTsx: false, + skipSerializers: true, + testEnvironment: options.testEnvironment, + skipFormat: true, + compiler: options.compiler, + }); +} + +function normalizeOptions( + tree: Tree, + options: GeneratorSchema, + destinationDir: string +): NormalizedSchema { + if (options.config === 'npm-scripts') { + options.unitTestRunner = 'none'; + options.linter = Linter.None; + options.buildable = false; + } + options.compiler ??= 'tsc'; + + if (options.compiler === 'swc' && options.skipTypeCheck == null) { + options.skipTypeCheck = false; + } + + const name = names(options.name).fileName; + const projectDirectory = options.directory + ? `${names(options.directory).fileName}/${name}` + : name; + + if (!options.unitTestRunner && options.config !== 'npm-scripts') { + options.unitTestRunner = 'jest'; + } + + if (!options.linter && options.config !== 'npm-scripts') { + options.linter = Linter.EsLint; + } + + const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); + const fileName = getCaseAwareFileName({ + fileName: options.simpleModuleName ? name : projectName, + pascalCaseFiles: options.pascalCaseFiles, + }); + + const { npmScope } = getWorkspaceLayout(tree); + + const projectRoot = joinPathFragments(destinationDir, projectDirectory); + + const parsedTags = options.tags + ? options.tags.split(',').map((s) => s.trim()) + : []; + + const defaultImportPath = `@${npmScope}/${projectDirectory}`; + const importPath = options.importPath || defaultImportPath; + + return { + ...options, + fileName, + name: projectName, + projectRoot, + projectDirectory, + parsedTags, + importPath, + }; +} + +function getCaseAwareFileName(options: { + pascalCaseFiles: boolean; + fileName: string; +}) { + const normalized = names(options.fileName); + + return options.pascalCaseFiles ? normalized.className : normalized.fileName; +} + +function updateRootTsConfig(host: Tree, options: NormalizedSchema) { + updateJson(host, 'tsconfig.base.json', (json) => { + const c = json.compilerOptions; + c.paths = c.paths || {}; + delete c.paths[options.name]; + + if (c.paths[options.importPath]) { + throw new Error( + `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` + ); + } + + c.paths[options.importPath] = [ + joinPathFragments( + options.projectRoot, + './src', + 'index.' + (options.js ? 'js' : 'ts') + ), + ]; + + return json; + }); } export default libraryGenerator; diff --git a/packages/js/src/index.ts b/packages/js/src/index.ts index 4f6a2d4ae3c84..a766533e9987f 100644 --- a/packages/js/src/index.ts +++ b/packages/js/src/index.ts @@ -1,4 +1,3 @@ export * from './utils/typescript/print-diagnostics'; export * from './utils/typescript/run-type-check'; export { libraryGenerator } from './generators/library/library'; -export { applicationGenerator } from './generators/application/application'; diff --git a/packages/js/src/migrations/update-13-9-0/update-node-executor.spec.ts b/packages/js/src/migrations/update-13-9-0/update-node-executor.spec.ts new file mode 100644 index 0000000000000..4461a2272db5d --- /dev/null +++ b/packages/js/src/migrations/update-13-9-0/update-node-executor.spec.ts @@ -0,0 +1,66 @@ +import { readJson } from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + +import update from './update-node-executor'; + +describe('Migration: rename execute to node', () => { + it(`should rename the "execute" executor to "node"`, async () => { + let tree = createTreeWithEmptyWorkspace(); + + tree.write( + 'workspace.json', + JSON.stringify({ + version: 2, + projects: { + myapp: { + root: 'apps/myapp', + sourceRoot: 'apps/myapp/src', + projectType: 'application', + targets: { + serve: { + executor: '@nrwl/js:node', + options: {}, + }, + }, + }, + }, + }) + ); + + const tasks = await update(tree); + + expect(tasks).toBeDefined(); + expect(readJson(tree, 'workspace.json')).toEqual({ + version: 2, + projects: { + myapp: { + root: 'apps/myapp', + sourceRoot: 'apps/myapp/src', + projectType: 'application', + targets: { + serve: { + executor: '@nrwl/node:node', + options: {}, + }, + }, + }, + }, + }); + }); + + it(`should skip migration if no projects use @nrwl/js:node`, async () => { + let tree = createTreeWithEmptyWorkspace(); + + tree.write( + 'workspace.json', + JSON.stringify({ + version: 2, + projects: {}, + }) + ); + + const tasks = await update(tree); + + expect(tasks).toBeUndefined(); + }); +}); diff --git a/packages/js/src/migrations/update-13-9-0/update-node-executor.ts b/packages/js/src/migrations/update-13-9-0/update-node-executor.ts new file mode 100644 index 0000000000000..e4150465af759 --- /dev/null +++ b/packages/js/src/migrations/update-13-9-0/update-node-executor.ts @@ -0,0 +1,36 @@ +import { + addDependenciesToPackageJson, + formatFiles, + getProjects, + Tree, + updateProjectConfiguration, +} from '@nrwl/devkit'; +import { nxVersion } from '@nrwl/workspace/src/utils/versions'; + +export default async function update(host: Tree) { + const projects = getProjects(host); + let installNeeded = false; + + for (const [name, config] of projects.entries()) { + if (config?.targets?.serve?.executor !== '@nrwl/js:node') continue; + + config.targets.serve.executor = '@nrwl/node:node'; + + installNeeded = true; + updateProjectConfiguration(host, name, config); + } + + const task = installNeeded + ? addDependenciesToPackageJson( + host, + {}, + { + '@nrwl/node': nxVersion, + } + ) + : undefined; + + await formatFiles(host); + + return task; +} diff --git a/packages/js/src/utils/project-generator.ts b/packages/js/src/utils/project-generator.ts deleted file mode 100644 index 23a596cbe5f22..0000000000000 --- a/packages/js/src/utils/project-generator.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { - addProjectConfiguration, - formatFiles, - generateFiles, - GeneratorCallback, - getWorkspaceLayout, - joinPathFragments, - names, - offsetFromRoot, - ProjectConfiguration, - toJS, - Tree, - updateJson, -} from '@nrwl/devkit'; -import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; -import { join } from 'path'; -import { GeneratorSchema } from './schema'; -import { addSwcConfig } from './swc/add-swc-config'; -import { addSwcDependencies } from './swc/add-swc-dependencies'; - -// nx-ignore-next-line -const { jestProjectGenerator } = require('@nrwl/jest'); -// nx-ignore-next-line -const { lintProjectGenerator, Linter } = require('@nrwl/linter'); - -export async function projectGenerator( - tree: Tree, - schema: GeneratorSchema, - destinationDir: string, - filesDir: string, - projectType: 'library' | 'application' -) { - const options = normalizeOptions(tree, schema, destinationDir); - - createFiles(tree, options, filesDir); - - addProject(tree, options, destinationDir, projectType); - - if (!schema.skipTsConfig) { - updateRootTsConfig(tree, options); - } - - const tasks: GeneratorCallback[] = []; - - if (options.linter !== 'none') { - const lintCallback = await addLint(tree, options); - tasks.push(lintCallback); - } - if (options.unitTestRunner === 'jest') { - const jestCallback = await addJest(tree, options); - tasks.push(jestCallback); - } - - if (!options.skipFormat) { - await formatFiles(tree); - } - - return runTasksInSerial(...tasks); -} - -export interface NormalizedSchema extends GeneratorSchema { - name: string; - fileName: string; - projectRoot: string; - projectDirectory: string; - parsedTags: string[]; - importPath?: string; -} - -function addProject( - tree: Tree, - options: NormalizedSchema, - destinationDir: string, - projectType: 'library' | 'application' -) { - const projectConfiguration: ProjectConfiguration = { - root: options.projectRoot, - sourceRoot: joinPathFragments(options.projectRoot, 'src'), - projectType: projectType, - targets: {}, - tags: options.parsedTags, - }; - - if (options.buildable && options.config != 'npm-scripts') { - projectConfiguration.targets.build = { - executor: `@nrwl/js:${options.compiler}`, - outputs: ['{options.outputPath}'], - options: { - outputPath: `dist/${destinationDir}/${options.projectDirectory}`, - main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'), - tsConfig: `${options.projectRoot}/${ - projectType === 'library' ? 'tsconfig.lib.json' : 'tsconfig.app.json' - }`, - assets: [`${options.projectRoot}/*.md`], - }, - }; - - if (options.compiler === 'swc' && options.skipTypeCheck) { - projectConfiguration.targets.build.options.skipTypeCheck = true; - } - - if (projectType === 'application') { - projectConfiguration.targets.serve = { - executor: `@nrwl/js:node`, - options: { - buildTarget: `${options.name}:build`, - }, - }; - } - } - - if (options.config === 'workspace') { - addProjectConfiguration(tree, options.name, projectConfiguration, false); - } else if (options.config === 'project') { - addProjectConfiguration(tree, options.name, projectConfiguration, true); - } else { - addProjectConfiguration( - tree, - options.name, - { - root: projectConfiguration.root, - tags: projectConfiguration.tags, - }, - true - ); - } -} - -export function addLint( - tree: Tree, - options: NormalizedSchema -): Promise { - return lintProjectGenerator(tree, { - project: options.name, - linter: options.linter, - skipFormat: true, - tsConfigPaths: [ - joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), - ], - eslintFilePatterns: [ - `${options.projectRoot}/**/*.${options.js ? 'js' : 'ts'}`, - ], - setParserOptionsProject: options.setParserOptionsProject, - }); -} - -function updateTsConfig(tree: Tree, options: NormalizedSchema) { - updateJson(tree, join(options.projectRoot, 'tsconfig.json'), (json) => { - if (options.strict) { - json.compilerOptions = { - ...json.compilerOptions, - forceConsistentCasingInFileNames: true, - strict: true, - noImplicitOverride: true, - noPropertyAccessFromIndexSignature: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }; - } - - return json; - }); -} - -function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) { - const { className, name, propertyName } = names(options.name); - - generateFiles(tree, filesDir, options.projectRoot, { - ...options, - dot: '.', - className, - name, - propertyName, - js: !!options.js, - cliCommand: 'nx', - strict: undefined, - tmpl: '', - offsetFromRoot: offsetFromRoot(options.projectRoot), - buildable: options.buildable === true, - hasUnitTestRunner: options.unitTestRunner !== 'none', - }); - - if (options.buildable && options.compiler === 'swc') { - addSwcDependencies(tree); - addSwcConfig(tree, options.projectRoot); - } - - if (options.unitTestRunner === 'none') { - tree.delete( - join(options.projectRoot, 'src/lib', `${options.fileName}.spec.ts`) - ); - tree.delete( - join(options.projectRoot, 'src/app', `${options.fileName}.spec.ts`) - ); - } - - if (options.js) { - toJS(tree); - } - - const packageJsonPath = join(options.projectRoot, 'package.json'); - if (options.config === 'npm-scripts') { - updateJson(tree, packageJsonPath, (json) => { - json.scripts = { - build: "echo 'implement build'", - test: "echo 'implement test'", - }; - return json; - }); - } else if (!options.buildable) { - tree.delete(packageJsonPath); - } - - updateTsConfig(tree, options); -} - -async function addJest( - tree: Tree, - options: NormalizedSchema -): Promise { - return await jestProjectGenerator(tree, { - project: options.name, - setupFile: 'none', - supportTsx: false, - skipSerializers: true, - testEnvironment: options.testEnvironment, - skipFormat: true, - compiler: options.compiler, - }); -} - -function normalizeOptions( - tree: Tree, - options: GeneratorSchema, - destinationDir: string -): NormalizedSchema { - if (options.config === 'npm-scripts') { - options.unitTestRunner = 'none'; - options.linter = Linter.None; - options.buildable = false; - } - - if (options.compiler === 'swc' && options.skipTypeCheck == null) { - options.skipTypeCheck = false; - } - - const name = names(options.name).fileName; - const projectDirectory = options.directory - ? `${names(options.directory).fileName}/${name}` - : name; - - if (!options.unitTestRunner && options.config !== 'npm-scripts') { - options.unitTestRunner = 'jest'; - } - - if (!options.linter && options.config !== 'npm-scripts') { - options.linter = Linter.EsLint; - } - - const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); - const fileName = getCaseAwareFileName({ - fileName: options.simpleModuleName ? name : projectName, - pascalCaseFiles: options.pascalCaseFiles, - }); - - const { npmScope } = getWorkspaceLayout(tree); - - const projectRoot = joinPathFragments(destinationDir, projectDirectory); - - const parsedTags = options.tags - ? options.tags.split(',').map((s) => s.trim()) - : []; - - const defaultImportPath = `@${npmScope}/${projectDirectory}`; - const importPath = options.importPath || defaultImportPath; - - return { - ...options, - fileName, - name: projectName, - projectRoot, - projectDirectory, - parsedTags, - importPath, - }; -} - -function getCaseAwareFileName(options: { - pascalCaseFiles: boolean; - fileName: string; -}) { - const normalized = names(options.fileName); - - return options.pascalCaseFiles ? normalized.className : normalized.fileName; -} - -function updateRootTsConfig(host: Tree, options: NormalizedSchema) { - updateJson(host, 'tsconfig.base.json', (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - c.paths[options.importPath] = [ - joinPathFragments( - options.projectRoot, - './src', - 'index.' + (options.js ? 'js' : 'ts') - ), - ]; - - return json; - }); -} diff --git a/packages/js/src/utils/schema.d.ts b/packages/js/src/utils/schema.d.ts index 3fa8af2dbb0ef..e07eccf1ba26b 100644 --- a/packages/js/src/utils/schema.d.ts +++ b/packages/js/src/utils/schema.d.ts @@ -64,8 +64,3 @@ export interface NormalizedSwcExecutorOptions skipTypeCheck: boolean; swcCliOptions: SwcCliOptions; } - -export interface ExecutorEvent { - outfile: string; - success: boolean; -} diff --git a/packages/linter/src/generators/lint-project/lint-project.ts b/packages/linter/src/generators/lint-project/lint-project.ts index 85075ae2df8c4..645d44a9bb082 100644 --- a/packages/linter/src/generators/lint-project/lint-project.ts +++ b/packages/linter/src/generators/lint-project/lint-project.ts @@ -1,11 +1,11 @@ +import type { ProjectConfiguration, Tree } from '@nrwl/devkit'; import { - writeJson, - updateProjectConfiguration, + formatFiles, offsetFromRoot, readProjectConfiguration, - formatFiles, + updateProjectConfiguration, + writeJson, } from '@nrwl/devkit'; -import type { ProjectConfiguration, Tree } from '@nrwl/devkit'; import { join } from 'path'; import { Linter } from '../utils/linter'; import { lintInitGenerator } from '../init/init'; diff --git a/packages/nest/src/generators/library/lib/add-project.ts b/packages/nest/src/generators/library/lib/add-project.ts index 16e1db706e428..ca0d1df885cca 100644 --- a/packages/nest/src/generators/library/lib/add-project.ts +++ b/packages/nest/src/generators/library/lib/add-project.ts @@ -13,7 +13,7 @@ export function addProject(tree: Tree, options: NormalizedOptions): void { const project = readProjectConfiguration(tree, options.projectName); project.targets.build = { - executor: '@nrwl/node:package', + executor: '@nrwl/js:tsc', outputs: ['{options.outputPath}'], options: { outputPath: `dist/${getWorkspaceLayout(tree).libsDir}/${ diff --git a/packages/node/executors.json b/packages/node/executors.json index dfe5ae581bdfe..6afcad152749b 100644 --- a/packages/node/executors.json +++ b/packages/node/executors.json @@ -1,36 +1,26 @@ { "executors": { - "build": { - "implementation": "./src/executors/build/build.impl", - "schema": "./src/executors/build/schema.json", - "description": "Build a Node application" + "webpack": { + "implementation": "./src/executors/webpack/webpack.impl", + "schema": "./src/executors/webpack/schema.json", + "description": "Build a Node application using webpack" }, - "execute": { - "implementation": "./src/executors/execute/execute.impl", - "schema": "./src/executors/execute/schema.json", + "node": { + "implementation": "./src/executors/node/node.impl", + "schema": "./src/executors/node/schema.json", "description": "Execute a Node application" - }, - "package": { - "implementation": "./src/executors/package/package.impl", - "schema": "./src/executors/package/schema.json", - "description": "Package a Node library" } }, "builders": { - "build": { - "implementation": "./src/executors/build/compat", - "schema": "./src/executors/build/schema.json", - "description": "Build a Node application" + "webpack": { + "implementation": "./src/executors/webpack/compat", + "schema": "./src/executors/webpack/schema.json", + "description": "Build a Node application using webpack" }, - "execute": { - "implementation": "./src/executors/execute/compat", - "schema": "./src/executors/execute/schema.json", + "node": { + "implementation": "./src/executors/node/compat", + "schema": "./src/executors/node/schema.json", "description": "Execute a Node application" - }, - "package": { - "implementation": "./src/executors/package/compat", - "schema": "./src/executors/package/schema.json", - "description": "Package a Node library" } } } diff --git a/packages/node/migrations.json b/packages/node/migrations.json index a72f6080f1753..185f150c724c5 100644 --- a/packages/node/migrations.json +++ b/packages/node/migrations.json @@ -15,6 +15,24 @@ "version": "13.0.0-beta.1", "description": "Remove packages installed by Nx 12's `@nrwl/node:webpack5` generator.", "factory": "./src/migrations/update-13-0-0/remove-webpack-5-packages-13-0-0" + }, + "rename-build-to-webpack": { + "cli": "nx", + "version": "13.9.0-beta.1", + "description": "Renames @nrwl/node:build to @nrwl/node:webpack", + "factory": "./src/migrations/update-13-9-0/rename-build-to-webpack" + }, + "rename-execute-to-node": { + "cli": "nx", + "version": "13.9.0-beta.1", + "description": "Renames @nrwl/node:execute to @nrwl/node:node", + "factory": "./src/migrations/update-13-9-0/rename-execute-to-node" + }, + "update-package-to-tsc": { + "cli": "nx", + "version": "13.9.0-beta.1", + "description": "Renames @nrwl/node:package to @nrwl/js:tsc", + "factory": "./src/migrations/update-13-9-0/update-package-to-tsc" } } } diff --git a/packages/node/package.json b/packages/node/package.json index 2225b4c679386..6ad82fbc586d2 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -33,6 +33,7 @@ "@nrwl/workspace": "*", "@nrwl/devkit": "*", "@nrwl/jest": "*", + "@nrwl/js": "*", "@nrwl/linter": "*", "chalk": "4.1.0", "copy-webpack-plugin": "^9.0.1", diff --git a/packages/node/src/executors/build/compat.ts b/packages/node/src/executors/build/compat.ts deleted file mode 100644 index 31cdeffe6b1de..0000000000000 --- a/packages/node/src/executors/build/compat.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { convertNxExecutor } from '@nrwl/devkit'; - -import { buildExecutor } from './build.impl'; - -export default convertNxExecutor(buildExecutor); diff --git a/packages/node/src/executors/execute/compat.ts b/packages/node/src/executors/execute/compat.ts deleted file mode 100644 index c3fb5f3b978de..0000000000000 --- a/packages/node/src/executors/execute/compat.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { convertNxExecutor } from '@nrwl/devkit'; - -import { executeExecutor } from './execute.impl'; - -export default convertNxExecutor(executeExecutor); diff --git a/packages/node/src/executors/execute/execute.impl.spec.ts b/packages/node/src/executors/execute/execute.impl.spec.ts deleted file mode 100644 index cb27fbdef8c38..0000000000000 --- a/packages/node/src/executors/execute/execute.impl.spec.ts +++ /dev/null @@ -1,335 +0,0 @@ -let buildOptions; - -jest.mock('@nrwl/devkit'); - -const devkit = require('@nrwl/devkit'); -import { ExecutorContext, logger } from '@nrwl/devkit'; - -jest.mock('child_process'); -let { fork } = require('child_process'); -jest.mock('tree-kill'); -let treeKill = require('tree-kill'); - -import { - executeExecutor, - InspectType, - NodeExecuteBuilderOptions, -} from './execute.impl'; - -describe('NodeExecuteBuilder', () => { - let testOptions: NodeExecuteBuilderOptions; - let context: ExecutorContext; - - beforeEach(async () => { - buildOptions = {}; - - (devkit.runExecutor as any).mockImplementation(function* () { - yield { success: true, outfile: 'outfile.js' }; - }); - - (devkit.readTargetOptions as any).mockImplementation(() => buildOptions); - - (devkit.parseTargetString as any).mockImplementation( - jest.requireActual('@nrwl/devkit').parseTargetString - ); - - fork.mockImplementation(() => { - return { - on: (eventName, cb) => { - if (eventName === 'exit') { - cb(); - } - }, - }; - }); - - treeKill.mockImplementation((pid, signal, callback) => { - callback(); - }); - context = { - root: '/root', - cwd: '/root', - workspace: { - version: 2, - projects: { - nodeapp: { - root: '/root/nodeapp', - targets: { - build: { - executor: 'build', - options: {}, - }, - }, - }, - }, - npmScope: 'test', - }, - isVerbose: false, - }; - testOptions = { - inspect: true, - args: [], - runtimeArgs: [], - buildTarget: 'nodeapp:build', - buildTargetOptions: { testOption: true }, - port: 9229, - waitUntilTargets: [], - host: 'localhost', - watch: true, - }; - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should build the application and start the built file', async () => { - for await (const event of executeExecutor(testOptions, context)) { - expect(event.success).toEqual(true); - } - expect(require('@nrwl/devkit').runExecutor).toHaveBeenCalledWith( - { - project: 'nodeapp', - target: 'build', - }, - { - testOption: true, - watch: true, - }, - context - ); - expect(fork).toHaveBeenCalledWith('outfile.js', [], { - execArgv: [ - '-r', - require.resolve('source-map-support/register'), - '--inspect=localhost:9229', - ], - }); - expect(treeKill).toHaveBeenCalledTimes(0); - expect(fork).toHaveBeenCalledTimes(1); - }); - - describe('--inspect', () => { - describe('inspect', () => { - it('should inspect the process', async () => { - for await (const event of executeExecutor( - { - ...testOptions, - inspect: InspectType.Inspect, - }, - context - )) { - } - expect(fork).toHaveBeenCalledWith('outfile.js', [], { - execArgv: [ - '-r', - require.resolve('source-map-support/register'), - '--inspect=localhost:9229', - ], - }); - }); - }); - - describe('inspect-brk', () => { - it('should inspect and break at beginning of execution', async () => { - for await (const event of executeExecutor( - { - ...testOptions, - inspect: InspectType.InspectBrk, - }, - context - )) { - } - expect(fork).toHaveBeenCalledWith('outfile.js', [], { - execArgv: [ - '-r', - require.resolve('source-map-support/register'), - '--inspect-brk=localhost:9229', - ], - }); - }); - }); - }); - - describe('--host', () => { - describe('0.0.0.0', () => { - it('should inspect the process on host 0.0.0.0', async () => { - for await (const event of executeExecutor( - { - ...testOptions, - host: '0.0.0.0', - }, - context - )) { - } - expect(fork).toHaveBeenCalledWith('outfile.js', [], { - execArgv: [ - '-r', - require.resolve('source-map-support/register'), - '--inspect=0.0.0.0:9229', - ], - }); - }); - }); - }); - - describe('--port', () => { - describe('1234', () => { - it('should inspect the process on port 1234', async () => { - for await (const event of executeExecutor( - { - ...testOptions, - port: 1234, - }, - context - )) { - } - expect(fork).toHaveBeenCalledWith('outfile.js', [], { - execArgv: [ - '-r', - require.resolve('source-map-support/register'), - '--inspect=localhost:1234', - ], - }); - }); - }); - }); - - describe('--runtimeArgs', () => { - it('should add runtime args to the node process', async () => { - for await (const event of executeExecutor( - { - ...testOptions, - runtimeArgs: ['-r', 'node-register'], - }, - context - )) { - } - expect(fork).toHaveBeenCalledWith('outfile.js', [], { - execArgv: [ - '-r', - require.resolve('source-map-support/register'), - '-r', - 'node-register', - '--inspect=localhost:9229', - ], - }); - }); - }); - - it('should log errors from killing the process', async () => { - treeKill.mockImplementation((pid, signal, callback) => { - callback(new Error('Error Message')); - }); - - const loggerError = jest.spyOn(logger, 'error'); - - for await (const event of executeExecutor(testOptions, context)) { - } - expect(loggerError).toHaveBeenCalledWith('Error Message'); - }); - - it('should log errors from killing the process on windows', async () => { - treeKill.mockImplementation((pid, signal, callback) => { - callback([new Error('error'), '', 'Error Message']); - }); - - const loggerError = jest.spyOn(logger, 'error'); - - for await (const event of executeExecutor( - { - ...testOptions, - runtimeArgs: ['-r', 'node-register'], - }, - context - )) { - } - expect(loggerError).toHaveBeenLastCalledWith('Error Message'); - }); - - it('should build the application and start the built file with options', async () => { - for await (const event of executeExecutor( - { - ...testOptions, - inspect: false, - args: ['arg1', 'arg2'], - }, - context - )) { - } - expect(fork).toHaveBeenCalledWith('outfile.js', ['arg1', 'arg2'], { - execArgv: ['-r', require.resolve('source-map-support/register')], - }); - }); - - it('should warn users who try to use it in production', async () => { - buildOptions = { - optimization: true, - }; - const loggerWarn = jest.spyOn(logger, 'warn'); - for await (const event of executeExecutor( - { - ...testOptions, - inspect: false, - args: ['arg1', 'arg2'], - }, - context - )) { - } - expect(loggerWarn).toHaveBeenCalled(); - }); - - describe('waitUntilTasks', () => { - it('should run the tasks before starting the build', async () => { - const runExecutor = require('@nrwl/devkit').runExecutor; - for await (const event of executeExecutor( - { - ...testOptions, - waitUntilTargets: ['project1:target1', 'project2:target2'], - }, - context - )) { - } - - expect(runExecutor).toHaveBeenCalledTimes(3); - expect(runExecutor).toHaveBeenNthCalledWith( - 1, - { - project: 'project1', - target: 'target1', - }, - {}, - context - ); - expect(runExecutor).toHaveBeenCalledWith( - { - project: 'project2', - target: 'target2', - }, - {}, - context - ); - }); - - it('should not run the build if any of the tasks fail', async () => { - devkit.runExecutor.mockImplementation(function* () { - yield { success: false }; - }); - - try { - for await (const event of executeExecutor( - { - ...testOptions, - waitUntilTargets: ['project1:target1', 'project2:target2'], - }, - context - )) { - } - } catch (e) { - expect(e.message).toMatchInlineSnapshot( - `"Wait until target failed: project1:target1."` - ); - } - }); - }); -}); diff --git a/packages/node/src/executors/execute/execute.impl.ts b/packages/node/src/executors/execute/execute.impl.ts deleted file mode 100644 index 7944857e5a1df..0000000000000 --- a/packages/node/src/executors/execute/execute.impl.ts +++ /dev/null @@ -1,182 +0,0 @@ -import 'dotenv/config'; -import { - runExecutor, - stripIndents, - parseTargetString, - ExecutorContext, - logger, - readTargetOptions, -} from '@nrwl/devkit'; - -import { ChildProcess, fork } from 'child_process'; -import { promisify } from 'util'; -import * as treeKill from 'tree-kill'; - -import { NodeBuildEvent } from '../build/build.impl'; -import { BuildNodeBuilderOptions } from '../../utils/types'; - -export const enum InspectType { - Inspect = 'inspect', - InspectBrk = 'inspect-brk', -} - -export interface NodeExecuteBuilderOptions { - inspect: boolean | InspectType; - runtimeArgs: string[]; - args: string[]; - waitUntilTargets: string[]; - buildTarget: string; - buildTargetOptions: Record; - host: string; - port: number; - watch: boolean; -} - -let subProcess: ChildProcess = null; - -export async function* executeExecutor( - options: NodeExecuteBuilderOptions, - context: ExecutorContext -) { - process.on('SIGTERM', () => { - subProcess?.kill(); - process.exit(128 + 15); - }); - process.on('exit', (code) => { - process.exit(code); - }); - - if (options.waitUntilTargets && options.waitUntilTargets.length > 0) { - const results = await runWaitUntilTargets(options, context); - for (const [i, result] of results.entries()) { - if (!result.success) { - console.log('throw'); - throw new Error( - `Wait until target failed: ${options.waitUntilTargets[i]}.` - ); - } - } - } - - for await (const event of startBuild(options, context)) { - if (!event.success) { - logger.error('There was an error with the build. See above.'); - logger.info(`${event.outfile} was not restarted.`); - } - await handleBuildEvent(event, options); - yield event; - } -} - -function runProcess(event: NodeBuildEvent, options: NodeExecuteBuilderOptions) { - if (subProcess || !event.success) { - return; - } - - subProcess = fork(event.outfile, options.args, { - execArgv: getExecArgv(options), - }); -} - -function getExecArgv(options: NodeExecuteBuilderOptions) { - const args = [ - '-r', - require.resolve('source-map-support/register'), - ...options.runtimeArgs, - ]; - - if (options.inspect === true) { - options.inspect = InspectType.Inspect; - } - - if (options.inspect) { - args.push(`--${options.inspect}=${options.host}:${options.port}`); - } - - return args; -} - -async function handleBuildEvent( - event: NodeBuildEvent, - options: NodeExecuteBuilderOptions -) { - if ((!event.success || options.watch) && subProcess) { - await killProcess(); - } - runProcess(event, options); -} - -async function killProcess() { - if (!subProcess) { - return; - } - - const promisifiedTreeKill: (pid: number, signal: string) => Promise = - promisify(treeKill); - try { - await promisifiedTreeKill(subProcess.pid, 'SIGTERM'); - } catch (err) { - if (Array.isArray(err) && err[0] && err[2]) { - const errorMessage = err[2]; - logger.error(errorMessage); - } else if (err.message) { - logger.error(err.message); - } - } finally { - subProcess = null; - } -} - -async function* startBuild( - options: NodeExecuteBuilderOptions, - context: ExecutorContext -) { - const buildTarget = parseTargetString(options.buildTarget); - const buildOptions = readTargetOptions( - buildTarget, - context - ); - if (buildOptions.optimization) { - logger.warn(stripIndents` - ************************************************ - This is a simple process manager for use in - testing or debugging Node applications locally. - DO NOT USE IT FOR PRODUCTION! - You should look into proper means of deploying - your node application to production. - ************************************************`); - } - - yield* await runExecutor( - buildTarget, - { - ...options.buildTargetOptions, - watch: options.watch, - }, - context - ); -} - -function runWaitUntilTargets( - options: NodeExecuteBuilderOptions, - context: ExecutorContext -): Promise<{ success: boolean }[]> { - return Promise.all( - options.waitUntilTargets.map(async (waitUntilTarget) => { - const target = parseTargetString(waitUntilTarget); - const output = await runExecutor(target, {}, context); - return new Promise<{ success: boolean }>(async (resolve) => { - let event = await output.next(); - // Resolve after first event - resolve(event.value as { success: boolean }); - - // Continue iterating - while (!event.done) { - event = await output.next(); - } - }); - }) - ); -} - -export default executeExecutor; diff --git a/packages/node/src/executors/execute/schema.json b/packages/node/src/executors/execute/schema.json deleted file mode 100644 index c414d4e466fc4..0000000000000 --- a/packages/node/src/executors/execute/schema.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "title": "Schema for Executing NodeJS apps", - "description": "NodeJS execution options", - "cli": "nx", - "type": "object", - "properties": { - "buildTarget": { - "type": "string", - "description": "The target to run to build you the app" - }, - "buildTargetOptions": { - "type": "object", - "description": "Additional options to pass into the build target.", - "default": {} - }, - "waitUntilTargets": { - "type": "array", - "description": "The targets to run to before starting the node app", - "default": [], - "items": { - "type": "string" - } - }, - "host": { - "type": "string", - "default": "localhost", - "description": "The host to inspect the process on" - }, - "port": { - "type": "number", - "default": 9229, - "description": "The port to inspect the process on. Setting port to 0 will assign random free ports to all forked processes." - }, - "watch": { - "type": "boolean", - "description": "Run build when files change", - "default": true - }, - "inspect": { - "oneOf": [ - { - "type": "string", - "enum": ["inspect", "inspect-brk"] - }, - { - "type": "boolean" - } - ], - "description": "Ensures the app is starting with debugging", - "default": "inspect" - }, - "runtimeArgs": { - "type": "array", - "description": "Extra args passed to the node process", - "default": [], - "items": { - "type": "string" - } - }, - "args": { - "type": "array", - "description": "Extra args when starting the app", - "default": [], - "items": { - "type": "string" - } - } - }, - "additionalProperties": false, - "required": ["buildTarget"] -} diff --git a/packages/js/src/executors/node/compat.ts b/packages/node/src/executors/node/compat.ts similarity index 100% rename from packages/js/src/executors/node/compat.ts rename to packages/node/src/executors/node/compat.ts diff --git a/packages/js/src/executors/node/node-with-require-overrides.ts b/packages/node/src/executors/node/node-with-require-overrides.ts similarity index 100% rename from packages/js/src/executors/node/node-with-require-overrides.ts rename to packages/node/src/executors/node/node-with-require-overrides.ts diff --git a/packages/js/src/executors/node/node.impl.ts b/packages/node/src/executors/node/node.impl.ts similarity index 98% rename from packages/js/src/executors/node/node.impl.ts rename to packages/node/src/executors/node/node.impl.ts index ed854a75eba07..729d00a9a5ae6 100644 --- a/packages/js/src/executors/node/node.impl.ts +++ b/packages/node/src/executors/node/node.impl.ts @@ -8,13 +8,17 @@ import { import { ChildProcess, fork } from 'child_process'; import * as treeKill from 'tree-kill'; import { promisify } from 'util'; -import { ExecutorEvent } from '../../utils/schema'; import { InspectType, NodeExecutorOptions } from './schema'; import { readCachedProjectGraph } from '@nrwl/workspace/src/core/project-graph'; import { calculateProjectDependencies } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; let subProcess: ChildProcess = null; +export interface ExecutorEvent { + outfile: string; + success: boolean; +} + export async function* nodeExecutor( options: NodeExecutorOptions, context: ExecutorContext diff --git a/packages/js/src/executors/node/schema.d.ts b/packages/node/src/executors/node/schema.d.ts similarity index 100% rename from packages/js/src/executors/node/schema.d.ts rename to packages/node/src/executors/node/schema.d.ts diff --git a/packages/js/src/executors/node/schema.json b/packages/node/src/executors/node/schema.json similarity index 100% rename from packages/js/src/executors/node/schema.json rename to packages/node/src/executors/node/schema.json diff --git a/packages/node/src/executors/package/compat.ts b/packages/node/src/executors/package/compat.ts deleted file mode 100644 index 50966de81d508..0000000000000 --- a/packages/node/src/executors/package/compat.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { convertNxExecutor } from '@nrwl/devkit'; - -import { packageExecutor } from './package.impl'; - -export default convertNxExecutor(packageExecutor); diff --git a/packages/node/src/executors/package/package.impl.spec.ts b/packages/node/src/executors/package/package.impl.spec.ts deleted file mode 100644 index e60cd07e12c23..0000000000000 --- a/packages/node/src/executors/package/package.impl.spec.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { ExecutorContext } from '@nrwl/devkit'; -import { join } from 'path'; -import { mocked } from 'ts-jest/utils'; - -jest.mock('@nrwl/workspace/src/core/project-graph'); -import * as projectGraph from '@nrwl/workspace/src/core/project-graph'; -import { - ProjectGraph, - ProjectType, -} from '@nrwl/workspace/src/core/project-graph'; - -import { packageExecutor } from './package.impl'; -import { NodePackageBuilderOptions } from './utils/models'; - -jest.mock('glob'); -import * as glob from 'glob'; - -jest.mock('fs-extra'); -import * as fs from 'fs-extra'; - -jest.mock('@nrwl/workspace/src/utilities/fileutils'); -import * as fsUtility from '@nrwl/workspace/src/utilities/fileutils'; -import * as devkit from '@nrwl/devkit'; -jest.mock('@nrwl/devkit', () => ({ - ...jest.requireActual('@nrwl/devkit'), - writeJsonFile: jest.fn(), - readJsonFile: jest.fn(), -})); - -import * as tsUtils from '@nrwl/workspace/src/utilities/typescript'; -import * as ts from 'typescript'; - -describe('NodePackageBuilder', () => { - let testOptions: NodePackageBuilderOptions; - let context: ExecutorContext; - - beforeEach(async () => { - mocked(devkit.readJsonFile).mockImplementation((path: string) => { - if (path.endsWith('tsconfig.lib.json')) { - return { - extends: './tsconfig.json', - compilerOptions: { - outDir: '../../dist/out-tsc', - declaration: true, - rootDir: './src', - types: ['node'], - }, - exclude: ['**/*.spec.ts'], - include: ['**/*.ts'], - }; - } else { - return { - name: 'nodelib', - }; - } - }); - mocked(devkit.writeJsonFile).mockImplementation( - (_: string, _2: unknown) => { - //empty - return; - } - ); - mocked(fs.existsSync).mockImplementation( - (path: string) => path === 'libs/nodelib/src/index.ts' - ); - context = { - root: '/root', - cwd: '/root', - - projectName: 'nodelib', - targetName: 'build', - workspace: { - version: 2, - projects: { - nodelib: { - root: 'libs/nodelib', - sourceRoot: 'libs/nodelib/src', - targets: {}, - }, - }, - npmScope: 'test', - }, - isVerbose: false, - }; - testOptions = { - assets: [], - main: 'libs/nodelib/src/index.ts', - outputPath: 'dist/libs/nodelib', - packageJson: 'libs/nodelib/package.json', - tsConfig: 'libs/nodelib/tsconfig.lib.json', - watch: false, - sourceMap: false, - deleteOutputPath: true, - }; - }); - - describe('Without library dependencies', () => { - beforeEach(() => { - jest - .spyOn(projectGraph, 'readCachedProjectGraph') - .mockImplementation(() => { - return { - nodes: { - nodelib: { - type: ProjectType.lib, - name: 'nodelib', - data: { - files: [], - root: 'libs/nodelib', - targets: { build: { executor: 'any builder' } }, - }, - }, - 'nodelib-child': { - type: ProjectType.lib, - name: 'nodelib-child', - data: { - files: [], - root: 'libs/nodelib-child', - prefix: 'proj', - targets: { - build: { - executor: 'any builder', - options: { - assets: [], - main: 'libs/nodelib-child/src/index.ts', - outputPath: 'dist/libs/nodelib-child', - packageJson: 'libs/nodelib-child/package.json', - tsConfig: 'libs/nodelib-child/tsconfig.lib.json', - }, - }, - }, - }, - }, - }, - dependencies: { - nodelib: [], - 'nodelib-child': [], - }, - } as ProjectGraph; - }); - }); - - it('should update the package.json after compiling typescript', async () => { - await packageExecutor(testOptions, context); - expect(devkit.writeJsonFile).toHaveBeenCalledWith( - `${testOptions.outputPath}/package.json`, - { - name: 'nodelib', - main: './src/index.js', - typings: './src/index.d.ts', - } - ); - }); - - it('should throw an error if `main` entry point does not exist', async () => { - await expect( - packageExecutor({ ...testOptions, main: 'does/not/exist.ts' }, context) - ).rejects.toThrow( - `Please verify that the "main" option for project "nodelib" is valid.` - ); - }); - - it('should have the output path in the BuilderOutput', async () => { - const result = await packageExecutor(testOptions, context); - - expect(result.outputPath).toEqual(testOptions.outputPath); - }); - - describe('Asset copying', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should be able to copy assets using the glob object', async () => { - mocked(glob.sync).mockReturnValue(['logo.png']); - await packageExecutor( - { - ...testOptions, - assets: [ - { - glob: '**.*', - input: 'lib/nodelib/src/assets', - output: './newfolder', - ignore: [], - }, - ], - }, - context - ); - expect(fs.copy).toHaveBeenCalledTimes(1); - expect(fs.copy).toHaveBeenCalledWith( - `${context.root}/lib/nodelib/src/assets/logo.png`, - `${context.root}/${testOptions.outputPath}/newfolder/logo.png` - ); - }); - it('should be able to copy assets with a regular string', async () => { - mocked(glob.sync).mockReturnValue(['lib/nodelib/src/LICENSE']); - - await packageExecutor( - { - ...testOptions, - assets: ['lib/nodelib/src/LICENSE'], - }, - context - ); - - expect(fs.copy).toHaveBeenCalledTimes(1); - expect(fs.copy).toHaveBeenCalledWith( - `${context.root}/lib/nodelib/src/LICENSE`, - `${context.root}/${testOptions.outputPath}/LICENSE` - ); - }); - - it('should be able to copy assets with a glob string', async () => { - mocked(glob.sync).mockReturnValue([ - 'lib/nodelib/src/README.md', - 'lib/nodelib/src/CONTRIBUTING.md', - ]); - await packageExecutor( - { - ...testOptions, - assets: ['lib/nodelib/src/*.MD'], - }, - context - ); - - expect(fs.copy).toHaveBeenCalledTimes(2); - expect(fs.copy).toHaveBeenCalledWith( - `${context.root}/lib/nodelib/src/README.md`, - `${context.root}/${testOptions.outputPath}/README.md` - ); - expect(fs.copy).toHaveBeenCalledWith( - `${context.root}/lib/nodelib/src/CONTRIBUTING.md`, - `${context.root}/${testOptions.outputPath}/CONTRIBUTING.md` - ); - }); - }); - - describe('srcRootForCompilationRoot', () => { - let spy: jest.SpyInstance; - beforeEach(() => { - jest.clearAllMocks(); - spy = jest.spyOn(ts, 'createCompilerHost'); - }); - - it('should use srcRootForCompilationRoot when it is defined', async () => { - testOptions.srcRootForCompilationRoot = 'libs/nodelib/src'; - - await packageExecutor(testOptions, context); - expect(spy).toHaveBeenCalledWith( - expect.objectContaining({ - rootDir: 'libs/nodelib/src', - }) - ); - }); - it('should not use srcRootForCompilationRoot when it is not defined', async () => { - testOptions.srcRootForCompilationRoot = undefined; - - await packageExecutor(testOptions, context); - - expect(spy).toHaveBeenCalledWith( - expect.objectContaining({ - rootDir: 'libs/nodelib', - }) - ); - }); - }); - }); - - describe('building with dependencies', () => { - beforeEach(() => { - // fake that dep project has been built - jest - .spyOn(projectGraph, 'readCachedProjectGraph') - .mockImplementation(() => { - return { - nodes: { - nodelib: { - type: ProjectType.lib, - name: 'nodelib', - data: { - files: [], - root: 'libs/nodelib', - targets: { build: { executor: 'any builder' } }, - }, - }, - 'nodelib-child': { - type: ProjectType.lib, - name: 'nodelib-child', - data: { - files: [], - root: 'libs/nodelib-child', - prefix: 'proj', - targets: { - build: { - executor: 'any builder', - options: { - assets: [], - main: 'libs/nodelib-child/src/index.ts', - outputPath: 'dist/libs/nodelib-child', - packageJson: 'libs/nodelib-child/package.json', - tsConfig: 'libs/nodelib-child/tsconfig.lib.json', - }, - }, - }, - }, - }, - }, - dependencies: { - nodelib: [ - { - type: ProjectType.lib, - target: 'nodelib-child', - source: null, - }, - ], - 'nodelib-child': [], - }, - } as ProjectGraph; - }); - // dist/libs/nodelib-child/package.json - mocked(fsUtility.directoryExists).mockImplementation((arg: string) => { - return arg.endsWith('dist/libs/nodelib-child'); - }); - }); - - it('should call the tsc compiler with the modified tsconfig.json', async () => { - const tmpTsConfigPath = join( - '/root', - 'tmp', - 'libs/nodelib', - 'tsconfig.generated.json' - ); - - const tsConfigSpy = jest.spyOn(tsUtils, 'readTsConfig'); - - await packageExecutor(testOptions, context); - expect(tsConfigSpy).toHaveBeenCalledWith(tmpTsConfigPath); - }); - }); -}); diff --git a/packages/node/src/executors/package/package.impl.ts b/packages/node/src/executors/package/package.impl.ts deleted file mode 100644 index 2ad7124dbfdab..0000000000000 --- a/packages/node/src/executors/package/package.impl.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { ExecutorContext } from '@nrwl/devkit'; -import { readCachedProjectGraph } from '@nrwl/workspace/src/core/project-graph'; -import { copyAssetFiles } from '@nrwl/workspace/src/utilities/assets'; -import { - calculateProjectDependencies, - checkDependentProjectsHaveBeenBuilt, - updateBuildableProjectPackageJsonDependencies, -} from '@nrwl/workspace/src/utilities/buildable-libs-utils'; -import { NodePackageBuilderOptions } from './utils/models'; -import compileTypeScriptFiles from './utils/compile-typescript-files'; -import updatePackageJson from './utils/update-package-json'; -import normalizeOptions from './utils/normalize-options'; -import addCliWrapper from './utils/cli'; - -export async function packageExecutor( - options: NodePackageBuilderOptions, - context: ExecutorContext -) { - const libRoot = context.workspace.projects[context.projectName].root; - const normalizedOptions = normalizeOptions(options, context, libRoot); - const { target, dependencies } = calculateProjectDependencies( - readCachedProjectGraph(), - context.root, - context.projectName, - context.targetName, - context.configurationName - ); - const dependentsBuilt = checkDependentProjectsHaveBeenBuilt( - context.root, - context.projectName, - context.targetName, - dependencies - ); - if (!dependentsBuilt) { - throw new Error(); - } - - const result = await compileTypeScriptFiles( - normalizedOptions, - context, - libRoot, - dependencies, - async () => - await updatePackageAndCopyAssets( - normalizedOptions, - context, - target, - dependencies - ) - ); - - if (options.cli) { - addCliWrapper(normalizedOptions, context); - } - - return { - ...(result as { success: boolean }), - outputPath: normalizedOptions.outputPath, - }; -} - -async function updatePackageAndCopyAssets( - options, - context, - target, - dependencies -) { - await copyAssetFiles(options.files); - - updatePackageJson(options, context); - if ( - dependencies.length > 0 && - options.updateBuildableProjectDepsInPackageJson - ) { - updateBuildableProjectPackageJsonDependencies( - context.root, - context.projectName, - context.targetName, - context.configurationName, - target, - dependencies, - options.buildableProjectDepsInPackageJsonType - ); - } -} - -export default packageExecutor; diff --git a/packages/node/src/executors/package/schema.json b/packages/node/src/executors/package/schema.json deleted file mode 100644 index 7bf46d287b98f..0000000000000 --- a/packages/node/src/executors/package/schema.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "title": "Node Library Package Target", - "description": "Packages a Node library using TypeScript", - "cli": "nx", - "type": "object", - "properties": { - "main": { - "type": "string", - "description": "The name of the main entry-point file." - }, - "tsConfig": { - "type": "string", - "description": "The name of the Typescript configuration file." - }, - "outputPath": { - "type": "string", - "description": "The output path of the generated files." - }, - "watch": { - "type": "boolean", - "description": "Enable re-building when files change.", - "default": false - }, - "sourceMap": { - "type": "boolean", - "description": "Output sourcemaps.", - "default": true - }, - "updateBuildableProjectDepsInPackageJson": { - "type": "boolean", - "description": "Update buildable project dependencies in package.json", - "default": true - }, - "buildableProjectDepsInPackageJsonType": { - "type": "string", - "description": "When updateBuildableProjectDepsInPackageJson is true, this adds dependencies to either `peerDependencies` or `dependencies`", - "enum": ["dependencies", "peerDependencies"], - "default": "dependencies" - }, - "assets": { - "type": "array", - "description": "List of static library assets.", - "default": [], - "items": { - "$ref": "#/definitions/assetPattern" - } - }, - "packageJson": { - "type": "string", - "description": "The name of the package.json file" - }, - "srcRootForCompilationRoot": { - "type": "string", - "description": "Sets the rootDir for TypeScript compilation. When not defined, it uses the project's root property" - }, - "deleteOutputPath": { - "type": "boolean", - "description": "Delete the output path before building.", - "default": true - }, - "cli": { - "type": "boolean", - "description": "Adds a CLI wrapper to main entry-point file." - }, - "tsPlugins": { - "type": "array", - "description": "List of TypeScript Compiler Plugins.", - "default": [], - "items": { - "$ref": "#/definitions/tsPluginPattern" - } - } - }, - "required": ["tsConfig", "main"], - - "definitions": { - "assetPattern": { - "oneOf": [ - { - "type": "object", - "properties": { - "glob": { - "type": "string", - "description": "The pattern to match." - }, - "input": { - "type": "string", - "description": "The input directory path in which to apply 'glob'. Defaults to the project root." - }, - "ignore": { - "description": "An array of globs to ignore.", - "type": "array", - "items": { - "type": "string" - } - }, - "output": { - "type": "string", - "description": "Absolute path within the output." - }, - "dot": { - "type": "boolean", - "description": "Whether or not files beginning with '.' should be included. Defaults to false", - "default": false - } - }, - "additionalProperties": false, - "required": ["glob", "input", "output"] - }, - { - "type": "string" - } - ] - }, - "tsPluginPattern": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "options": { - "type": "object", - "additionalProperties": true - } - }, - "additionalProperties": false, - "required": ["name"] - } - ] - } - } -} diff --git a/packages/node/src/executors/package/utils/cli.ts b/packages/node/src/executors/package/utils/cli.ts deleted file mode 100644 index ee35cb983393b..0000000000000 --- a/packages/node/src/executors/package/utils/cli.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { ExecutorContext } from '@nrwl/devkit'; -import { readJsonFile, writeJsonFile } from '@nrwl/devkit'; - -import { writeToFile } from '@nrwl/workspace/src/utilities/fileutils'; -import { chmodSync } from 'fs-extra'; -import { NormalizedBuilderOptions } from './models'; - -export default function addCliWrapper( - options: NormalizedBuilderOptions, - context: ExecutorContext -) { - const packageJson = readJsonFile(`${options.outputPath}/package.json`); - - const binFile = `${options.outputPath}/index.bin.js`; - writeToFile( - binFile, - `#!/usr/bin/env node -'use strict'; - -require('${packageJson.main}'); -` - ); - - chmodSync(binFile, '755'); // Make the command-line file executable - - packageJson.bin = { - [context.projectName]: './index.bin.js', - }; - writeJsonFile(`${options.outputPath}/package.json`, packageJson); -} diff --git a/packages/node/src/executors/package/utils/compile-typescript-files.ts b/packages/node/src/executors/package/utils/compile-typescript-files.ts deleted file mode 100644 index 1616d848f20cd..0000000000000 --- a/packages/node/src/executors/package/utils/compile-typescript-files.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { ExecutorContext } from '@nrwl/devkit'; -import { - createTmpTsConfig, - DependentBuildableProjectNode, -} from '@nrwl/workspace/src/utilities/buildable-libs-utils'; -import { - compileTypeScript, - compileTypeScriptWatcher, -} from '@nrwl/workspace/src/utilities/typescript/compilation'; -import { join } from 'path'; -import type { - CustomTransformers, - Program, - SourceFile, - TransformerFactory, -} from 'typescript'; -import { loadTsPlugins } from '../../../utils/load-ts-plugins'; -import { NormalizedBuilderOptions } from './models'; - -export default async function compileTypeScriptFiles( - options: NormalizedBuilderOptions, - context: ExecutorContext, - libRoot: string, - projectDependencies: DependentBuildableProjectNode[], - postCompleteAction: () => void | Promise -) { - let tsConfigPath = join(context.root, options.tsConfig); - if (projectDependencies.length > 0) { - tsConfigPath = createTmpTsConfig( - tsConfigPath, - context.root, - libRoot, - projectDependencies - ); - } - - const { compilerPluginHooks } = loadTsPlugins(options.tsPlugins); - - const getCustomTransformers = (program: Program): CustomTransformers => ({ - before: compilerPluginHooks.beforeHooks.map( - (hook) => hook(program) as TransformerFactory - ), - after: compilerPluginHooks.afterHooks.map( - (hook) => hook(program) as TransformerFactory - ), - afterDeclarations: compilerPluginHooks.afterDeclarationsHooks.map( - (hook) => hook(program) as TransformerFactory - ), - }); - - const tcsOptions = { - outputPath: options.normalizedOutputPath, - projectName: context.projectName, - projectRoot: libRoot, - tsConfig: tsConfigPath, - deleteOutputPath: options.deleteOutputPath, - rootDir: options.srcRootForCompilationRoot, - watch: options.watch, - getCustomTransformers, - }; - - if (options.watch) { - return compileTypeScriptWatcher(tcsOptions, async (d) => { - // Means tsc found 0 errors, in watch mode. https://github.com/microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json - if (d.code === 6194) { - await postCompleteAction(); - } - }); - } else { - const result = compileTypeScript(tcsOptions); - await postCompleteAction(); - return result; - } -} diff --git a/packages/node/src/executors/package/utils/models.ts b/packages/node/src/executors/package/utils/models.ts deleted file mode 100644 index f08929c35eee6..0000000000000 --- a/packages/node/src/executors/package/utils/models.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - AssetGlob, - FileInputOutput, -} from '@nrwl/workspace/src/utilities/assets'; -import { TsPluginEntry } from '../../../utils/types'; - -export interface NodePackageBuilderOptions { - main: string; - tsConfig: string; - outputPath: string; - watch: boolean; - sourceMap: boolean; - assets: Array; - packageJson: string; - updateBuildableProjectDepsInPackageJson?: boolean; - buildableProjectDepsInPackageJsonType?: 'dependencies' | 'peerDependencies'; - srcRootForCompilationRoot?: string; - deleteOutputPath: boolean; - cli?: boolean; - tsPlugins?: TsPluginEntry[]; -} - -export interface NormalizedBuilderOptions extends NodePackageBuilderOptions { - files: Array; - normalizedOutputPath: string; - relativeMainFileOutput: string; -} diff --git a/packages/node/src/executors/package/utils/normalize-options.ts b/packages/node/src/executors/package/utils/normalize-options.ts deleted file mode 100644 index 0e8b10df7879d..0000000000000 --- a/packages/node/src/executors/package/utils/normalize-options.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ExecutorContext, normalizePath } from '@nrwl/devkit'; -import { - assetGlobsToFiles, - FileInputOutput, -} from '@nrwl/workspace/src/utilities/assets'; -import { existsSync } from 'fs-extra'; -import { dirname, join, relative } from 'path'; -import { NodePackageBuilderOptions, NormalizedBuilderOptions } from './models'; - -export default function normalizeOptions( - options: NodePackageBuilderOptions, - context: ExecutorContext, - libRoot: string -): NormalizedBuilderOptions { - const outDir = join(context.root, options.outputPath); - const files: FileInputOutput[] = assetGlobsToFiles( - options.assets, - context.root, - outDir - ); - - const rootDir = libRoot || ''; - - if (options.main && !existsSync(options.main)) { - throw new Error( - `Please verify that the "main" option for project "${context.projectName}" is valid.` - ); - } - - const mainFileDir = dirname(options.main); - - // Always include a preceding dot to match format used for entry points - const relativeDir = normalizePath(relative(rootDir, mainFileDir)); - const relativeMainFileOutput = - relativeDir === '' ? `./` : `./${relativeDir}/`; - - if (options.buildableProjectDepsInPackageJsonType == undefined) { - options.buildableProjectDepsInPackageJsonType = 'dependencies'; - } - - return { - ...options, - files, - relativeMainFileOutput, - normalizedOutputPath: join(context.root, options.outputPath), - }; -} diff --git a/packages/node/src/executors/package/utils/update-package-json.ts b/packages/node/src/executors/package/utils/update-package-json.ts deleted file mode 100644 index fab673f594f88..0000000000000 --- a/packages/node/src/executors/package/utils/update-package-json.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExecutorContext } from '@nrwl/devkit'; -import { readJsonFile, writeJsonFile } from '@nrwl/devkit'; -import { basename, join } from 'path'; -import { NormalizedBuilderOptions } from './models'; - -export default function updatePackageJson( - options: NormalizedBuilderOptions, - context: ExecutorContext -) { - const mainFile = basename(options.main).replace(/\.[tj]s$/, ''); - const typingsFile = `${mainFile}.d.ts`; - const mainJsFile = `${mainFile}.js`; - const packageJson = readJsonFile(join(context.root, options.packageJson)); - - if (!packageJson.main) { - packageJson.main = `${options.relativeMainFileOutput}${mainJsFile}`; - } - - if (!packageJson.typings) { - packageJson.typings = `${options.relativeMainFileOutput}${typingsFile}`; - } - - writeJsonFile(`${options.outputPath}/package.json`, packageJson); -} diff --git a/packages/node/src/executors/webpack/compat.ts b/packages/node/src/executors/webpack/compat.ts new file mode 100644 index 0000000000000..919858b9b3dd7 --- /dev/null +++ b/packages/node/src/executors/webpack/compat.ts @@ -0,0 +1,5 @@ +import { convertNxExecutor } from '@nrwl/devkit'; + +import { webpackExecutor } from './webpack.impl'; + +export default convertNxExecutor(webpackExecutor); diff --git a/packages/node/src/executors/build/schema.json b/packages/node/src/executors/webpack/schema.json similarity index 100% rename from packages/node/src/executors/build/schema.json rename to packages/node/src/executors/webpack/schema.json diff --git a/packages/node/src/executors/build/build.impl.spec.ts b/packages/node/src/executors/webpack/webpack.impl.spec.ts similarity index 95% rename from packages/node/src/executors/build/build.impl.spec.ts rename to packages/node/src/executors/webpack/webpack.impl.spec.ts index 912a12e66ea85..7a9133c8bda5a 100644 --- a/packages/node/src/executors/build/build.impl.spec.ts +++ b/packages/node/src/executors/webpack/webpack.impl.spec.ts @@ -2,7 +2,7 @@ import { ExecutorContext } from '@nrwl/devkit'; import { of } from 'rxjs'; import * as projectGraph from '@nrwl/workspace/src/core/project-graph'; import type { ProjectGraph } from '@nrwl/workspace/src/core/project-graph'; -import buildExecutor from './build.impl'; +import webpackExecutor from './webpack.impl'; import { BuildNodeBuilderOptions } from '../../utils/types'; jest.mock('tsconfig-paths-webpack-plugin'); @@ -51,7 +51,7 @@ describe('Node Build Executor', () => { afterEach(() => jest.clearAllMocks()); it('should call webpack', async () => { - await buildExecutor(options, context).next(); + await webpackExecutor(options, context).next(); expect(runWebpack).toHaveBeenCalledWith( expect.objectContaining({ @@ -65,7 +65,7 @@ describe('Node Build Executor', () => { }); it('should use outputFileName if passed in', async () => { - await buildExecutor( + await webpackExecutor( { ...options, outputFileName: 'index.js' }, context ).next(); @@ -88,7 +88,7 @@ describe('Node Build Executor', () => { () => (options) => ({ ...options, prop: 'my-val' }), { virtual: true } ); - await buildExecutor( + await webpackExecutor( { ...options, webpackConfig: 'config.js' }, context ).next(); @@ -120,7 +120,7 @@ describe('Node Build Executor', () => { }), { virtual: true } ); - await buildExecutor( + await webpackExecutor( { ...options, webpackConfig: ['config1.js', 'config2.js'] }, context ).next(); diff --git a/packages/node/src/executors/build/build.impl.ts b/packages/node/src/executors/webpack/webpack.impl.ts similarity index 97% rename from packages/node/src/executors/build/build.impl.ts rename to packages/node/src/executors/webpack/webpack.impl.ts index 8ac2fbc23abfd..6a10fa798f4d2 100644 --- a/packages/node/src/executors/build/build.impl.ts +++ b/packages/node/src/executors/webpack/webpack.impl.ts @@ -27,7 +27,7 @@ export type NodeBuildEvent = { success: boolean; }; -export async function* buildExecutor( +export async function* webpackExecutor( rawOptions: BuildNodeBuilderOptions, context: ExecutorContext ) { @@ -116,4 +116,4 @@ function registerTsNode() { }); } -export default buildExecutor; +export default webpackExecutor; diff --git a/packages/node/src/generators/application/application.spec.ts b/packages/node/src/generators/application/application.spec.ts index 5fc0b8efcf703..20b6be3ef703e 100644 --- a/packages/node/src/generators/application/application.spec.ts +++ b/packages/node/src/generators/application/application.spec.ts @@ -44,7 +44,7 @@ describe('app', () => { expect(project.architect).toEqual( expect.objectContaining({ build: { - builder: '@nrwl/node:build', + builder: '@nrwl/node:webpack', outputs: ['{options.outputPath}'], options: { outputPath: 'dist/apps/my-node-app', diff --git a/packages/node/src/generators/application/application.ts b/packages/node/src/generators/application/application.ts index 8421c55b1ef95..a4fd9972e98e3 100644 --- a/packages/node/src/generators/application/application.ts +++ b/packages/node/src/generators/application/application.ts @@ -39,7 +39,7 @@ function getBuildConfig( options: NormalizedSchema ): TargetConfiguration { return { - executor: '@nrwl/node:build', + executor: '@nrwl/node:webpack', outputs: ['{options.outputPath}'], options: { outputPath: joinPathFragments('dist', options.appProjectRoot), diff --git a/packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.spec.ts b/packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.spec.ts new file mode 100644 index 0000000000000..9ac591917f6f8 --- /dev/null +++ b/packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.spec.ts @@ -0,0 +1,49 @@ +import { readJson } from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + +import rename from './rename-build-to-webpack'; + +describe('Migration: rename build to webpack', () => { + it(`should rename the "build" executor to "webpack"`, async () => { + let tree = createTreeWithEmptyWorkspace(); + + tree.write( + 'workspace.json', + JSON.stringify({ + version: 2, + projects: { + myapp: { + root: 'apps/myapp', + sourceRoot: 'apps/myapp/src', + projectType: 'application', + targets: { + build: { + executor: '@nrwl/node:build', + options: {}, + }, + }, + }, + }, + }) + ); + + await rename(tree); + + expect(readJson(tree, 'workspace.json')).toEqual({ + version: 2, + projects: { + myapp: { + root: 'apps/myapp', + sourceRoot: 'apps/myapp/src', + projectType: 'application', + targets: { + build: { + executor: '@nrwl/node:webpack', + options: {}, + }, + }, + }, + }, + }); + }); +}); diff --git a/packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.ts b/packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.ts new file mode 100644 index 0000000000000..c7e48b1cd4992 --- /dev/null +++ b/packages/node/src/migrations/update-13-9-0/rename-build-to-webpack.ts @@ -0,0 +1,20 @@ +import { + formatFiles, + getProjects, + Tree, + updateProjectConfiguration, +} from '@nrwl/devkit'; + +export default async function update(host: Tree) { + const projects = getProjects(host); + + for (const [name, config] of projects.entries()) { + if (config?.targets?.build?.executor !== '@nrwl/node:build') continue; + + config.targets.build.executor = '@nrwl/node:webpack'; + + updateProjectConfiguration(host, name, config); + } + + await formatFiles(host); +} diff --git a/packages/node/src/migrations/update-13-9-0/rename-execute-to-node.spec.ts b/packages/node/src/migrations/update-13-9-0/rename-execute-to-node.spec.ts new file mode 100644 index 0000000000000..b24b6af48f6f3 --- /dev/null +++ b/packages/node/src/migrations/update-13-9-0/rename-execute-to-node.spec.ts @@ -0,0 +1,49 @@ +import { readJson } from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + +import rename from './rename-execute-to-node'; + +describe('Migration: rename execute to node', () => { + it(`should rename the "execute" executor to "node"`, async () => { + let tree = createTreeWithEmptyWorkspace(); + + tree.write( + 'workspace.json', + JSON.stringify({ + version: 2, + projects: { + myapp: { + root: 'apps/myapp', + sourceRoot: 'apps/myapp/src', + projectType: 'application', + targets: { + serve: { + executor: '@nrwl/node:execute', + options: {}, + }, + }, + }, + }, + }) + ); + + await rename(tree); + + expect(readJson(tree, 'workspace.json')).toEqual({ + version: 2, + projects: { + myapp: { + root: 'apps/myapp', + sourceRoot: 'apps/myapp/src', + projectType: 'application', + targets: { + serve: { + executor: '@nrwl/node:node', + options: {}, + }, + }, + }, + }, + }); + }); +}); diff --git a/packages/node/src/migrations/update-13-9-0/rename-execute-to-node.ts b/packages/node/src/migrations/update-13-9-0/rename-execute-to-node.ts new file mode 100644 index 0000000000000..598bd2591447f --- /dev/null +++ b/packages/node/src/migrations/update-13-9-0/rename-execute-to-node.ts @@ -0,0 +1,20 @@ +import { + formatFiles, + getProjects, + Tree, + updateProjectConfiguration, +} from '@nrwl/devkit'; + +export default async function update(host: Tree) { + const projects = getProjects(host); + + for (const [name, config] of projects.entries()) { + if (config?.targets?.serve?.executor !== '@nrwl/node:execute') continue; + + config.targets.serve.executor = '@nrwl/node:node'; + + updateProjectConfiguration(host, name, config); + } + + await formatFiles(host); +} diff --git a/packages/node/src/migrations/update-13-9-0/update-package-to-tsc.spec.ts b/packages/node/src/migrations/update-13-9-0/update-package-to-tsc.spec.ts new file mode 100644 index 0000000000000..ca376c437b480 --- /dev/null +++ b/packages/node/src/migrations/update-13-9-0/update-package-to-tsc.spec.ts @@ -0,0 +1,70 @@ +import { readJson } from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + +import update from './update-package-to-tsc'; + +describe('Migration: rename package to tsc', () => { + it(`should rename the "package" executor to "tsc"`, async () => { + let tree = createTreeWithEmptyWorkspace(); + + tree.write( + 'workspace.json', + JSON.stringify({ + version: 2, + projects: { + mylib: { + root: 'libs/mylib', + sourceRoot: 'libs/mylib/src', + projectType: 'library', + targets: { + build: { + executor: '@nrwl/node:package', + options: { + tsPlugins: [], + }, + }, + }, + }, + }, + }) + ); + + const tasks = await update(tree); + + expect(tasks).toBeDefined(); + expect(readJson(tree, 'workspace.json')).toEqual({ + version: 2, + projects: { + mylib: { + root: 'libs/mylib', + sourceRoot: 'libs/mylib/src', + projectType: 'library', + targets: { + build: { + executor: '@nrwl/js:tsc', + options: { + transformers: [], + }, + }, + }, + }, + }, + }); + }); + + it(`should skip migration if no projects use @nrwl/js:node`, async () => { + let tree = createTreeWithEmptyWorkspace(); + + tree.write( + 'workspace.json', + JSON.stringify({ + version: 2, + projects: {}, + }) + ); + + const tasks = await update(tree); + + expect(tasks).toBeUndefined(); + }); +}); diff --git a/packages/node/src/migrations/update-13-9-0/update-package-to-tsc.ts b/packages/node/src/migrations/update-13-9-0/update-package-to-tsc.ts new file mode 100644 index 0000000000000..f2710672a7f11 --- /dev/null +++ b/packages/node/src/migrations/update-13-9-0/update-package-to-tsc.ts @@ -0,0 +1,42 @@ +import { + addDependenciesToPackageJson, + formatFiles, + getProjects, + Tree, + updateProjectConfiguration, +} from '@nrwl/devkit'; +import { nxVersion } from '@nrwl/workspace/src/utils/versions'; + +export default async function update(host: Tree) { + const projects = getProjects(host); + let installNeeded = false; + + for (const [name, config] of projects.entries()) { + if (config?.targets?.build?.executor !== '@nrwl/node:package') continue; + + config.targets.build.executor = '@nrwl/js:tsc'; + + const transformers = config.targets.build.options?.tsPlugins; + if (transformers) { + delete config.targets.build.options.tsPlugins; + config.targets.build.options.transformers = transformers; + } + + installNeeded = true; + updateProjectConfiguration(host, name, config); + } + + const task = installNeeded + ? addDependenciesToPackageJson( + host, + {}, + { + '@nrwl/js': nxVersion, + } + ) + : undefined; + + await formatFiles(host); + + return task; +} diff --git a/packages/nx-plugin/package.json b/packages/nx-plugin/package.json index 4bff75fa17724..1ffecd8c95ce3 100644 --- a/packages/nx-plugin/package.json +++ b/packages/nx-plugin/package.json @@ -30,7 +30,7 @@ "@nrwl/devkit": "*", "@nrwl/jest": "*", "@nrwl/linter": "*", - "@nrwl/node": "*", + "@nrwl/js": "*", "fs-extra": "^9.1.0", "rxjs": "^6.5.4", "tslib": "^2.3.0" diff --git a/packages/nx-plugin/src/generators/executor/executor.spec.ts b/packages/nx-plugin/src/generators/executor/executor.spec.ts index ac2cdabbee9b7..3b4803d22d836 100644 --- a/packages/nx-plugin/src/generators/executor/executor.spec.ts +++ b/packages/nx-plugin/src/generators/executor/executor.spec.ts @@ -9,7 +9,7 @@ describe('NxPlugin Executor Generator', () => { beforeEach(async () => { projectName = 'my-plugin'; - tree = createTreeWithEmptyWorkspace(); + tree = createTreeWithEmptyWorkspace(2); await pluginGenerator(tree, { name: projectName, diff --git a/packages/nx-plugin/src/generators/generator/generator.spec.ts b/packages/nx-plugin/src/generators/generator/generator.spec.ts index a0991e62e1d52..e6661c9ec96ed 100644 --- a/packages/nx-plugin/src/generators/generator/generator.spec.ts +++ b/packages/nx-plugin/src/generators/generator/generator.spec.ts @@ -9,7 +9,7 @@ describe('NxPlugin Generator Generator', () => { beforeEach(async () => { projectName = 'my-plugin'; - tree = createTreeWithEmptyWorkspace(); + tree = createTreeWithEmptyWorkspace(2); await pluginGenerator(tree, { name: projectName, } as any); diff --git a/packages/nx-plugin/src/generators/migration/migration.spec.ts b/packages/nx-plugin/src/generators/migration/migration.spec.ts index 554f58d0a65f1..7b856e89dd16b 100644 --- a/packages/nx-plugin/src/generators/migration/migration.spec.ts +++ b/packages/nx-plugin/src/generators/migration/migration.spec.ts @@ -9,7 +9,7 @@ describe('NxPlugin migration generator', () => { beforeEach(async () => { projectName = 'my-plugin'; - tree = createTreeWithEmptyWorkspace(); + tree = createTreeWithEmptyWorkspace(2); await pluginGenerator(tree, { name: projectName, diff --git a/packages/nx-plugin/src/generators/plugin/plugin.spec.ts b/packages/nx-plugin/src/generators/plugin/plugin.spec.ts index 02b8e320cf8d1..a075529dc3b03 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.spec.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.spec.ts @@ -6,7 +6,7 @@ describe('NxPlugin Plugin Generator', () => { let tree: Tree; beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); + tree = createTreeWithEmptyWorkspace(2); }); it('should update the workspace.json file', async () => { @@ -14,12 +14,11 @@ describe('NxPlugin Plugin Generator', () => { const project = readProjectConfiguration(tree, 'my-plugin'); expect(project.root).toEqual('libs/my-plugin'); expect(project.targets.build).toEqual({ - executor: '@nrwl/node:package', + executor: '@nrwl/js:tsc', outputs: ['{options.outputPath}'], options: { outputPath: 'dist/libs/my-plugin', tsConfig: 'libs/my-plugin/tsconfig.lib.json', - packageJson: 'libs/my-plugin/package.json', main: 'libs/my-plugin/src/index.ts', assets: [ 'libs/my-plugin/*.md', @@ -78,6 +77,7 @@ describe('NxPlugin Plugin Generator', () => { await pluginGenerator(tree, { name: 'myPlugin' } as any); [ + 'libs/my-plugin/project.json', 'libs/my-plugin/generators.json', 'libs/my-plugin/executors.json', 'libs/my-plugin/src/generators/my-plugin/schema.d.ts', diff --git a/packages/nx-plugin/src/generators/plugin/plugin.ts b/packages/nx-plugin/src/generators/plugin/plugin.ts index 861cbe099eabc..4e25f74af3765 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.ts @@ -15,7 +15,7 @@ import { import type { Schema } from './schema'; import { nxVersion } from '../../utils/versions'; import * as path from 'path'; -import { libraryGenerator } from '@nrwl/node'; +import { libraryGenerator } from '@nrwl/js'; import { e2eProjectGenerator } from '../e2e-project/e2e'; import { generatorGenerator } from '../generator/generator'; import { executorGenerator } from '../executor/executor'; @@ -126,7 +126,8 @@ export async function pluginGenerator(host: Tree, schema: Schema) { const libraryTask = await libraryGenerator(host, { ...schema, - publishable: true, + config: options.standaloneConfig !== false ? 'project' : 'workspace', + buildable: true, importPath: schema.importPath ?? options.npmPackageName, }); tasks.push(libraryTask); @@ -137,7 +138,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) { { '@nrwl/devkit': nxVersion, '@nrwl/jest': nxVersion, - '@nrwl/node': nxVersion, + '@nrwl/js': nxVersion, tslib: '^2.0.0', } ); @@ -151,7 +152,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) { projectDirectory: options.projectDirectory, pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`, npmPackageName: options.npmPackageName, - standaloneConfig: options.standaloneConfig, + standaloneConfig: options.standaloneConfig ?? true, }); await formatFiles(host);