cleanup(angular): move the angular cli migration generator from @nrwl/workspace to @nrwl/angular (#9244)
* cleanup(angular): move the angular cli migration generator from @nrwl/workspace to @nrwl/angular * cleanup(angular): support merged packages (cli, tao, nx) * cleanup(angular): update make-angular-cli-faster to support packages consolidation
This commit is contained in:
parent
3824eebc23
commit
88a7ad7654
@ -157,12 +157,28 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
|||||||
npmScope: 'projscope',
|
npmScope: 'projscope',
|
||||||
affected: { defaultBase: 'main' },
|
affected: { defaultBase: 'main' },
|
||||||
implicitDependencies: {
|
implicitDependencies: {
|
||||||
'angular.json': '*',
|
'package.json': {
|
||||||
'package.json': '*',
|
dependencies: '*',
|
||||||
'tslint.json': '*',
|
devDependencies: '*',
|
||||||
|
},
|
||||||
'.eslintrc.json': '*',
|
'.eslintrc.json': '*',
|
||||||
'tsconfig.base.json': '*',
|
'tsconfig.base.json': '*',
|
||||||
'nx.json': '*',
|
},
|
||||||
|
tasksRunnerOptions: {
|
||||||
|
default: {
|
||||||
|
runner: '@nrwl/workspace/tasks-runners/default',
|
||||||
|
options: {
|
||||||
|
cacheableOperations: ['build', 'lint', 'test', 'e2e'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
targetDependencies: {
|
||||||
|
build: [
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
projects: 'dependencies',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
cli: { defaultCollection: '@nrwl/angular', packageManager },
|
cli: { defaultCollection: '@nrwl/angular', packageManager },
|
||||||
defaultProject: project,
|
defaultProject: project,
|
||||||
|
|||||||
@ -125,8 +125,8 @@ describe('list', () => {
|
|||||||
|
|
||||||
// check for schematics
|
// check for schematics
|
||||||
expect(listOutput).toContain('workspace');
|
expect(listOutput).toContain('workspace');
|
||||||
expect(listOutput).toContain('ng-add');
|
|
||||||
expect(listOutput).toContain('library');
|
expect(listOutput).toContain('library');
|
||||||
|
expect(listOutput).toContain('workspace-generator');
|
||||||
|
|
||||||
// check for builders
|
// check for builders
|
||||||
expect(listOutput).toContain('run-commands');
|
expect(listOutput).toContain('run-commands');
|
||||||
|
|||||||
@ -422,8 +422,8 @@ export function runNgAdd(
|
|||||||
}
|
}
|
||||||
): string {
|
): string {
|
||||||
try {
|
try {
|
||||||
packageInstall('@nrwl/workspace');
|
packageInstall('@nrwl/angular');
|
||||||
return execSync(`npx ng add @nrwl/workspace ${command}`, {
|
return execSync(`npx ng add @nrwl/angular ${command}`, {
|
||||||
cwd: tmpProjPath(),
|
cwd: tmpProjPath(),
|
||||||
env: { ...(opts.env || process.env), NX_INVOKED_BY_RUNNER: undefined },
|
env: { ...(opts.env || process.env), NX_INVOKED_BY_RUNNER: undefined },
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
|
|||||||
@ -47,7 +47,6 @@
|
|||||||
"factory": "./src/generators/init/init.compat#initSchematic",
|
"factory": "./src/generators/init/init.compat#initSchematic",
|
||||||
"schema": "./src/generators/init/schema.json",
|
"schema": "./src/generators/init/schema.json",
|
||||||
"description": "Initializes the @nrwl/angular plugin.",
|
"description": "Initializes the @nrwl/angular plugin.",
|
||||||
"aliases": ["ng-add"],
|
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"karma": {
|
"karma": {
|
||||||
@ -91,6 +90,12 @@
|
|||||||
"aliases": ["host"],
|
"aliases": ["host"],
|
||||||
"description": "Generate a Host Angular Micro Frontend Application."
|
"description": "Generate a Host Angular Micro Frontend Application."
|
||||||
},
|
},
|
||||||
|
"ng-add": {
|
||||||
|
"factory": "./src/generators/ng-add/compat",
|
||||||
|
"schema": "./src/generators/ng-add/schema.json",
|
||||||
|
"description": "Migrates an Angular CLI workspace to Nx or adds the Angular plugin to an Nx workspace.",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
"ngrx": {
|
"ngrx": {
|
||||||
"factory": "./src/generators/ngrx/compat",
|
"factory": "./src/generators/ngrx/compat",
|
||||||
"schema": "./src/generators/ngrx/schema.json",
|
"schema": "./src/generators/ngrx/schema.json",
|
||||||
@ -197,7 +202,6 @@
|
|||||||
"factory": "./src/generators/init/init",
|
"factory": "./src/generators/init/init",
|
||||||
"schema": "./src/generators/init/schema.json",
|
"schema": "./src/generators/init/schema.json",
|
||||||
"description": "Initializes the @nrwl/angular plugin.",
|
"description": "Initializes the @nrwl/angular plugin.",
|
||||||
"aliases": ["ng-add"],
|
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"karma": {
|
"karma": {
|
||||||
@ -241,6 +245,12 @@
|
|||||||
"aliases": ["host"],
|
"aliases": ["host"],
|
||||||
"description": "Generate a Host Angular Micro Frontend Application."
|
"description": "Generate a Host Angular Micro Frontend Application."
|
||||||
},
|
},
|
||||||
|
"ng-add": {
|
||||||
|
"factory": "./src/generators/ng-add/ng-add",
|
||||||
|
"schema": "./src/generators/ng-add/schema.json",
|
||||||
|
"description": "Migrates an Angular CLI workspace to Nx or adds the Angular plugin to an Nx workspace.",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
"ngrx": {
|
"ngrx": {
|
||||||
"factory": "./src/generators/ngrx/ngrx",
|
"factory": "./src/generators/ngrx/ngrx",
|
||||||
"schema": "./src/generators/ngrx/schema.json",
|
"schema": "./src/generators/ngrx/schema.json",
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
updateWorkspaceConfiguration,
|
updateWorkspaceConfiguration,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { jestInitGenerator } from '@nrwl/jest';
|
import { jestInitGenerator } from '@nrwl/jest';
|
||||||
|
import { Linter } from '@nrwl/linter';
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import { setDefaultCollection } from '@nrwl/workspace/src/utilities/set-default-collection';
|
import { setDefaultCollection } from '@nrwl/workspace/src/utilities/set-default-collection';
|
||||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||||
@ -22,8 +23,9 @@ import { Schema } from './schema';
|
|||||||
|
|
||||||
export async function angularInitGenerator(
|
export async function angularInitGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
options: Schema
|
rawOptions: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
|
const options = normalizeOptions(rawOptions);
|
||||||
setDefaults(host, options);
|
setDefaults(host, options);
|
||||||
addPostInstall(host);
|
addPostInstall(host);
|
||||||
|
|
||||||
@ -41,6 +43,18 @@ export async function angularInitGenerator(
|
|||||||
return runTasksInSerial(depsTask, unitTestTask, e2eTask);
|
return runTasksInSerial(depsTask, unitTestTask, e2eTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeOptions(options: Schema): Required<Schema> {
|
||||||
|
return {
|
||||||
|
e2eTestRunner: options.e2eTestRunner ?? E2eTestRunner.Cypress,
|
||||||
|
linter: options.linter ?? Linter.EsLint,
|
||||||
|
skipFormat: options.skipFormat ?? false,
|
||||||
|
skipInstall: options.skipInstall ?? false,
|
||||||
|
skipPackageJson: options.skipPackageJson ?? false,
|
||||||
|
style: options.style ?? 'css',
|
||||||
|
unitTestRunner: options.unitTestRunner ?? UnitTestRunner.Jest,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function setDefaults(host: Tree, options: Schema) {
|
function setDefaults(host: Tree, options: Schema) {
|
||||||
const workspace = readWorkspaceConfiguration(host);
|
const workspace = readWorkspaceConfiguration(host);
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
|||||||
import type { Styles } from '../utils/types';
|
import type { Styles } from '../utils/types';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
unitTestRunner: UnitTestRunner;
|
unitTestRunner?: UnitTestRunner;
|
||||||
e2eTestRunner?: E2eTestRunner;
|
e2eTestRunner?: E2eTestRunner;
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipInstall?: boolean;
|
skipInstall?: boolean;
|
||||||
style?: Styles;
|
style?: Styles;
|
||||||
linter: Exclude<Linter, Linter.TsLint>;
|
linter?: Exclude<Linter, Linter.TsLint>;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
"description": "The file extension to be used for style files.",
|
"description": "The file extension to be used for style files.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "css",
|
"default": "css",
|
||||||
|
"enum": ["css", "scss", "sass", "less"],
|
||||||
"x-prompt": {
|
"x-prompt": {
|
||||||
"message": "Which stylesheet format would you like to use?",
|
"message": "Which stylesheet format would you like to use?",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
@ -50,6 +51,10 @@
|
|||||||
"value": "scss",
|
"value": "scss",
|
||||||
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "sass",
|
||||||
|
"label": "SASS(.sass) [ http://sass-lang.com ]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "less",
|
"value": "less",
|
||||||
"label": "LESS [ http://lesscss.org ]"
|
"label": "LESS [ http://lesscss.org ]"
|
||||||
|
|||||||
@ -167,13 +167,34 @@ Object {
|
|||||||
"defaultProject": "myApp",
|
"defaultProject": "myApp",
|
||||||
"implicitDependencies": Object {
|
"implicitDependencies": Object {
|
||||||
".eslintrc.json": "*",
|
".eslintrc.json": "*",
|
||||||
"angular.json": "*",
|
"package.json": Object {
|
||||||
"nx.json": "*",
|
"dependencies": "*",
|
||||||
"package.json": "*",
|
"devDependencies": "*",
|
||||||
|
},
|
||||||
"tsconfig.base.json": "*",
|
"tsconfig.base.json": "*",
|
||||||
"tslint.json": "*",
|
|
||||||
},
|
},
|
||||||
"npmScope": "my-app",
|
"npmScope": "my-app",
|
||||||
|
"targetDependencies": Object {
|
||||||
|
"build": Array [
|
||||||
|
Object {
|
||||||
|
"projects": "dependencies",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"tasksRunnerOptions": Object {
|
||||||
|
"default": Object {
|
||||||
|
"options": Object {
|
||||||
|
"cacheableOperations": Array [
|
||||||
|
"build",
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"e2e",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
4
packages/angular/src/generators/ng-add/compat.ts
Normal file
4
packages/angular/src/generators/ng-add/compat.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { convertNxGenerator } from '@nrwl/devkit';
|
||||||
|
import { ngAddGenerator } from './ng-add';
|
||||||
|
|
||||||
|
export default convertNxGenerator(ngAddGenerator);
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching
|
||||||
|
* and faster execution of tasks.
|
||||||
|
*
|
||||||
|
* It does this by:
|
||||||
|
*
|
||||||
|
* - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command.
|
||||||
|
* - Symlinking the ng to nx command, so all commands run through the Nx CLI
|
||||||
|
* - Updating the package.json postinstall script to give you control over this script
|
||||||
|
*
|
||||||
|
* The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it.
|
||||||
|
* Every command you run should work the same when using the Nx CLI, except faster.
|
||||||
|
*
|
||||||
|
* Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case,
|
||||||
|
* will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked.
|
||||||
|
* The Nx CLI simply does some optimizations before invoking the Angular CLI.
|
||||||
|
*
|
||||||
|
* To opt out of this patch:
|
||||||
|
* - Replace occurrences of nx with ng in your package.json
|
||||||
|
* - Remove the script from your postinstall script in your package.json
|
||||||
|
* - Delete and reinstall your node_modules
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const cp = require('child_process');
|
||||||
|
const isWindows = os.platform() === 'win32';
|
||||||
|
let output;
|
||||||
|
try {
|
||||||
|
output = require('@nrwl/workspace').output;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Angular CLI could not be decorated to enable computation caching. Please ensure @nrwl/workspace is installed.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symlink of ng to nx, so you can keep using `ng build/test/lint` and still
|
||||||
|
* invoke the Nx CLI and get the benefits of computation caching.
|
||||||
|
*/
|
||||||
|
function symlinkNgCLItoNxCLI() {
|
||||||
|
try {
|
||||||
|
const ngPath = './node_modules/.bin/ng';
|
||||||
|
const nxPath = './node_modules/.bin/nx';
|
||||||
|
if (isWindows) {
|
||||||
|
/**
|
||||||
|
* This is the most reliable way to create symlink-like behavior on Windows.
|
||||||
|
* Such that it works in all shells and works with npx.
|
||||||
|
*/
|
||||||
|
['', '.cmd', '.ps1'].forEach(ext => {
|
||||||
|
if (fs.existsSync(nxPath + ext)) fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If unix-based, symlink
|
||||||
|
cp.execSync(`ln -sf ./nx ${ngPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
output.error({ title: 'Unable to create a symlink from the Angular CLI to the Nx CLI:' + e.message });
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
symlinkNgCLItoNxCLI();
|
||||||
|
require('nx/src/cli/decorate-cli').decorateCli();
|
||||||
|
output.log({ title: 'Angular CLI has been decorated to enable computation caching.' });
|
||||||
|
} catch(e) {
|
||||||
|
output.error({ title: 'Decoration of the Angular CLI did not complete successfully' });
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"npmScope": "<%= npmScope %>",
|
||||||
|
"affected": {
|
||||||
|
"defaultBase": "<%= defaultBase %>"
|
||||||
|
},
|
||||||
|
"implicitDependencies": {
|
||||||
|
"package.json": {
|
||||||
|
"dependencies": "*",
|
||||||
|
"devDependencies": "*"
|
||||||
|
},
|
||||||
|
".eslintrc.json": "*"
|
||||||
|
},
|
||||||
|
"tasksRunnerOptions": {
|
||||||
|
"default": {
|
||||||
|
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||||
|
"options": {
|
||||||
|
"cacheableOperations": ["build", "lint", "test", "e2e"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetDependencies": {
|
||||||
|
"build": [
|
||||||
|
{
|
||||||
|
"target": "build",
|
||||||
|
"projects": "dependencies"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { createTree } from '@nrwl/devkit/testing';
|
import { createTree } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
import { initGenerator } from './init';
|
import { migrateFromAngularCli } from './migrate-from-angular-cli';
|
||||||
|
|
||||||
describe('workspace', () => {
|
describe('workspace', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
@ -77,7 +77,7 @@ describe('workspace', () => {
|
|||||||
it('should error if no package.json is present', async () => {
|
it('should error if no package.json is present', async () => {
|
||||||
tree.delete('package.json');
|
tree.delete('package.json');
|
||||||
try {
|
try {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
fail('should throw');
|
fail('should throw');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toContain('Cannot find package.json');
|
expect(e.message).toContain('Cannot find package.json');
|
||||||
@ -88,7 +88,7 @@ describe('workspace', () => {
|
|||||||
tree.delete('/e2e/protractor.conf.js');
|
tree.delete('/e2e/protractor.conf.js');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await initGenerator(tree, { name: 'proj1' });
|
await migrateFromAngularCli(tree, { name: 'proj1' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toContain(
|
expect(e.message).toContain(
|
||||||
'An e2e project with Protractor was found but "e2e/protractor.conf.js" could not be found.'
|
'An e2e project with Protractor was found but "e2e/protractor.conf.js" could not be found.'
|
||||||
@ -101,7 +101,9 @@ describe('workspace', () => {
|
|||||||
project.targets.e2e.executor = '@cypress/schematic:cypress';
|
project.targets.e2e.executor = '@cypress/schematic:cypress';
|
||||||
updateProjectConfiguration(tree, 'myApp', project);
|
updateProjectConfiguration(tree, 'myApp', project);
|
||||||
|
|
||||||
await expect(initGenerator(tree, { name: 'myApp' })).rejects.toThrow(
|
await expect(
|
||||||
|
migrateFromAngularCli(tree, { name: 'myApp' })
|
||||||
|
).rejects.toThrow(
|
||||||
'An e2e project with Cypress was found but "cypress.json" could not be found.'
|
'An e2e project with Cypress was found but "cypress.json" could not be found.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -116,7 +118,9 @@ describe('workspace', () => {
|
|||||||
};
|
};
|
||||||
updateProjectConfiguration(tree, 'myApp', project);
|
updateProjectConfiguration(tree, 'myApp', project);
|
||||||
|
|
||||||
await expect(initGenerator(tree, { name: 'myApp' })).rejects.toThrow(
|
await expect(
|
||||||
|
migrateFromAngularCli(tree, { name: 'myApp' })
|
||||||
|
).rejects.toThrow(
|
||||||
'An e2e project with Cypress was found but "cypress.config.json" could not be found.'
|
'An e2e project with Cypress was found but "cypress.config.json" could not be found.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -127,7 +131,9 @@ describe('workspace', () => {
|
|||||||
updateProjectConfiguration(tree, 'myApp', project);
|
updateProjectConfiguration(tree, 'myApp', project);
|
||||||
tree.write('cypress.json', '{}');
|
tree.write('cypress.json', '{}');
|
||||||
|
|
||||||
await expect(initGenerator(tree, { name: 'myApp' })).rejects.toThrow(
|
await expect(
|
||||||
|
migrateFromAngularCli(tree, { name: 'myApp' })
|
||||||
|
).rejects.toThrow(
|
||||||
'An e2e project with Cypress was found but the "cypress" directory could not be found.'
|
'An e2e project with Cypress was found but the "cypress" directory could not be found.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -137,7 +143,9 @@ describe('workspace', () => {
|
|||||||
project.targets.e2e.executor = '@my-org/my-package:my-executor';
|
project.targets.e2e.executor = '@my-org/my-package:my-executor';
|
||||||
updateProjectConfiguration(tree, 'myApp', project);
|
updateProjectConfiguration(tree, 'myApp', project);
|
||||||
|
|
||||||
await expect(initGenerator(tree, { name: 'myApp' })).rejects.toThrow(
|
await expect(
|
||||||
|
migrateFromAngularCli(tree, { name: 'myApp' })
|
||||||
|
).rejects.toThrow(
|
||||||
`An e2e project was found but it's using an unsupported executor "@my-org/my-package:my-executor".`
|
`An e2e project was found but it's using an unsupported executor "@my-org/my-package:my-executor".`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -145,7 +153,7 @@ describe('workspace', () => {
|
|||||||
it('should error if no angular.json is present', async () => {
|
it('should error if no angular.json is present', async () => {
|
||||||
try {
|
try {
|
||||||
tree.delete('angular.json');
|
tree.delete('angular.json');
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toContain('Cannot find angular.json');
|
expect(e.message).toContain('Cannot find angular.json');
|
||||||
}
|
}
|
||||||
@ -164,7 +172,7 @@ describe('workspace', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toContain('Can only convert projects with one app');
|
expect(e.message).toContain('Can only convert projects with one app');
|
||||||
}
|
}
|
||||||
@ -183,7 +191,7 @@ describe('workspace', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toContain('Can only convert projects with one app');
|
expect(e.message).toContain('Can only convert projects with one app');
|
||||||
}
|
}
|
||||||
@ -239,7 +247,7 @@ describe('workspace', () => {
|
|||||||
tree.write('/projects/myApp/e2e/protractor.conf.js', '// content');
|
tree.write('/projects/myApp/e2e/protractor.conf.js', '// content');
|
||||||
tree.write('/projects/myApp/src/app/app.module.ts', '// content');
|
tree.write('/projects/myApp/src/app/app.module.ts', '// content');
|
||||||
|
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
const a = readJson(tree, '/angular.json');
|
const a = readJson(tree, '/angular.json');
|
||||||
|
|
||||||
@ -247,30 +255,30 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set the default collection to @nrwl/angular', async () => {
|
it('should set the default collection to @nrwl/angular', async () => {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
expect(readJson(tree, 'nx.json').cli.defaultCollection).toBe(
|
expect(readJson(tree, 'nx.json').cli.defaultCollection).toBe(
|
||||||
'@nrwl/angular'
|
'@nrwl/angular'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create nx.json', async () => {
|
it('should create nx.json', async () => {
|
||||||
await initGenerator(tree, { name: 'myApp', defaultBase: 'main' });
|
await migrateFromAngularCli(tree, { name: 'myApp', defaultBase: 'main' });
|
||||||
expect(readJson(tree, 'nx.json')).toMatchSnapshot();
|
expect(readJson(tree, 'nx.json')).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work if angular-cli workspace had tsconfig.base.json', async () => {
|
it('should work if angular-cli workspace had tsconfig.base.json', async () => {
|
||||||
tree.rename('tsconfig.json', 'tsconfig.base.json');
|
tree.rename('tsconfig.json', 'tsconfig.base.json');
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
expect(readJson(tree, 'tsconfig.base.json')).toMatchSnapshot();
|
expect(readJson(tree, 'tsconfig.base.json')).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update tsconfig.base.json if present', async () => {
|
it('should update tsconfig.base.json if present', async () => {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
expect(readJson(tree, 'tsconfig.base.json')).toMatchSnapshot();
|
expect(readJson(tree, 'tsconfig.base.json')).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work without nested tsconfig files', async () => {
|
it('should work without nested tsconfig files', async () => {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -321,7 +329,7 @@ describe('workspace', () => {
|
|||||||
'/src/tsconfig.spec.json',
|
'/src/tsconfig.spec.json',
|
||||||
'{"extends": "../tsconfig.json", "compilerOptions": {}}'
|
'{"extends": "../tsconfig.json", "compilerOptions": {}}'
|
||||||
);
|
);
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -374,7 +382,7 @@ describe('workspace', () => {
|
|||||||
tree.write('/projects/myApp/e2e/protractor.conf.js', '// content');
|
tree.write('/projects/myApp/e2e/protractor.conf.js', '// content');
|
||||||
tree.write('/projects/myApp/src/app/app.module.ts', '// content');
|
tree.write('/projects/myApp/src/app/app.module.ts', '// content');
|
||||||
|
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
expect(tree.exists('/tslint.json')).toBe(true);
|
expect(tree.exists('/tslint.json')).toBe(true);
|
||||||
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
||||||
@ -406,7 +414,7 @@ describe('workspace', () => {
|
|||||||
);
|
);
|
||||||
tree.write('/karma.conf.js', '// content');
|
tree.write('/karma.conf.js', '// content');
|
||||||
|
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
expect(tree.exists('/apps/myApp/tsconfig.app.json')).toBe(true);
|
||||||
expect(tree.exists('/apps/myApp/karma.conf.js')).toBe(true);
|
expect(tree.exists('/apps/myApp/karma.conf.js')).toBe(true);
|
||||||
@ -416,7 +424,7 @@ describe('workspace', () => {
|
|||||||
|
|
||||||
it('should work with existing .prettierignore file', async () => {
|
it('should work with existing .prettierignore file', async () => {
|
||||||
tree.write('/.prettierignore', '# existing ignore rules');
|
tree.write('/.prettierignore', '# existing ignore rules');
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
const prettierIgnore = tree.read('/.prettierignore').toString();
|
const prettierIgnore = tree.read('/.prettierignore').toString();
|
||||||
expect(prettierIgnore).toBe('# existing ignore rules');
|
expect(prettierIgnore).toBe('# existing ignore rules');
|
||||||
@ -424,7 +432,7 @@ describe('workspace', () => {
|
|||||||
|
|
||||||
it('should update tsconfigs', async () => {
|
it('should update tsconfigs', async () => {
|
||||||
tree.write('/.prettierignore', '# existing ignore rules');
|
tree.write('/.prettierignore', '# existing ignore rules');
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
const prettierIgnore = tree.read('/.prettierignore').toString();
|
const prettierIgnore = tree.read('/.prettierignore').toString();
|
||||||
expect(prettierIgnore).toBe('# existing ignore rules');
|
expect(prettierIgnore).toBe('# existing ignore rules');
|
||||||
@ -432,7 +440,7 @@ describe('workspace', () => {
|
|||||||
|
|
||||||
it('should work with no root tslint.json', async () => {
|
it('should work with no root tslint.json', async () => {
|
||||||
tree.delete('/tslint.json');
|
tree.delete('/tslint.json');
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
expect(tree.exists('/tslint.json')).toBe(false);
|
expect(tree.exists('/tslint.json')).toBe(false);
|
||||||
});
|
});
|
||||||
@ -518,7 +526,7 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should migrate e2e tests correctly', async () => {
|
it('should migrate e2e tests correctly', async () => {
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
expect(tree.exists('cypress.json')).toBe(false);
|
expect(tree.exists('cypress.json')).toBe(false);
|
||||||
expect(tree.exists('cypress')).toBe(false);
|
expect(tree.exists('cypress')).toBe(false);
|
||||||
@ -550,7 +558,7 @@ describe('workspace', () => {
|
|||||||
updateProjectConfiguration(tree, 'myApp', project);
|
updateProjectConfiguration(tree, 'myApp', project);
|
||||||
tree.delete('cypress.json');
|
tree.delete('cypress.json');
|
||||||
|
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
expect(tree.exists('cypress.json')).toBe(false);
|
expect(tree.exists('cypress.json')).toBe(false);
|
||||||
expect(tree.exists('cypress')).toBe(false);
|
expect(tree.exists('cypress')).toBe(false);
|
||||||
@ -569,7 +577,7 @@ describe('workspace', () => {
|
|||||||
delete project.targets['cypress-open'];
|
delete project.targets['cypress-open'];
|
||||||
updateProjectConfiguration(tree, 'myApp', project);
|
updateProjectConfiguration(tree, 'myApp', project);
|
||||||
|
|
||||||
await initGenerator(tree, { name: 'myApp' });
|
await migrateFromAngularCli(tree, { name: 'myApp' });
|
||||||
|
|
||||||
expect(tree.exists('cypress.json')).toBe(false);
|
expect(tree.exists('cypress.json')).toBe(false);
|
||||||
expect(tree.exists('cypress')).toBe(false);
|
expect(tree.exists('cypress')).toBe(false);
|
||||||
@ -589,7 +597,7 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update package.json', async () => {
|
it('should update package.json', async () => {
|
||||||
await initGenerator(tree, {
|
await migrateFromAngularCli(tree, {
|
||||||
name: 'myApp',
|
name: 'myApp',
|
||||||
preserveAngularCliLayout: true,
|
preserveAngularCliLayout: true,
|
||||||
});
|
});
|
||||||
@ -600,7 +608,7 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create nx.json', async () => {
|
it('should create nx.json', async () => {
|
||||||
await initGenerator(tree, {
|
await migrateFromAngularCli(tree, {
|
||||||
name: 'myApp',
|
name: 'myApp',
|
||||||
preserveAngularCliLayout: true,
|
preserveAngularCliLayout: true,
|
||||||
});
|
});
|
||||||
@ -610,7 +618,7 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create decorate-angular-cli.js', async () => {
|
it('should create decorate-angular-cli.js', async () => {
|
||||||
await initGenerator(tree, {
|
await migrateFromAngularCli(tree, {
|
||||||
name: 'myApp',
|
name: 'myApp',
|
||||||
preserveAngularCliLayout: true,
|
preserveAngularCliLayout: true,
|
||||||
});
|
});
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
getProjects,
|
getProjects,
|
||||||
@ -12,30 +11,26 @@ import {
|
|||||||
normalizePath,
|
normalizePath,
|
||||||
NxJsonConfiguration,
|
NxJsonConfiguration,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
|
ProjectConfiguration,
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
readWorkspaceConfiguration,
|
readWorkspaceConfiguration,
|
||||||
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
updateWorkspaceConfiguration,
|
updateWorkspaceConfiguration,
|
||||||
visitNotIgnoredFiles,
|
visitNotIgnoredFiles,
|
||||||
writeJson,
|
writeJson,
|
||||||
ProjectConfiguration,
|
|
||||||
TargetConfiguration,
|
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { readFileSync } from 'fs';
|
import { DEFAULT_NRWL_PRETTIER_CONFIG } from '@nrwl/workspace/src/generators/workspace/workspace';
|
||||||
|
import { deduceDefaultBase } from '@nrwl/workspace/src/utilities/default-base';
|
||||||
|
import { resolveUserExistingPrettierConfig } from '@nrwl/workspace/src/utilities/prettier';
|
||||||
|
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||||
|
import { prettierVersion } from '@nrwl/workspace/src/utils/versions';
|
||||||
import { basename, relative } from 'path';
|
import { basename, relative } from 'path';
|
||||||
import { resolveUserExistingPrettierConfig } from '../../utilities/prettier';
|
import { angularDevkitVersion, nxVersion } from '../../utils/versions';
|
||||||
import { deduceDefaultBase } from '../../utilities/default-base';
|
|
||||||
import {
|
|
||||||
angularCliVersion,
|
|
||||||
nxVersion,
|
|
||||||
prettierVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import { DEFAULT_NRWL_PRETTIER_CONFIG } from '../workspace/workspace';
|
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { getRootTsConfigPathInTree } from '../../utilities/typescript';
|
|
||||||
|
|
||||||
function updatePackageJson(tree) {
|
function updatePackageJson(tree) {
|
||||||
updateJson(tree, 'package.json', (packageJson) => {
|
updateJson(tree, 'package.json', (packageJson) => {
|
||||||
@ -66,12 +61,14 @@ function updatePackageJson(tree) {
|
|||||||
if (!packageJson.dependencies['@nrwl/angular']) {
|
if (!packageJson.dependencies['@nrwl/angular']) {
|
||||||
packageJson.dependencies['@nrwl/angular'] = nxVersion;
|
packageJson.dependencies['@nrwl/angular'] = nxVersion;
|
||||||
}
|
}
|
||||||
delete packageJson.dependencies['@nrwl/workspace'];
|
if (!packageJson.devDependencies['@angular/cli']) {
|
||||||
|
packageJson.devDependencies['@angular/cli'] = angularDevkitVersion;
|
||||||
|
}
|
||||||
if (!packageJson.devDependencies['@nrwl/workspace']) {
|
if (!packageJson.devDependencies['@nrwl/workspace']) {
|
||||||
packageJson.devDependencies['@nrwl/workspace'] = nxVersion;
|
packageJson.devDependencies['@nrwl/workspace'] = nxVersion;
|
||||||
}
|
}
|
||||||
if (!packageJson.devDependencies['@angular/cli']) {
|
if (!packageJson.devDependencies['nx']) {
|
||||||
packageJson.devDependencies['@angular/cli'] = angularCliVersion;
|
packageJson.devDependencies['nx'] = nxVersion;
|
||||||
}
|
}
|
||||||
if (!packageJson.devDependencies['prettier']) {
|
if (!packageJson.devDependencies['prettier']) {
|
||||||
packageJson.devDependencies['prettier'] = prettierVersion;
|
packageJson.devDependencies['prettier'] = prettierVersion;
|
||||||
@ -623,25 +620,7 @@ function replaceCypressGlobConfig(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createAdditionalFiles(host: Tree, options: Schema) {
|
async function createAdditionalFiles(host: Tree) {
|
||||||
const nxJson: NxJsonConfiguration = {
|
|
||||||
npmScope: options.npmScope,
|
|
||||||
affected: {
|
|
||||||
defaultBase: options.defaultBase
|
|
||||||
? `${options.defaultBase}`
|
|
||||||
: deduceDefaultBase(),
|
|
||||||
},
|
|
||||||
implicitDependencies: {
|
|
||||||
'angular.json': '*',
|
|
||||||
'package.json': '*',
|
|
||||||
'tslint.json': '*',
|
|
||||||
'.eslintrc.json': '*',
|
|
||||||
'nx.json': '*',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
writeJson(host, 'nx.json', nxJson);
|
|
||||||
host.write('libs/.gitkeep', '');
|
|
||||||
|
|
||||||
const recommendations = [
|
const recommendations = [
|
||||||
'nrwl.angular-console',
|
'nrwl.angular-console',
|
||||||
'angular.ng-template',
|
'angular.ng-template',
|
||||||
@ -749,8 +728,7 @@ function checkCanConvertToWorkspace(host: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createNxJson(host: Tree) {
|
function createNxJson(host: Tree) {
|
||||||
const json = JSON.parse(host.read('angular.json').toString());
|
const { projects = {}, newProjectRoot = '' } = readJson(host, 'angular.json');
|
||||||
const projects = json.projects || {};
|
|
||||||
const hasLibraries = Object.keys(projects).find(
|
const hasLibraries = Object.keys(projects).find(
|
||||||
(project) =>
|
(project) =>
|
||||||
projects[project].projectType &&
|
projects[project].projectType &&
|
||||||
@ -782,19 +760,17 @@ function createNxJson(host: Tree) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
workspaceLayout: { appsDir: newProjectRoot, libsDir: newProjectRoot },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function decorateAngularClI(host: Tree) {
|
function decorateAngularCli(host: Tree) {
|
||||||
const decorateCli = readFileSync(
|
generateFiles(
|
||||||
joinPathFragments(
|
host,
|
||||||
__dirname as any,
|
joinPathFragments(__dirname, 'files', 'decorate-angular-cli'),
|
||||||
'..',
|
'.',
|
||||||
'utils',
|
{ tmpl: '' }
|
||||||
'decorate-angular-cli.js__tmpl__'
|
);
|
||||||
)
|
|
||||||
).toString();
|
|
||||||
host.write('decorate-angular-cli.js', decorateCli);
|
|
||||||
updateJson(host, 'package.json', (json) => {
|
updateJson(host, 'package.json', (json) => {
|
||||||
if (
|
if (
|
||||||
json.scripts &&
|
json.scripts &&
|
||||||
@ -815,11 +791,13 @@ function decorateAngularClI(host: Tree) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFiles(host: Tree) {
|
function addFiles(host: Tree, options: Schema) {
|
||||||
generateFiles(host, joinPathFragments(__dirname, './files/root'), '.', {
|
generateFiles(host, joinPathFragments(__dirname, './files/root'), '.', {
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
dot: '.',
|
dot: '.',
|
||||||
rootTsConfigPath: getRootTsConfigPathInTree(host),
|
rootTsConfigPath: getRootTsConfigPathInTree(host),
|
||||||
|
npmScope: options.npmScope,
|
||||||
|
defaultBase: options.defaultBase ?? deduceDefaultBase(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!host.exists('.prettierignore')) {
|
if (!host.exists('.prettierignore')) {
|
||||||
@ -857,15 +835,18 @@ function renameDirSyncInTree(tree: Tree, from: string, to: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initGenerator(tree: Tree, schema: Schema) {
|
export async function migrateFromAngularCli(tree: Tree, schema: Schema) {
|
||||||
if (schema.preserveAngularCliLayout) {
|
if (schema.preserveAngularCliLayout) {
|
||||||
updateJson(tree, 'package.json', (json) => {
|
addDependenciesToPackageJson(
|
||||||
delete json.dependencies?.['@nrwl/workspace'];
|
tree,
|
||||||
return json;
|
{},
|
||||||
});
|
{
|
||||||
addDependenciesToPackageJson(tree, {}, { '@nrwl/workspace': nxVersion });
|
nx: nxVersion,
|
||||||
|
'@nrwl/workspace': nxVersion,
|
||||||
|
}
|
||||||
|
);
|
||||||
createNxJson(tree);
|
createNxJson(tree);
|
||||||
decorateAngularClI(tree);
|
decorateAngularCli(tree);
|
||||||
} else {
|
} else {
|
||||||
const options = {
|
const options = {
|
||||||
...schema,
|
...schema,
|
||||||
@ -874,15 +855,15 @@ export async function initGenerator(tree: Tree, schema: Schema) {
|
|||||||
|
|
||||||
checkCanConvertToWorkspace(tree);
|
checkCanConvertToWorkspace(tree);
|
||||||
moveExistingFiles(tree, options);
|
moveExistingFiles(tree, options);
|
||||||
addFiles(tree);
|
addFiles(tree, options);
|
||||||
await createAdditionalFiles(tree, options);
|
await createAdditionalFiles(tree);
|
||||||
updatePackageJson(tree);
|
updatePackageJson(tree);
|
||||||
updateAngularCLIJson(tree, options);
|
updateAngularCLIJson(tree, options);
|
||||||
updateTsLint(tree);
|
updateTsLint(tree);
|
||||||
updateProjectTsLint(tree, options);
|
updateProjectTsLint(tree, options);
|
||||||
updateTsConfig(tree);
|
updateTsConfig(tree);
|
||||||
updateTsConfigsJson(tree, options);
|
updateTsConfigsJson(tree, options);
|
||||||
decorateAngularClI(tree);
|
decorateAngularCli(tree);
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
if (!schema.skipInstall) {
|
if (!schema.skipInstall) {
|
||||||
@ -891,7 +872,3 @@ export async function initGenerator(tree: Tree, schema: Schema) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initSchematic = convertNxGenerator(initGenerator);
|
|
||||||
|
|
||||||
export default initGenerator;
|
|
||||||
36
packages/angular/src/generators/ng-add/ng-add.spec.ts
Normal file
36
packages/angular/src/generators/ng-add/ng-add.spec.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import * as angularCliMigrator from './migrate-from-angular-cli';
|
||||||
|
import * as initGenerator from '../init/init';
|
||||||
|
import { ngAddGenerator } from './ng-add';
|
||||||
|
import { Tree } from '@nrwl/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
|
describe('ngAdd generator', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace(2);
|
||||||
|
jest
|
||||||
|
.spyOn(angularCliMigrator, 'migrateFromAngularCli')
|
||||||
|
.mockImplementation(() => Promise.resolve(() => {}));
|
||||||
|
jest
|
||||||
|
.spyOn(initGenerator, 'angularInitGenerator')
|
||||||
|
.mockImplementation(() => Promise.resolve(() => {}));
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize the Angular plugin when in an Nx workspace', async () => {
|
||||||
|
await ngAddGenerator(tree, {});
|
||||||
|
|
||||||
|
expect(initGenerator.angularInitGenerator).toHaveBeenCalled();
|
||||||
|
expect(angularCliMigrator.migrateFromAngularCli).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should perform a migration when in an Angular CLI workspace', async () => {
|
||||||
|
tree.delete('nx.json');
|
||||||
|
|
||||||
|
await ngAddGenerator(tree, {});
|
||||||
|
|
||||||
|
expect(angularCliMigrator.migrateFromAngularCli).toHaveBeenCalled();
|
||||||
|
expect(initGenerator.angularInitGenerator).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
18
packages/angular/src/generators/ng-add/ng-add.ts
Normal file
18
packages/angular/src/generators/ng-add/ng-add.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Tree } from '@nrwl/devkit';
|
||||||
|
import { migrateFromAngularCli } from './migrate-from-angular-cli';
|
||||||
|
import { angularInitGenerator } from '../init/init';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
|
||||||
|
function getWorkspaceType(tree: Tree): 'angular' | 'nx' {
|
||||||
|
return tree.exists('nx.json') ? 'nx' : 'angular';
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function ngAddGenerator(tree: Tree, options: Schema) {
|
||||||
|
if (getWorkspaceType(tree) === 'angular') {
|
||||||
|
return await migrateFromAngularCli(tree, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return angularInitGenerator(tree, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ngAddGenerator;
|
||||||
19
packages/angular/src/generators/ng-add/schema.d.ts
vendored
Normal file
19
packages/angular/src/generators/ng-add/schema.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Linter } from '@nrwl/linter';
|
||||||
|
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||||
|
import type { Styles } from '../utils/types';
|
||||||
|
|
||||||
|
export interface Schema {
|
||||||
|
name?: string;
|
||||||
|
skipInstall?: boolean;
|
||||||
|
npmScope?: string;
|
||||||
|
preserveAngularCliLayout?: boolean;
|
||||||
|
defaultBase?: string;
|
||||||
|
|
||||||
|
unitTestRunner?: UnitTestRunner;
|
||||||
|
e2eTestRunner?: E2eTestRunner;
|
||||||
|
skipFormat?: boolean;
|
||||||
|
skipInstall?: boolean;
|
||||||
|
style?: Styles;
|
||||||
|
linter?: Exclude<Linter, Linter.TsLint>;
|
||||||
|
skipPackageJson?: boolean;
|
||||||
|
}
|
||||||
71
packages/angular/src/generators/ng-add/schema.json
Normal file
71
packages/angular/src/generators/ng-add/schema.json
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"$id": "NxAngularNgAddGenerator",
|
||||||
|
"title": "Angular plugin initialization",
|
||||||
|
"cli": "nx",
|
||||||
|
"description": "Migrates an Angular CLI workspace to Nx or adds the Angular plugin to an Nx workspace. NOTE: Does not work in the `--dry-run` mode.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"npmScope": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Npm scope for importing libs. NOTE: only used if running the generator in an Angular CLI workspace."
|
||||||
|
},
|
||||||
|
"defaultBase": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Default base branch for affected. NOTE: only used if running the generator in an Angular CLI workspace."
|
||||||
|
},
|
||||||
|
"skipInstall": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Skip installing added packages.",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"preserveAngularCliLayout": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Preserve the Angular CLI layout instead of moving the app into apps. NOTE: only used if running the generator in an Angular CLI workspace.",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Project name. NOTE: only used if running the generator in an Angular CLI workspace.",
|
||||||
|
"$default": {
|
||||||
|
"$source": "projectName"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"unitTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["karma", "jest", "none"],
|
||||||
|
"description": "Test runner to use for unit tests. NOTE: only used if running the generator in an Nx workspace.",
|
||||||
|
"default": "jest"
|
||||||
|
},
|
||||||
|
"e2eTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["protractor", "cypress", "none"],
|
||||||
|
"description": "Test runner to use for end to end (e2e) tests. NOTE: only used if running the generator in an Nx workspace.",
|
||||||
|
"default": "cypress"
|
||||||
|
},
|
||||||
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files. NOTE: only used if running the generator in an Nx workspace.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks. NOTE: only used if running the generator in an Nx workspace.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "eslint"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"description": "The file extension to be used for style files. NOTE: only used if running the generator in an Nx workspace.",
|
||||||
|
"type": "string",
|
||||||
|
"default": "css",
|
||||||
|
"enum": ["css", "scss", "sass", "less"]
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Do not add dependencies to `package.json`. NOTE: only used if running the generator in an Nx workspace."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
@ -16,8 +16,10 @@
|
|||||||
"Cypress",
|
"Cypress",
|
||||||
"CLI"
|
"CLI"
|
||||||
],
|
],
|
||||||
|
"main": "src/index.js",
|
||||||
|
"typings": "src/index.d.ts",
|
||||||
"bin": {
|
"bin": {
|
||||||
"make-angular-cli-faster": "./make-angular-cli-faster.js"
|
"make-angular-cli-faster": "./src/index.js"
|
||||||
},
|
},
|
||||||
"author": "Victor Savkin",
|
"author": "Victor Savkin",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -26,9 +28,13 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://nx.dev",
|
"homepage": "https://nx.dev",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yargs-parser": "20.0.0",
|
"@nrwl/devkit": "*",
|
||||||
"yargs": "15.4.1",
|
"@nrwl/workspace": "*",
|
||||||
"enquirer": "^2.3.6",
|
"enquirer": "^2.3.6",
|
||||||
"@nrwl/workspace": "*"
|
"nx": "*",
|
||||||
|
"semver": "7.3.4",
|
||||||
|
"tmp": "~0.2.1",
|
||||||
|
"yargs": "15.4.1",
|
||||||
|
"yargs-parser": "20.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"command": "node ./scripts/chmod build/packages/make-angular-cli-faster/src/make-angular-cli-faster.js"
|
"command": "node ./scripts/chmod build/packages/make-angular-cli-faster/src/index.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "node ./scripts/copy-readme.js make-angular-cli-faster"
|
"command": "node ./scripts/copy-readme.js make-angular-cli-faster"
|
||||||
|
|||||||
21
packages/make-angular-cli-faster/src/index.ts
Normal file
21
packages/make-angular-cli-faster/src/index.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import * as yargsParser from 'yargs-parser';
|
||||||
|
import {
|
||||||
|
Args,
|
||||||
|
makeAngularCliFaster,
|
||||||
|
} from './utilities/make-angular-cli-faster';
|
||||||
|
|
||||||
|
const args = yargsParser(process.argv, {
|
||||||
|
string: ['version'],
|
||||||
|
boolean: ['verbose'],
|
||||||
|
});
|
||||||
|
|
||||||
|
makeAngularCliFaster(args as Args)
|
||||||
|
.then(() => {
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@ -1,94 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
import { statSync } from 'fs';
|
|
||||||
import { execSync } from 'child_process';
|
|
||||||
import * as yargsParser from 'yargs-parser';
|
|
||||||
|
|
||||||
const enquirer = require('enquirer');
|
|
||||||
|
|
||||||
const parsedArgs = yargsParser(process.argv, {
|
|
||||||
string: ['version'],
|
|
||||||
boolean: ['verbose'],
|
|
||||||
});
|
|
||||||
|
|
||||||
function isYarn() {
|
|
||||||
try {
|
|
||||||
statSync('yarn.lock');
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addDependency(dep: string) {
|
|
||||||
const stdio = parsedArgs.verbose ? [0, 1, 2] : ['ignore', 'ignore', 'ignore'];
|
|
||||||
if (isYarn()) {
|
|
||||||
execSync(`yarn add -D ${dep}`, { stdio: stdio as any });
|
|
||||||
} else {
|
|
||||||
execSync(`npm i --save-dev ${dep}`, { stdio: stdio as any });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addNxCloud() {
|
|
||||||
return enquirer
|
|
||||||
.prompt([
|
|
||||||
{
|
|
||||||
name: 'NxCloud',
|
|
||||||
message: `Use the free tier of the distributed cache provided by Nx Cloud?`,
|
|
||||||
type: 'list',
|
|
||||||
choices: [
|
|
||||||
{
|
|
||||||
value: 'yes',
|
|
||||||
name: 'Yes [Faster command execution, faster CI. Learn more at https://nx.app]',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
value: 'no',
|
|
||||||
name: 'No [Only use local computation cache]',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
default: 'no',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.then((a: { NxCloud: 'yes' | 'no' }) => a.NxCloud === 'yes');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const version = parsedArgs.version ? parsedArgs.version : `latest`;
|
|
||||||
|
|
||||||
const output = require('@nrwl/workspace/src/utils/output').output;
|
|
||||||
output.log({ title: 'Nx initialization' });
|
|
||||||
|
|
||||||
addDependency(`nx@${version}`);
|
|
||||||
addDependency(`@nrwl/cli@${version}`);
|
|
||||||
addDependency(`@nrwl/workspace@${version}`);
|
|
||||||
execSync(`nx g @nrwl/workspace:ng-add --preserve-angular-cli-layout`, {
|
|
||||||
stdio: [0, 1, 2],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (await addNxCloud()) {
|
|
||||||
output.log({ title: 'Nx Cloud initialization' });
|
|
||||||
addDependency(`@nrwl/nx-cloud`);
|
|
||||||
execSync(`nx g @nrwl/nx-cloud:init`, { stdio: [0, 1, 2] });
|
|
||||||
}
|
|
||||||
|
|
||||||
execSync('npm install', { stdio: ['ignore', 'ignore', 'ignore'] });
|
|
||||||
|
|
||||||
output.success({
|
|
||||||
title: 'Angular CLI is faster now!',
|
|
||||||
bodyLines: [
|
|
||||||
`Execute 'npx ng build' twice to see the computation caching in action.`,
|
|
||||||
`Learn more about computation caching, how it is shared with your teammates,`,
|
|
||||||
`and how it can speed up your CI by up to 10 times at https://nx.dev/angular`,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
.then(() => {
|
|
||||||
process.exit(0);
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { output } from '@nrwl/workspace/src/utilities/output';
|
||||||
|
import { determineMigration, migrateWorkspace } from './migration';
|
||||||
|
import { initNxCloud, promptForNxCloud } from './nx-cloud';
|
||||||
|
import { installDependencies } from './package-manager';
|
||||||
|
|
||||||
|
export interface Args {
|
||||||
|
version?: string;
|
||||||
|
verbose?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function makeAngularCliFaster(args: Args) {
|
||||||
|
output.log({ title: '🐳 Nx initialization' });
|
||||||
|
|
||||||
|
output.log({ title: '🧐 Checking versions compatibility' });
|
||||||
|
const migration = await determineMigration(args.version);
|
||||||
|
|
||||||
|
const useNxCloud = await promptForNxCloud();
|
||||||
|
|
||||||
|
output.log({ title: '📦 Installing dependencies' });
|
||||||
|
installDependencies(migration, useNxCloud);
|
||||||
|
|
||||||
|
output.log({ title: '📝 Setting up workspace for faster computation' });
|
||||||
|
migrateWorkspace(migration);
|
||||||
|
|
||||||
|
if (useNxCloud) {
|
||||||
|
output.log({ title: '🛠️ Setting up Nx Cloud' });
|
||||||
|
initNxCloud();
|
||||||
|
}
|
||||||
|
|
||||||
|
output.success({
|
||||||
|
title: '🎉 Angular CLI is faster now!',
|
||||||
|
bodyLines: [
|
||||||
|
`Execute 'npx ng build' twice to see the computation caching in action.`,
|
||||||
|
'Learn more about computation caching, how it is shared with your teammates,' +
|
||||||
|
' and how it can speed up your CI by up to 10 times at https://nx.dev/getting-started/nx-and-angular',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
182
packages/make-angular-cli-faster/src/utilities/migration.ts
Normal file
182
packages/make-angular-cli-faster/src/utilities/migration.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import { getPackageManagerCommand, readJsonFile } from '@nrwl/devkit';
|
||||||
|
import { output } from '@nrwl/workspace/src/utilities/output';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { prompt } from 'enquirer';
|
||||||
|
import { appRootPath } from 'nx/src/utils/app-root';
|
||||||
|
import { lt, lte, major, satisfies } from 'semver';
|
||||||
|
import { resolvePackageVersion } from './package-manager';
|
||||||
|
import { MigrationDefinition } from './types';
|
||||||
|
|
||||||
|
// up to this version the generator was in the @nrwl/workspace package
|
||||||
|
const latestWorkspaceVersionWithMigration = '13.9.3';
|
||||||
|
// up to this version the preserveAngularCLILayout option was used
|
||||||
|
const latestVersionWithOldFlag = '13.8.3';
|
||||||
|
// map of Angular major versions to the versions of Nx that are compatible with them,
|
||||||
|
// key is the Angular major version, value is an object with the range of supported
|
||||||
|
// versions and the max version of the range if there's a bigger major version that
|
||||||
|
// is already supported
|
||||||
|
const nxAngularVersionMap: Record<number, { range: string; max?: string }> = {
|
||||||
|
13: { range: '>= 13.2.0' },
|
||||||
|
};
|
||||||
|
// latest major version of Angular that is compatible with Nx, based on the map above
|
||||||
|
const latestCompatibleAngularMajorVersion = Math.max(
|
||||||
|
...Object.keys(nxAngularVersionMap).map((x) => +x)
|
||||||
|
);
|
||||||
|
|
||||||
|
export async function determineMigration(
|
||||||
|
version: string | undefined
|
||||||
|
): Promise<MigrationDefinition> {
|
||||||
|
const angularVersion = getInstalledAngularVersion();
|
||||||
|
const majorAngularVersion = major(angularVersion);
|
||||||
|
|
||||||
|
if (version) {
|
||||||
|
const normalizedVersion = normalizeVersion(version);
|
||||||
|
if (lte(normalizedVersion, latestWorkspaceVersionWithMigration)) {
|
||||||
|
// specified version should use @nrwl/workspace:ng-add
|
||||||
|
return { packageName: '@nrwl/workspace', version: normalizedVersion };
|
||||||
|
}
|
||||||
|
|
||||||
|
// if greater than the latest workspace version with the migration,
|
||||||
|
// check the versions map for compatibility with Angular
|
||||||
|
if (
|
||||||
|
nxAngularVersionMap[majorAngularVersion] &&
|
||||||
|
satisfies(
|
||||||
|
normalizedVersion,
|
||||||
|
nxAngularVersionMap[majorAngularVersion].range
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// there's a match, use @nrwl/angular:ng-add
|
||||||
|
return { packageName: '@nrwl/angular', version: normalizedVersion };
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's not compatible with the currently installed Angular version,
|
||||||
|
// suggest the latest possible version to use
|
||||||
|
return await findAndSuggestVersionToUse(
|
||||||
|
angularVersion,
|
||||||
|
majorAngularVersion,
|
||||||
|
version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestNxCompatibleVersion = getNxVersionBasedOnInstalledAngularVersion(
|
||||||
|
angularVersion,
|
||||||
|
majorAngularVersion
|
||||||
|
);
|
||||||
|
|
||||||
|
// should use @nrwl/workspace:ng-add if the version is less than the
|
||||||
|
// latest workspace version that has the migration, otherwise use
|
||||||
|
// @nrwl/angular:ng-add
|
||||||
|
return {
|
||||||
|
packageName: lte(
|
||||||
|
latestNxCompatibleVersion,
|
||||||
|
latestWorkspaceVersionWithMigration
|
||||||
|
)
|
||||||
|
? '@nrwl/workspace'
|
||||||
|
: '@nrwl/angular',
|
||||||
|
version: latestNxCompatibleVersion,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function migrateWorkspace(migration: MigrationDefinition): void {
|
||||||
|
const preserveAngularCliLayoutFlag = lte(
|
||||||
|
migration.version,
|
||||||
|
latestVersionWithOldFlag
|
||||||
|
)
|
||||||
|
? '--preserveAngularCLILayout'
|
||||||
|
: '--preserve-angular-cli-layout';
|
||||||
|
execSync(
|
||||||
|
`${getPackageManagerCommand().exec} nx g ${
|
||||||
|
migration.packageName
|
||||||
|
}:ng-add ${preserveAngularCliLayoutFlag}`,
|
||||||
|
{ stdio: [0, 1, 2] }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findAndSuggestVersionToUse(
|
||||||
|
angularVersion: string,
|
||||||
|
majorAngularVersion: number,
|
||||||
|
userSpecifiedVersion: string
|
||||||
|
): Promise<MigrationDefinition> {
|
||||||
|
const latestNxCompatibleVersion = getNxVersionBasedOnInstalledAngularVersion(
|
||||||
|
angularVersion,
|
||||||
|
majorAngularVersion
|
||||||
|
);
|
||||||
|
const useSuggestedVersion = await promptForVersion(latestNxCompatibleVersion);
|
||||||
|
if (useSuggestedVersion) {
|
||||||
|
// should use @nrwl/workspace:ng-add if the version is less than the
|
||||||
|
// latest workspace version that has the migration, otherwise use
|
||||||
|
// @nrwl/angular:ng-add
|
||||||
|
return {
|
||||||
|
packageName: lte(
|
||||||
|
latestNxCompatibleVersion,
|
||||||
|
latestWorkspaceVersionWithMigration
|
||||||
|
)
|
||||||
|
? '@nrwl/workspace'
|
||||||
|
: '@nrwl/angular',
|
||||||
|
version: latestNxCompatibleVersion,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
output.error({
|
||||||
|
title: `❌ Cannot proceed with the migration.`,
|
||||||
|
bodyLines: [
|
||||||
|
`The specified Nx version "${userSpecifiedVersion}" is not compatible with the installed Angular version "${angularVersion}".`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNxVersionBasedOnInstalledAngularVersion(
|
||||||
|
angularVersion: string,
|
||||||
|
majorAngularVersion: number
|
||||||
|
): string {
|
||||||
|
if (lt(angularVersion, '13.0.0')) {
|
||||||
|
// the @nrwl/angular:ng-add generator is only available for versions supporting
|
||||||
|
// Angular >= 13.0.0, fall back to @nrwl/workspace:ng-add
|
||||||
|
return latestWorkspaceVersionWithMigration;
|
||||||
|
}
|
||||||
|
if (nxAngularVersionMap[majorAngularVersion]?.max) {
|
||||||
|
// use the max of the range
|
||||||
|
return nxAngularVersionMap[majorAngularVersion].max;
|
||||||
|
}
|
||||||
|
if (majorAngularVersion > latestCompatibleAngularMajorVersion) {
|
||||||
|
// installed Angular version is not supported yet, we can't @nrwl/angular:ng-add,
|
||||||
|
// fall back to @nrwl/workspace:ng-add
|
||||||
|
return latestWorkspaceVersionWithMigration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use latest, only the last version in the map should not contain a max
|
||||||
|
return resolvePackageVersion('@nrwl/angular', 'latest');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function promptForVersion(version: string): Promise<boolean> {
|
||||||
|
const { useVersion } = await prompt<{ useVersion: boolean }>([
|
||||||
|
{
|
||||||
|
name: 'useVersion',
|
||||||
|
message: `The provided version of Nx is not compatible with the installed Angular CLI version. Would you like to use the recommended version "${version}" instead?`,
|
||||||
|
type: 'confirm',
|
||||||
|
initial: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
return useVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInstalledAngularVersion(): string {
|
||||||
|
const packageJsonPath = require.resolve('@angular/core/package.json', {
|
||||||
|
paths: [appRootPath],
|
||||||
|
});
|
||||||
|
return readJsonFile(packageJsonPath).version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeVersion(version: string): string {
|
||||||
|
if (
|
||||||
|
version.startsWith('^') ||
|
||||||
|
version.startsWith('~') ||
|
||||||
|
version.split('.').length < 3
|
||||||
|
) {
|
||||||
|
return resolvePackageVersion('@nrwl/angular', version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
29
packages/make-angular-cli-faster/src/utilities/nx-cloud.ts
Normal file
29
packages/make-angular-cli-faster/src/utilities/nx-cloud.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { getPackageManagerCommand } from '@nrwl/devkit';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { prompt } from 'enquirer';
|
||||||
|
|
||||||
|
export async function promptForNxCloud(): Promise<boolean> {
|
||||||
|
const { useNxCloud } = await prompt<{ useNxCloud: 'Yes' | 'No' }>([
|
||||||
|
{
|
||||||
|
name: 'useNxCloud',
|
||||||
|
message: `Use Nx Cloud? (It's free and doesn't require registration.)`,
|
||||||
|
type: 'select',
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: 'Yes',
|
||||||
|
hint: 'Yes [Faster builds, run details, Github integration. Learn more at https://nx.app]',
|
||||||
|
},
|
||||||
|
{ name: 'No' },
|
||||||
|
],
|
||||||
|
initial: 'Yes' as any,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
return useNxCloud === 'Yes';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initNxCloud(): void {
|
||||||
|
execSync(`${getPackageManagerCommand().exec} nx g @nrwl/nx-cloud:init`, {
|
||||||
|
stdio: [0, 1, 2],
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
import {
|
||||||
|
getPackageManagerCommand,
|
||||||
|
readJsonFile,
|
||||||
|
writeJsonFile,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { copyFileSync, existsSync, unlinkSync, writeFileSync } from 'fs';
|
||||||
|
import { appRootPath } from 'nx/src/utils/app-root';
|
||||||
|
import { sortObjectByKeys } from 'nx/src/utils/object-sort';
|
||||||
|
import { dirname, join } from 'path';
|
||||||
|
import { gte, lt, major } from 'semver';
|
||||||
|
import { dirSync } from 'tmp';
|
||||||
|
import { MigrationDefinition } from './types';
|
||||||
|
|
||||||
|
// version when the Nx CLI changed from @nrwl/tao & @nrwl/cli to nx
|
||||||
|
const versionWithConsolidatedPackages = '13.9.0';
|
||||||
|
|
||||||
|
export function installDependencies(
|
||||||
|
{ packageName, version }: MigrationDefinition,
|
||||||
|
useNxCloud: boolean
|
||||||
|
): void {
|
||||||
|
const json = readJsonFile(join(appRootPath, 'package.json'));
|
||||||
|
|
||||||
|
json.devDependencies ??= {};
|
||||||
|
json.devDependencies['@nrwl/workspace'] = version;
|
||||||
|
|
||||||
|
if (gte(version, versionWithConsolidatedPackages)) {
|
||||||
|
json.devDependencies['nx'] = version;
|
||||||
|
} else {
|
||||||
|
json.devDependencies['@nrwl/cli'] = version;
|
||||||
|
json.devDependencies['@nrwl/tao'] = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useNxCloud) {
|
||||||
|
// get the latest @nrwl/nx-cloud version compatible with the Nx major
|
||||||
|
// version being installed
|
||||||
|
json.devDependencies['@nrwl/nx-cloud'] = resolvePackageVersion(
|
||||||
|
'@nrwl/nx-cloud',
|
||||||
|
`^${major(version)}.0.0`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
json.devDependencies = sortObjectByKeys(json.devDependencies);
|
||||||
|
|
||||||
|
if (packageName === '@nrwl/angular') {
|
||||||
|
json.dependencies ??= {};
|
||||||
|
json.dependencies['@nrwl/angular'] = version;
|
||||||
|
json.dependencies = sortObjectByKeys(json.dependencies);
|
||||||
|
}
|
||||||
|
writeFileSync(`package.json`, JSON.stringify(json, null, 2));
|
||||||
|
|
||||||
|
execSync(getPackageManagerCommand().install, {
|
||||||
|
stdio: [0, 1, 2],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolvePackageVersion(
|
||||||
|
packageName: string,
|
||||||
|
version: string
|
||||||
|
): string {
|
||||||
|
const dir = dirSync().name;
|
||||||
|
const npmrc = checkForNPMRC();
|
||||||
|
if (npmrc) {
|
||||||
|
// Creating a package.json is needed for .npmrc to resolve
|
||||||
|
writeJsonFile(`${dir}/package.json`, {});
|
||||||
|
// Copy npmrc if it exists, so that npm still follows it.
|
||||||
|
copyFileSync(npmrc, `${dir}/.npmrc`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pmc = getPackageManagerCommand();
|
||||||
|
execSync(`${pmc.add} ${packageName}@${version}`, { stdio: [], cwd: dir });
|
||||||
|
|
||||||
|
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
|
||||||
|
paths: [dir],
|
||||||
|
});
|
||||||
|
const { version: resolvedVersion } = readJsonFile(packageJsonPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
unlinkSync(dir);
|
||||||
|
} catch {
|
||||||
|
// It's okay if this fails, the OS will clean it up eventually
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForNPMRC(): string | null {
|
||||||
|
let directory = process.cwd();
|
||||||
|
while (!existsSync(join(directory, 'package.json'))) {
|
||||||
|
directory = dirname(directory);
|
||||||
|
}
|
||||||
|
const path = join(directory, '.npmrc');
|
||||||
|
return existsSync(path) ? path : null;
|
||||||
|
}
|
||||||
4
packages/make-angular-cli-faster/src/utilities/types.ts
Normal file
4
packages/make-angular-cli-faster/src/utilities/types.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface MigrationDefinition {
|
||||||
|
packageName: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
@ -9,13 +9,6 @@
|
|||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"ng-add": {
|
|
||||||
"factory": "./src/generators/init/init#initSchematic",
|
|
||||||
"schema": "./src/generators/init/schema.json",
|
|
||||||
"description": "Convert an existing Angular CLI project into an Nx Workspace",
|
|
||||||
"hidden": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"preset": {
|
"preset": {
|
||||||
"factory": "./src/generators/preset/preset#presetSchematic",
|
"factory": "./src/generators/preset/preset#presetSchematic",
|
||||||
"schema": "./src/generators/preset/schema.json",
|
"schema": "./src/generators/preset/schema.json",
|
||||||
@ -87,13 +80,6 @@
|
|||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"ng-add": {
|
|
||||||
"factory": "./src/generators/init/init#initGenerator",
|
|
||||||
"schema": "./src/generators/init/schema.json",
|
|
||||||
"description": "Convert an existing Angular CLI project into an Nx Workspace",
|
|
||||||
"hidden": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"preset": {
|
"preset": {
|
||||||
"factory": "./src/generators/preset/preset#presetGenerator",
|
"factory": "./src/generators/preset/preset#presetGenerator",
|
||||||
"schema": "./src/generators/preset/schema.json",
|
"schema": "./src/generators/preset/schema.json",
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
export interface Schema {
|
|
||||||
name: string;
|
|
||||||
skipInstall?: boolean;
|
|
||||||
npmScope?: string;
|
|
||||||
preserveAngularCliLayout?: boolean;
|
|
||||||
defaultBase?: string;
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "http://json-schema.org/schema",
|
|
||||||
"$id": "SchematicsNxNgAdd",
|
|
||||||
"title": "Init Workspace",
|
|
||||||
"cli": "ng",
|
|
||||||
"description": "NOTE: Does not work in the --dry-run mode",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"npmScope": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Npm scope for importing libs."
|
|
||||||
},
|
|
||||||
"defaultBase": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Default base branch for affected."
|
|
||||||
},
|
|
||||||
"skipInstall": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Skip installing after adding @nrwl/workspace",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"preserveAngularCliLayout": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Preserve the Angular CLI layout instead of moving the app into apps.",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Project name.",
|
|
||||||
"$default": {
|
|
||||||
"$source": "projectName"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -116,6 +116,7 @@ const IGNORE_MATCHES = {
|
|||||||
'@nrwl/devkit',
|
'@nrwl/devkit',
|
||||||
],
|
],
|
||||||
nest: ['semver'],
|
nest: ['semver'],
|
||||||
|
'make-angular-cli-faster': ['@angular/core'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function getMissingDependencies(
|
export default async function getMissingDependencies(
|
||||||
|
|||||||
@ -189,7 +189,6 @@ function build(nxVersion: string) {
|
|||||||
].map((f) => `${f}/package.json`),
|
].map((f) => `${f}/package.json`),
|
||||||
'create-nx-workspace/bin/create-nx-workspace.js',
|
'create-nx-workspace/bin/create-nx-workspace.js',
|
||||||
'create-nx-plugin/bin/create-nx-plugin.js',
|
'create-nx-plugin/bin/create-nx-plugin.js',
|
||||||
'make-angular-cli-faster/src/make-angular-cli-faster.js',
|
|
||||||
'add-nx-to-monorepo/src/add-nx-to-monorepo.js',
|
'add-nx-to-monorepo/src/add-nx-to-monorepo.js',
|
||||||
].map((f) => `${BUILD_DIR}/${f}`);
|
].map((f) => `${BUILD_DIR}/${f}`);
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,6 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
|
|||||||
sed -i "" "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
sed -i "" "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
||||||
sed -i "" "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
sed -i "" "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
||||||
sed -i "" "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
sed -i "" "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
||||||
sed -i "" "s|NX_VERSION|$NX_VERSION|g" make-angular-cli-faster/src/make-angular-cli-faster.js
|
|
||||||
sed -i "" "s|NX_VERSION|$NX_VERSION|g" add-nx-to-monorepo/src/add-nx-to-monorepo.js
|
sed -i "" "s|NX_VERSION|$NX_VERSION|g" add-nx-to-monorepo/src/add-nx-to-monorepo.js
|
||||||
else
|
else
|
||||||
sed -i "s|exports.nxVersion = '\*';|exports.nxVersion = '$NX_VERSION';|g" {react,next,web,jest,node,linter,express,nest,cypress,storybook,angular,workspace,nx-plugin,react-native,detox,js}/src/utils/versions.js
|
sed -i "s|exports.nxVersion = '\*';|exports.nxVersion = '$NX_VERSION';|g" {react,next,web,jest,node,linter,express,nest,cypress,storybook,angular,workspace,nx-plugin,react-native,detox,js}/src/utils/versions.js
|
||||||
@ -41,7 +40,6 @@ else
|
|||||||
sed -i "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
sed -i "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
||||||
sed -i "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
sed -i "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
||||||
sed -i "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
sed -i "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" create-nx-plugin/bin/create-nx-plugin.js
|
||||||
sed -i "s|NX_VERSION|$NX_VERSION|g" make-angular-cli-faster/src/make-angular-cli-faster.js
|
|
||||||
sed -i "s|NX_VERSION|$NX_VERSION|g" add-nx-to-monorepo/src/add-nx-to-monorepo.js
|
sed -i "s|NX_VERSION|$NX_VERSION|g" add-nx-to-monorepo/src/add-nx-to-monorepo.js
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user