feat(react): migrate @nrwl/web schematics to devkit (#4666)
This commit is contained in:
parent
a500088d36
commit
06f84b3326
@ -7,13 +7,14 @@ packages/workspace/src/generators/**/files/**/*.json
|
|||||||
packages/workspace/src/core/dep-graph/vendor.js
|
packages/workspace/src/core/dep-graph/vendor.js
|
||||||
packages/angular/src/schematics/**/files/**/*.json
|
packages/angular/src/schematics/**/files/**/*.json
|
||||||
packages/angular/src/migrations/**/files/**/*.json
|
packages/angular/src/migrations/**/files/**/*.json
|
||||||
packages/web/src/schematics/**/files/**/*.json
|
packages/web/src/generators/**/files/**/*.json
|
||||||
packages/node/src/schematics/**/files/**/*.json
|
packages/node/src/schematics/**/files/**/*.json
|
||||||
packages/express/src/schematics/**/files/**/*.json
|
packages/express/src/schematics/**/files/**/*.json
|
||||||
packages/nest/src/schematics/**/files/**/*.json
|
packages/nest/src/schematics/**/files/**/*.json
|
||||||
packages/react/src/schematics/**/files/**/*.json
|
packages/react/src/schematics/**/files/**/*.json
|
||||||
packages/jest/src/schematics/**/files/**/*.json
|
packages/jest/src/schematics/**/files/**/*.json
|
||||||
packages/**/schematics/**/files/**/*.html
|
packages/**/schematics/**/files/**/*.html
|
||||||
|
packages/**/generators/**/files/**/*.html
|
||||||
/.vscode
|
/.vscode
|
||||||
/.idea
|
/.idea
|
||||||
/.github
|
/.github
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"init": {
|
"init": {
|
||||||
"factory": "./src/generators/init/init#initSchematic",
|
"factory": "./src/generators/init/init#cypressInitSchematic",
|
||||||
"schema": "./src/generators/init/schema.json",
|
"schema": "./src/generators/init/schema.json",
|
||||||
"description": "Initialize the @nrwl/cypress plugin",
|
"description": "Initialize the @nrwl/cypress plugin",
|
||||||
"aliases": ["ng-add"],
|
"aliases": ["ng-add"],
|
||||||
@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"generators": {
|
"generators": {
|
||||||
"init": {
|
"init": {
|
||||||
"factory": "./src/generators/init/init#initGenerator",
|
"factory": "./src/generators/init/init#cypressInitGenerator",
|
||||||
"schema": "./src/generators/init/schema.json",
|
"schema": "./src/generators/init/schema.json",
|
||||||
"description": "Initialize the @nrwl/cypress plugin",
|
"description": "Initialize the @nrwl/cypress plugin",
|
||||||
"aliases": ["ng-add"],
|
"aliases": ["ng-add"],
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
export { cypressProjectGenerator } from './src/generators/cypress-project/cypress-project';
|
export { cypressProjectGenerator } from './src/generators/cypress-project/cypress-project';
|
||||||
|
export { cypressInitGenerator } from './src/generators/init/init';
|
||||||
|
|||||||
@ -76,7 +76,7 @@ async function addLinter(host: Tree, options: CypressProjectSchema) {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (options.linter !== Linter.EsLint) {
|
if (!options.linter || options.linter !== Linter.EsLint) {
|
||||||
return installTask;
|
return installTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +127,8 @@ function normalizeOptions(host: Tree, options: Schema): CypressProjectSchema {
|
|||||||
options.name
|
options.name
|
||||||
)
|
)
|
||||||
: joinPathFragments(appsDir, options.name);
|
: joinPathFragments(appsDir, options.name);
|
||||||
|
|
||||||
|
options.linter = options.linter || Linter.EsLint;
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
projectName,
|
projectName,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export interface Schema {
|
|||||||
project?: string;
|
project?: string;
|
||||||
name: string;
|
name: string;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
linter: Linter;
|
linter?: Linter;
|
||||||
js?: boolean;
|
js?: boolean;
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { readJson, Tree, updateJson } from '@nrwl/devkit';
|
|||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
import { cypressVersion } from '../../utils/versions';
|
import { cypressVersion } from '../../utils/versions';
|
||||||
import initGenerator from './init';
|
import { cypressInitGenerator } from './init';
|
||||||
|
|
||||||
describe('init', () => {
|
describe('init', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
@ -21,7 +21,7 @@ describe('init', () => {
|
|||||||
json.devDependencies[existing] = existingVersion;
|
json.devDependencies[existing] = existingVersion;
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
initGenerator(tree);
|
cypressInitGenerator(tree);
|
||||||
const packageJson = readJson(tree, 'package.json');
|
const packageJson = readJson(tree, 'package.json');
|
||||||
|
|
||||||
expect(packageJson.devDependencies.cypress).toBeDefined();
|
expect(packageJson.devDependencies.cypress).toBeDefined();
|
||||||
|
|||||||
@ -24,9 +24,9 @@ function updateDependencies(host: Tree) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initGenerator(host: Tree) {
|
export function cypressInitGenerator(host: Tree) {
|
||||||
return updateDependencies(host);
|
return updateDependencies(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default initGenerator;
|
export default cypressInitGenerator;
|
||||||
export const initSchematic = convertNxGenerator(initGenerator);
|
export const cypressInitSchematic = convertNxGenerator(cypressInitGenerator);
|
||||||
|
|||||||
@ -4,3 +4,4 @@ export {
|
|||||||
} from './src/utils/config/update-config';
|
} from './src/utils/config/update-config';
|
||||||
export { jestConfigObjectAst } from './src/utils/config/functions';
|
export { jestConfigObjectAst } from './src/utils/config/functions';
|
||||||
export { jestProjectGenerator } from './src/generators/jest-project/jest-project';
|
export { jestProjectGenerator } from './src/generators/jest-project/jest-project';
|
||||||
|
export { jestInitGenerator } from './src/generators/init/init';
|
||||||
|
|||||||
@ -23,6 +23,10 @@ function normalizeOptions(options: JestProjectSchema) {
|
|||||||
options.testEnvironment = '';
|
options.testEnvironment = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.hasOwnProperty('supportTsx')) {
|
||||||
|
options.supportTsx = false;
|
||||||
|
}
|
||||||
|
|
||||||
// if we support TSX or babelJest we don't support angular(html templates)
|
// if we support TSX or babelJest we don't support angular(html templates)
|
||||||
if (options.supportTsx || options.babelJest) {
|
if (options.supportTsx || options.babelJest) {
|
||||||
options.skipSerializers = true;
|
options.skipSerializers = true;
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
export interface JestProjectSchema {
|
export interface JestProjectSchema {
|
||||||
project: string;
|
project: string;
|
||||||
supportTsx: boolean;
|
supportTsx?: boolean;
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
skipSetupFile: boolean;
|
skipSetupFile?: boolean;
|
||||||
setupFile: 'angular' | 'web-components' | 'none';
|
setupFile?: 'angular' | 'web-components' | 'none';
|
||||||
skipSerializers: boolean;
|
skipSerializers?: boolean;
|
||||||
testEnvironment?: 'node' | 'jsdom' | '';
|
testEnvironment?: 'node' | 'jsdom' | '';
|
||||||
babelJest: boolean;
|
babelJest?: boolean;
|
||||||
skipFormat: boolean;
|
skipFormat?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import {
|
|||||||
import { Linter } from '../utils/linter';
|
import { Linter } from '../utils/linter';
|
||||||
|
|
||||||
export interface LinterInitOptions {
|
export interface LinterInitOptions {
|
||||||
linter: Linter;
|
linter?: Linter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalTsLintConfiguration = {
|
const globalTsLintConfiguration = {
|
||||||
@ -197,9 +197,9 @@ function initEsLint(tree: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function lintInitGenerator(tree: Tree, options: LinterInitOptions) {
|
export function lintInitGenerator(tree: Tree, options: LinterInitOptions) {
|
||||||
if (options.linter === Linter.TsLint) {
|
if (!options.linter || options.linter === Linter.EsLint) {
|
||||||
return initTsLint(tree);
|
|
||||||
} else if (options.linter === Linter.EsLint) {
|
|
||||||
return initEsLint(tree);
|
return initEsLint(tree);
|
||||||
|
} else if (options.linter === Linter.TsLint) {
|
||||||
|
return initTsLint(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { lintInitGenerator } from '../init/init';
|
|||||||
|
|
||||||
interface LintProjectOptions {
|
interface LintProjectOptions {
|
||||||
project: string;
|
project: string;
|
||||||
linter: Linter;
|
linter?: Linter;
|
||||||
eslintFilePatterns?: string[];
|
eslintFilePatterns?: string[];
|
||||||
tsConfigPaths?: string[];
|
tsConfigPaths?: string[];
|
||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
|
|||||||
@ -46,10 +46,10 @@ import {
|
|||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { libsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
import { libsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
import { initRootBabelConfig } from '@nrwl/web/src/utils/rules';
|
|
||||||
import { updateBabelJestConfig } from '../../rules/update-babel-jest-config';
|
import { updateBabelJestConfig } from '../../rules/update-babel-jest-config';
|
||||||
import { names, offsetFromRoot } from '@nrwl/devkit';
|
import { names, offsetFromRoot } from '@nrwl/devkit';
|
||||||
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
|
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
|
||||||
|
import init from '../init/init';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
@ -76,6 +76,11 @@ export default function (schema: Schema): Rule {
|
|||||||
options.style = 'none';
|
options.style = 'none';
|
||||||
}
|
}
|
||||||
return chain([
|
return chain([
|
||||||
|
init({
|
||||||
|
...options,
|
||||||
|
e2eTestRunner: 'none',
|
||||||
|
skipFormat: true,
|
||||||
|
}),
|
||||||
addLintFiles(options.projectRoot, options.linter, {
|
addLintFiles(options.projectRoot, options.linter, {
|
||||||
localConfig: reactEslintJson,
|
localConfig: reactEslintJson,
|
||||||
extraPackageDeps: extraEslintDependencies,
|
extraPackageDeps: extraEslintDependencies,
|
||||||
@ -125,7 +130,6 @@ export default function (schema: Schema): Rule {
|
|||||||
{}
|
{}
|
||||||
),
|
),
|
||||||
updateAppRoutes(options, context),
|
updateAppRoutes(options, context),
|
||||||
initRootBabelConfig(),
|
|
||||||
formatFiles(options),
|
formatFiles(options),
|
||||||
])(host, context);
|
])(host, context);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -44,7 +44,10 @@ export interface WorkspaceConfiguration {
|
|||||||
/**
|
/**
|
||||||
* Default generator collection. It is used when no collection is provided.
|
* Default generator collection. It is used when no collection is provided.
|
||||||
*/
|
*/
|
||||||
cli?: { defaultCollection: string };
|
cli?: {
|
||||||
|
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
||||||
|
defaultCollection?: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -4,15 +4,30 @@
|
|||||||
"extends": ["@nrwl/workspace"],
|
"extends": ["@nrwl/workspace"],
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"init": {
|
"init": {
|
||||||
"factory": "./src/schematics/init/init",
|
"factory": "./src/generators/init/init#webInitSchematic",
|
||||||
"schema": "./src/schematics/init/schema.json",
|
"schema": "./src/generators/init/schema.json",
|
||||||
"description": "Add @nrwl/web to a project",
|
"description": "Add @nrwl/web to a project",
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"application": {
|
"application": {
|
||||||
"factory": "./src/schematics/application/application",
|
"factory": "./src/generators/application/application#applicationSchematic",
|
||||||
"schema": "./src/schematics/application/schema.json",
|
"schema": "./src/generators/application/schema.json",
|
||||||
|
"aliases": ["app"],
|
||||||
|
"description": "Create an application"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generators": {
|
||||||
|
"init": {
|
||||||
|
"factory": "./src/generators/init/init#webInitGenerator",
|
||||||
|
"schema": "./src/generators/init/schema.json",
|
||||||
|
"description": "Add @nrwl/web to a project",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"application": {
|
||||||
|
"factory": "./src/generators/application/application#applicationGenerator",
|
||||||
|
"schema": "./src/generators/application/schema.json",
|
||||||
"aliases": ["app"],
|
"aliases": ["app"],
|
||||||
"description": "Create an application"
|
"description": "Create an application"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { applicationGenerator } from './src/schematics/application/application';
|
export { applicationGenerator } from './src/generators/application/application';
|
||||||
|
|||||||
@ -33,9 +33,9 @@ import { ExtraEntryPoint } from '../../utils/third-party/browser/schema';
|
|||||||
|
|
||||||
export interface WebBuildBuilderOptions extends BuildBuilderOptions {
|
export interface WebBuildBuilderOptions extends BuildBuilderOptions {
|
||||||
index: string;
|
index: string;
|
||||||
budgets: any[];
|
budgets?: any[];
|
||||||
baseHref: string;
|
baseHref?: string;
|
||||||
deployUrl: string;
|
deployUrl?: string;
|
||||||
|
|
||||||
extractCss?: boolean;
|
extractCss?: boolean;
|
||||||
crossOrigin?: CrossOriginValue;
|
crossOrigin?: CrossOriginValue;
|
||||||
@ -49,6 +49,8 @@ export interface WebBuildBuilderOptions extends BuildBuilderOptions {
|
|||||||
vendorChunk?: boolean;
|
vendorChunk?: boolean;
|
||||||
commonChunk?: boolean;
|
commonChunk?: boolean;
|
||||||
|
|
||||||
|
namedChunks?: boolean;
|
||||||
|
|
||||||
stylePreprocessingOptions?: any;
|
stylePreprocessingOptions?: any;
|
||||||
subresourceIntegrity?: boolean;
|
subresourceIntegrity?: boolean;
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +1,21 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { readJson, Tree } from '@nrwl/devkit';
|
||||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import * as stripJsonComments from 'strip-json-comments';
|
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
|
||||||
import { readJsonInTree, NxJson } from '@nrwl/workspace';
|
|
||||||
import { runSchematic } from '../../utils/testing';
|
|
||||||
|
|
||||||
|
import { applicationGenerator } from './application';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
describe('app', () => {
|
describe('app', () => {
|
||||||
let appTree: Tree;
|
let tree: Tree;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
appTree = Tree.empty();
|
tree = createTreeWithEmptyWorkspace();
|
||||||
appTree = createEmptyWorkspace(appTree);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update workspace.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
await applicationGenerator(tree, { name: 'myApp' });
|
||||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
const workspaceJson = readJson(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||||
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||||
@ -27,12 +25,8 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, { name: 'myApp', tags: 'one,two' });
|
||||||
'app',
|
const nxJson = readJson<NxJson>(tree, '/nx.json');
|
||||||
{ name: 'myApp', tags: 'one,two' },
|
|
||||||
appTree
|
|
||||||
);
|
|
||||||
const nxJson = readJsonInTree<NxJson>(tree, '/nx.json');
|
|
||||||
expect(nxJson.projects).toEqual({
|
expect(nxJson.projects).toEqual({
|
||||||
'my-app': {
|
'my-app': {
|
||||||
tags: ['one', 'two'],
|
tags: ['one', 'two'],
|
||||||
@ -45,7 +39,7 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should generate files', async () => {
|
it('should generate files', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
await applicationGenerator(tree, { name: 'myApp' });
|
||||||
expect(tree.exists('apps/my-app/src/main.ts')).toBeTruthy();
|
expect(tree.exists('apps/my-app/src/main.ts')).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-app/src/app/app.element.ts')).toBeTruthy();
|
expect(tree.exists('apps/my-app/src/app/app.element.ts')).toBeTruthy();
|
||||||
expect(
|
expect(
|
||||||
@ -53,7 +47,7 @@ describe('app', () => {
|
|||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-app/src/app/app.element.css')).toBeTruthy();
|
expect(tree.exists('apps/my-app/src/app/app.element.css')).toBeTruthy();
|
||||||
|
|
||||||
const tsconfig = readJsonInTree(tree, 'apps/my-app/tsconfig.json');
|
const tsconfig = readJson(tree, 'apps/my-app/tsconfig.json');
|
||||||
expect(tsconfig.references).toEqual([
|
expect(tsconfig.references).toEqual([
|
||||||
{
|
{
|
||||||
path: './tsconfig.app.json',
|
path: './tsconfig.app.json',
|
||||||
@ -63,21 +57,15 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const tsconfigApp = JSON.parse(
|
const tsconfigApp = readJson(tree, 'apps/my-app/tsconfig.app.json');
|
||||||
stripJsonComments(tree.readContent('apps/my-app/tsconfig.app.json'))
|
|
||||||
);
|
|
||||||
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||||
|
|
||||||
const linter = JSON.parse(
|
const linter = readJson(tree, 'apps/my-app/.eslintrc.json');
|
||||||
stripJsonComments(tree.readContent('apps/my-app/.eslintrc.json'))
|
expect(linter.extends).toEqual(['../../.eslintrc.json']);
|
||||||
);
|
|
||||||
expect(linter.extends).toEqual('../../.eslintrc.json');
|
|
||||||
|
|
||||||
expect(tree.exists('apps/my-app-e2e/cypress.json')).toBeTruthy();
|
expect(tree.exists('apps/my-app-e2e/cypress.json')).toBeTruthy();
|
||||||
const tsconfigE2E = JSON.parse(
|
const tsconfigE2E = readJson(tree, 'apps/my-app-e2e/tsconfig.e2e.json');
|
||||||
stripJsonComments(tree.readContent('apps/my-app-e2e/tsconfig.e2e.json'))
|
|
||||||
);
|
|
||||||
expect(tsconfigE2E.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
expect(tsconfigE2E.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||||
expect(tsconfigE2E.extends).toEqual('./tsconfig.json');
|
expect(tsconfigE2E.extends).toEqual('./tsconfig.json');
|
||||||
});
|
});
|
||||||
@ -85,12 +73,11 @@ describe('app', () => {
|
|||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update workspace.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', directory: 'myDir' },
|
directory: 'myDir',
|
||||||
appTree
|
});
|
||||||
);
|
const workspaceJson = readJson(tree, '/workspace.json');
|
||||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
|
||||||
|
|
||||||
expect(workspaceJson.projects['my-dir-my-app'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app'].root).toEqual(
|
||||||
'apps/my-dir/my-app'
|
'apps/my-dir/my-app'
|
||||||
@ -101,12 +88,12 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', directory: 'myDir', tags: 'one,two' },
|
directory: 'myDir',
|
||||||
appTree
|
tags: 'one,two',
|
||||||
);
|
});
|
||||||
const nxJson = readJsonInTree<NxJson>(tree, '/nx.json');
|
const nxJson = readJson<NxJson>(tree, '/nx.json');
|
||||||
expect(nxJson.projects).toEqual({
|
expect(nxJson.projects).toEqual({
|
||||||
'my-dir-my-app': {
|
'my-dir-my-app': {
|
||||||
tags: ['one', 'two'],
|
tags: ['one', 'two'],
|
||||||
@ -120,16 +107,14 @@ describe('app', () => {
|
|||||||
|
|
||||||
it('should generate files', async () => {
|
it('should generate files', async () => {
|
||||||
const hasJsonValue = ({ path, expectedValue, lookupFn }) => {
|
const hasJsonValue = ({ path, expectedValue, lookupFn }) => {
|
||||||
const content = tree.readContent(path);
|
const config = readJson(tree, path);
|
||||||
const config = JSON.parse(stripJsonComments(content));
|
|
||||||
|
|
||||||
expect(lookupFn(config)).toEqual(expectedValue);
|
expect(lookupFn(config)).toEqual(expectedValue);
|
||||||
};
|
};
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', directory: 'myDir' },
|
directory: 'myDir',
|
||||||
appTree
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Make sure these exist
|
// Make sure these exist
|
||||||
[
|
[
|
||||||
@ -156,62 +141,50 @@ describe('app', () => {
|
|||||||
{
|
{
|
||||||
path: 'apps/my-dir/my-app/.eslintrc.json',
|
path: 'apps/my-dir/my-app/.eslintrc.json',
|
||||||
lookupFn: (json) => json.extends,
|
lookupFn: (json) => json.extends,
|
||||||
expectedValue: '../../../.eslintrc.json',
|
expectedValue: ['../../../.eslintrc.json'],
|
||||||
},
|
},
|
||||||
].forEach(hasJsonValue);
|
].forEach(hasJsonValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create Nx specific template', async () => {
|
it('should create Nx specific template', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', directory: 'myDir' },
|
directory: 'myDir',
|
||||||
appTree
|
});
|
||||||
);
|
|
||||||
expect(
|
expect(
|
||||||
tree.readContent('apps/my-dir/my-app/src/app/app.element.ts')
|
tree.read('apps/my-dir/my-app/src/app/app.element.ts').toString()
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(
|
expect(
|
||||||
tree.readContent('apps/my-dir/my-app/src/app/app.element.ts')
|
tree.read('apps/my-dir/my-app/src/app/app.element.ts').toString()
|
||||||
).toContain('Thank you for using and showing some ♥ for Nx.');
|
).toContain('Thank you for using and showing some ♥ for Nx.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('--style scss', () => {
|
describe('--style scss', () => {
|
||||||
it('should generate scss styles', async () => {
|
it('should generate scss styles', async () => {
|
||||||
const result = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', style: 'scss' },
|
style: 'scss',
|
||||||
appTree
|
});
|
||||||
);
|
expect(tree.exists('apps/my-app/src/app/app.element.scss')).toEqual(true);
|
||||||
expect(result.exists('apps/my-app/src/app/app.element.scss')).toEqual(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup jest without serializers', async () => {
|
it('should setup jest without serializers', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
|
||||||
{
|
|
||||||
name: 'my-App',
|
name: 'my-App',
|
||||||
},
|
});
|
||||||
appTree
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(tree.readContent('apps/my-app/jest.config.js')).not.toContain(
|
expect(tree.read('apps/my-app/jest.config.js').toString()).not.toContain(
|
||||||
`'jest-preset-angular/build/AngularSnapshotSerializer.js',`
|
`'jest-preset-angular/build/AngularSnapshotSerializer.js',`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the nrwl web build builder', async () => {
|
it('should setup the nrwl web build builder', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
|
||||||
{
|
|
||||||
name: 'my-App',
|
name: 'my-App',
|
||||||
},
|
});
|
||||||
appTree
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
);
|
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
|
||||||
const architectConfig = workspaceJson.projects['my-app'].architect;
|
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||||
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
||||||
expect(architectConfig.build.outputs).toEqual(['{options.outputPath}']);
|
expect(architectConfig.build.outputs).toEqual(['{options.outputPath}']);
|
||||||
@ -250,14 +223,10 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the nrwl web dev server builder', async () => {
|
it('should setup the nrwl web dev server builder', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
|
||||||
{
|
|
||||||
name: 'my-App',
|
name: 'my-App',
|
||||||
},
|
});
|
||||||
appTree
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
);
|
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
|
||||||
const architectConfig = workspaceJson.projects['my-app'].architect;
|
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||||
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
||||||
expect(architectConfig.serve.options).toEqual({
|
expect(architectConfig.serve.options).toEqual({
|
||||||
@ -269,14 +238,10 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should setup the eslint builder', async () => {
|
it('should setup the eslint builder', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
|
||||||
{
|
|
||||||
name: 'my-App',
|
name: 'my-App',
|
||||||
},
|
});
|
||||||
appTree
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
);
|
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
|
||||||
|
|
||||||
expect(workspaceJson.projects['my-app'].architect.lint).toEqual({
|
expect(workspaceJson.projects['my-app'].architect.lint).toEqual({
|
||||||
builder: '@nrwl/linter:eslint',
|
builder: '@nrwl/linter:eslint',
|
||||||
@ -288,13 +253,9 @@ describe('app', () => {
|
|||||||
|
|
||||||
describe('--prefix', () => {
|
describe('--prefix', () => {
|
||||||
it('should use the prefix in the index.html', async () => {
|
it('should use the prefix in the index.html', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, { name: 'myApp', prefix: 'prefix' });
|
||||||
'app',
|
|
||||||
{ name: 'myApp', prefix: 'prefix' },
|
|
||||||
appTree
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(tree.readContent('apps/my-app/src/index.html')).toContain(
|
expect(tree.read('apps/my-app/src/index.html').toString()).toContain(
|
||||||
'<prefix-root></prefix-root>'
|
'<prefix-root></prefix-root>'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -302,16 +263,17 @@ describe('app', () => {
|
|||||||
|
|
||||||
describe('--unit-test-runner none', () => {
|
describe('--unit-test-runner none', () => {
|
||||||
it('should not generate test configuration', async () => {
|
it('should not generate test configuration', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', unitTestRunner: 'none' },
|
unitTestRunner: 'none',
|
||||||
appTree
|
});
|
||||||
);
|
|
||||||
expect(tree.exists('jest.config.js')).toBeFalsy();
|
expect(tree.exists('jest.config.js')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/src/app/app.spec.ts')).toBeFalsy();
|
expect(
|
||||||
|
tree.exists('apps/my-app/src/app/app.element.spec.ts')
|
||||||
|
).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||||
expect(workspaceJson.projects['my-app'].architect.lint)
|
expect(workspaceJson.projects['my-app'].architect.lint)
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
@ -329,44 +291,40 @@ describe('app', () => {
|
|||||||
|
|
||||||
describe('--e2e-test-runner none', () => {
|
describe('--e2e-test-runner none', () => {
|
||||||
it('should not generate test configuration', async () => {
|
it('should not generate test configuration', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', e2eTestRunner: 'none' },
|
e2eTestRunner: 'none',
|
||||||
appTree
|
});
|
||||||
);
|
|
||||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('--babelJest', () => {
|
describe('--babelJest', () => {
|
||||||
it('should use babel for jest', async () => {
|
it('should use babel for jest', async () => {
|
||||||
const tree = await runSchematic(
|
await applicationGenerator(tree, {
|
||||||
'app',
|
name: 'myApp',
|
||||||
{ name: 'myApp', babelJest: true } as Schema,
|
babelJest: true,
|
||||||
appTree
|
} as Schema);
|
||||||
);
|
|
||||||
|
|
||||||
expect(tree.readContent(`apps/my-app/jest.config.js`))
|
expect(tree.read(`apps/my-app/jest.config.js`).toString())
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
"module.exports = {
|
"module.exports = {
|
||||||
displayName: 'my-app',
|
displayName: 'my-app',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../../jest.preset.js',
|
||||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\\\\\\\.[tj]s$': [
|
'^.+\\\\\\\\.[tj]s$': [ 'babel-jest',
|
||||||
'babel-jest',
|
{ cwd: __dirname, configFile: './babel-jest.config.json' }]
|
||||||
{ cwd: __dirname, configFile: './babel-jest.config.json' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||||
coverageDirectory: '../../coverage/apps/my-app',
|
coverageDirectory: '../../coverage/apps/my-app'
|
||||||
};
|
};
|
||||||
"
|
"
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(readJsonInTree(tree, 'apps/my-app/babel-jest.config.json'))
|
expect(readJson(tree, 'apps/my-app/babel-jest.config.json'))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"presets": Array [
|
"presets": Array [
|
||||||
243
packages/web/src/generators/application/application.ts
Normal file
243
packages/web/src/generators/application/application.ts
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
import {
|
||||||
|
addProjectConfiguration,
|
||||||
|
convertNxGenerator,
|
||||||
|
formatFiles,
|
||||||
|
generateFiles,
|
||||||
|
getWorkspaceLayout,
|
||||||
|
joinPathFragments,
|
||||||
|
names,
|
||||||
|
NxJsonProjectConfiguration,
|
||||||
|
offsetFromRoot,
|
||||||
|
ProjectConfiguration,
|
||||||
|
readWorkspaceConfiguration,
|
||||||
|
TargetConfiguration,
|
||||||
|
Tree,
|
||||||
|
updateWorkspaceConfiguration,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { webInitGenerator } from '../init/init';
|
||||||
|
import { cypressProjectGenerator } from '@nrwl/cypress';
|
||||||
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||||
|
import { jestProjectGenerator } from '@nrwl/jest';
|
||||||
|
|
||||||
|
import { WebBuildBuilderOptions } from '../../builders/build/build.impl';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
|
||||||
|
interface NormalizedSchema extends Schema {
|
||||||
|
projectName: string;
|
||||||
|
appProjectRoot: string;
|
||||||
|
e2eProjectName: string;
|
||||||
|
e2eProjectRoot: string;
|
||||||
|
parsedTags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
||||||
|
generateFiles(tree, join(__dirname, './files/app'), options.appProjectRoot, {
|
||||||
|
...options,
|
||||||
|
...names(options.name),
|
||||||
|
tmpl: '',
|
||||||
|
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
||||||
|
});
|
||||||
|
if (options.unitTestRunner === 'none') {
|
||||||
|
tree.delete(join(options.appProjectRoot, './src/app/app.element.spec.ts'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addBuildTarget(
|
||||||
|
project: ProjectConfiguration,
|
||||||
|
options: NormalizedSchema
|
||||||
|
): ProjectConfiguration {
|
||||||
|
const buildOptions: WebBuildBuilderOptions = {
|
||||||
|
outputPath: joinPathFragments('dist', options.appProjectRoot),
|
||||||
|
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
|
||||||
|
main: joinPathFragments(options.appProjectRoot, 'src/main.ts'),
|
||||||
|
polyfills: joinPathFragments(options.appProjectRoot, 'src/polyfills.ts'),
|
||||||
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
|
assets: [
|
||||||
|
joinPathFragments(options.appProjectRoot, 'src/favicon.ico'),
|
||||||
|
joinPathFragments(options.appProjectRoot, 'src/assets'),
|
||||||
|
],
|
||||||
|
styles: [
|
||||||
|
joinPathFragments(options.appProjectRoot, `src/styles.${options.style}`),
|
||||||
|
],
|
||||||
|
scripts: [],
|
||||||
|
};
|
||||||
|
const productionBuildOptions: Partial<WebBuildBuilderOptions> = {
|
||||||
|
fileReplacements: [
|
||||||
|
{
|
||||||
|
replace: joinPathFragments(
|
||||||
|
options.appProjectRoot,
|
||||||
|
`src/environments/environment.ts`
|
||||||
|
),
|
||||||
|
with: joinPathFragments(
|
||||||
|
options.appProjectRoot,
|
||||||
|
`src/environments/environment.prod.ts`
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
optimization: true,
|
||||||
|
outputHashing: 'all',
|
||||||
|
sourceMap: false,
|
||||||
|
extractCss: true,
|
||||||
|
namedChunks: false,
|
||||||
|
extractLicenses: true,
|
||||||
|
vendorChunk: false,
|
||||||
|
budgets: [
|
||||||
|
{
|
||||||
|
type: 'initial',
|
||||||
|
maximumWarning: '2mb',
|
||||||
|
maximumError: '5mb',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...project,
|
||||||
|
targets: {
|
||||||
|
...project.targets,
|
||||||
|
build: {
|
||||||
|
executor: '@nrwl/web:build',
|
||||||
|
outputs: ['{options.outputPath}'],
|
||||||
|
options: buildOptions,
|
||||||
|
configurations: {
|
||||||
|
production: productionBuildOptions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function addServeTarget(
|
||||||
|
project: ProjectConfiguration,
|
||||||
|
options: NormalizedSchema
|
||||||
|
) {
|
||||||
|
const serveTarget: TargetConfiguration = {
|
||||||
|
executor: '@nrwl/web:dev-server',
|
||||||
|
options: {
|
||||||
|
buildTarget: `${options.projectName}:build`,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
production: {
|
||||||
|
buildTarget: `${options.projectName}:build:production`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...project,
|
||||||
|
targets: {
|
||||||
|
...project.targets,
|
||||||
|
serve: serveTarget,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function addProject(tree: Tree, options: NormalizedSchema) {
|
||||||
|
const targets: Record<string, TargetConfiguration> = {};
|
||||||
|
let project: ProjectConfiguration & NxJsonProjectConfiguration = {
|
||||||
|
projectType: 'application',
|
||||||
|
root: options.appProjectRoot,
|
||||||
|
sourceRoot: joinPathFragments(options.appProjectRoot, 'src'),
|
||||||
|
tags: options.parsedTags,
|
||||||
|
targets,
|
||||||
|
};
|
||||||
|
|
||||||
|
project = addBuildTarget(project, options);
|
||||||
|
project = addServeTarget(project, options);
|
||||||
|
|
||||||
|
addProjectConfiguration(tree, options.projectName, project);
|
||||||
|
|
||||||
|
const workspace = readWorkspaceConfiguration(tree);
|
||||||
|
|
||||||
|
if (!workspace.defaultProject) {
|
||||||
|
workspace.defaultProject = options.projectName;
|
||||||
|
|
||||||
|
updateWorkspaceConfiguration(tree, workspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function applicationGenerator(host: Tree, schema: Schema) {
|
||||||
|
const options = normalizeOptions(host, schema);
|
||||||
|
|
||||||
|
let installTask = await webInitGenerator(host, {
|
||||||
|
...options,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
createApplicationFiles(host, options);
|
||||||
|
addProject(host, options);
|
||||||
|
|
||||||
|
const lintInstallTask = await lintProjectGenerator(host, {
|
||||||
|
linter: options.linter,
|
||||||
|
project: options.projectName,
|
||||||
|
tsConfigPaths: [
|
||||||
|
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
|
],
|
||||||
|
eslintFilePatterns: [`${options.appProjectRoot}/**/*.ts`],
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
installTask = lintInstallTask || installTask;
|
||||||
|
|
||||||
|
if (options.e2eTestRunner === 'cypress') {
|
||||||
|
const cypressInstallTask = await cypressProjectGenerator(host, {
|
||||||
|
...options,
|
||||||
|
name: options.name + '-e2e',
|
||||||
|
directory: options.directory,
|
||||||
|
project: options.projectName,
|
||||||
|
});
|
||||||
|
installTask = cypressInstallTask || installTask;
|
||||||
|
}
|
||||||
|
if (options.unitTestRunner === 'jest') {
|
||||||
|
const jestInstallTask = await jestProjectGenerator(host, {
|
||||||
|
project: options.projectName,
|
||||||
|
skipSerializers: true,
|
||||||
|
setupFile: 'web-components',
|
||||||
|
babelJest: options.babelJest,
|
||||||
|
});
|
||||||
|
installTask = jestInstallTask || installTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!schema.skipFormat) {
|
||||||
|
await formatFiles(host);
|
||||||
|
}
|
||||||
|
return installTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||||
|
const appDirectory = options.directory
|
||||||
|
? `${names(options.directory).fileName}/${names(options.name).fileName}`
|
||||||
|
: names(options.name).fileName;
|
||||||
|
|
||||||
|
const { appsDir, npmScope: defaultPrefix } = getWorkspaceLayout(host);
|
||||||
|
|
||||||
|
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
|
const e2eProjectName = `${appProjectName}-e2e`;
|
||||||
|
|
||||||
|
const appProjectRoot = `${appsDir}/${appDirectory}`;
|
||||||
|
const e2eProjectRoot = `${appsDir}/${appDirectory}-e2e`;
|
||||||
|
|
||||||
|
const parsedTags = options.tags
|
||||||
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
|
: [];
|
||||||
|
|
||||||
|
options.style = options.style || 'css';
|
||||||
|
options.linter = options.linter || Linter.EsLint;
|
||||||
|
options.unitTestRunner = options.unitTestRunner || 'jest';
|
||||||
|
options.e2eTestRunner = options.e2eTestRunner || 'cypress';
|
||||||
|
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
prefix: options.prefix ? options.prefix : defaultPrefix,
|
||||||
|
name: names(options.name).fileName,
|
||||||
|
projectName: appProjectName,
|
||||||
|
appProjectRoot,
|
||||||
|
e2eProjectRoot,
|
||||||
|
e2eProjectName,
|
||||||
|
parsedTags,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default applicationGenerator;
|
||||||
|
export const applicationSchematic = convertNxGenerator(applicationGenerator);
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
14
packages/web/src/generators/application/schema.d.ts
vendored
Normal file
14
packages/web/src/generators/application/schema.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Linter } from '@nrwl/linter';
|
||||||
|
|
||||||
|
export interface Schema {
|
||||||
|
name: string;
|
||||||
|
prefix?: string;
|
||||||
|
style?: string;
|
||||||
|
skipFormat?: boolean;
|
||||||
|
directory?: string;
|
||||||
|
tags?: string;
|
||||||
|
unitTestRunner?: 'jest' | 'none';
|
||||||
|
e2eTestRunner?: 'cypress' | 'none';
|
||||||
|
linter?: Linter;
|
||||||
|
babelJest?: boolean;
|
||||||
|
}
|
||||||
79
packages/web/src/generators/init/init.spec.ts
Normal file
79
packages/web/src/generators/init/init.spec.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { addDependenciesToPackageJson, readJson, Tree } from '@nrwl/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
|
|
||||||
|
import webInitGenerator from './init';
|
||||||
|
|
||||||
|
describe('init', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add web dependencies', async () => {
|
||||||
|
const existing = 'existing';
|
||||||
|
const existingVersion = '1.0.0';
|
||||||
|
addDependenciesToPackageJson(
|
||||||
|
tree,
|
||||||
|
{
|
||||||
|
'@nrwl/web': nxVersion,
|
||||||
|
[existing]: existingVersion,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[existing]: existingVersion,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await webInitGenerator(tree, {});
|
||||||
|
const packageJson = readJson(tree, 'package.json');
|
||||||
|
expect(packageJson.devDependencies['@nrwl/web']).toBeDefined();
|
||||||
|
expect(packageJson.devDependencies[existing]).toBeDefined();
|
||||||
|
expect(packageJson.dependencies['@nrwl/web']).toBeUndefined();
|
||||||
|
expect(packageJson.dependencies['document-register-element']).toBeDefined();
|
||||||
|
expect(packageJson.dependencies[existing]).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('defaultCollection', () => {
|
||||||
|
it('should be set if none was set before', async () => {
|
||||||
|
await webInitGenerator(tree, {});
|
||||||
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add jest config if unitTestRunner is none', async () => {
|
||||||
|
await webInitGenerator(tree, {
|
||||||
|
unitTestRunner: 'none',
|
||||||
|
});
|
||||||
|
expect(tree.exists('jest.config.js')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('babel config', () => {
|
||||||
|
it('should create babel config if not present', async () => {
|
||||||
|
await webInitGenerator(tree, {
|
||||||
|
unitTestRunner: 'none',
|
||||||
|
});
|
||||||
|
expect(tree.exists('babel.config.json')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not overwrite existing babel config', async () => {
|
||||||
|
tree.write('babel.config.json', '{ "preset": ["preset-awesome"] }');
|
||||||
|
|
||||||
|
await webInitGenerator(tree, {
|
||||||
|
unitTestRunner: 'none',
|
||||||
|
});
|
||||||
|
|
||||||
|
const existing = readJson(tree, 'babel.config.json');
|
||||||
|
expect(existing).toEqual({ preset: ['preset-awesome'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not overwrite existing babel config (.js)', async () => {
|
||||||
|
tree.write('/babel.config.js', 'module.exports = () => {};');
|
||||||
|
await webInitGenerator(tree, {
|
||||||
|
unitTestRunner: 'none',
|
||||||
|
});
|
||||||
|
expect(tree.exists('babel.config.json')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
82
packages/web/src/generators/init/init.ts
Normal file
82
packages/web/src/generators/init/init.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import {
|
||||||
|
addDependenciesToPackageJson,
|
||||||
|
convertNxGenerator,
|
||||||
|
formatFiles,
|
||||||
|
GeneratorCallback,
|
||||||
|
readWorkspaceConfiguration,
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
updateWorkspaceConfiguration,
|
||||||
|
writeJson,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
import {
|
||||||
|
documentRegisterElementVersion,
|
||||||
|
nxVersion,
|
||||||
|
} from '../../utils/versions';
|
||||||
|
import { cypressInitGenerator } from '@nrwl/cypress';
|
||||||
|
import { jestInitGenerator } from '@nrwl/jest';
|
||||||
|
|
||||||
|
function updateDependencies(tree: Tree) {
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
delete json.dependencies['@nrwl/web'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
return addDependenciesToPackageJson(
|
||||||
|
tree,
|
||||||
|
{
|
||||||
|
'core-js': '^3.6.5',
|
||||||
|
'document-register-element': documentRegisterElementVersion,
|
||||||
|
tslib: '^2.0.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'@nrwl/web': nxVersion,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefaultCollection(tree: Tree) {
|
||||||
|
const workspace = readWorkspaceConfiguration(tree);
|
||||||
|
workspace.cli = workspace.cli || {};
|
||||||
|
|
||||||
|
const defaultCollection = workspace.cli.defaultCollection;
|
||||||
|
|
||||||
|
if (!defaultCollection || defaultCollection === '@nrwl/workspace') {
|
||||||
|
workspace.cli.defaultCollection = '@nrwl/web';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWorkspaceConfiguration(tree, workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initRootBabelConfig(tree: Tree) {
|
||||||
|
if (tree.exists('/babel.config.json') || tree.exists('/babel.config.js')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeJson(tree, '/babel.config.json', {
|
||||||
|
presets: ['@nrwl/web/babel'],
|
||||||
|
babelrcRoots: ['*'], // Make sure .babelrc files other than root can be loaded in a monorepo
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function webInitGenerator(tree: Tree, schema: Schema) {
|
||||||
|
let installTask: GeneratorCallback;
|
||||||
|
|
||||||
|
setDefaultCollection(tree);
|
||||||
|
if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') {
|
||||||
|
installTask = jestInitGenerator(tree, {});
|
||||||
|
}
|
||||||
|
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
|
||||||
|
installTask = cypressInitGenerator(tree) || installTask;
|
||||||
|
}
|
||||||
|
installTask = updateDependencies(tree) || installTask;
|
||||||
|
initRootBabelConfig(tree);
|
||||||
|
if (!schema.skipFormat) {
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
|
return installTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default webInitGenerator;
|
||||||
|
export const webInitSchematic = convertNxGenerator(webInitGenerator);
|
||||||
5
packages/web/src/generators/init/schema.d.ts
vendored
Normal file
5
packages/web/src/generators/init/schema.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface Schema {
|
||||||
|
unitTestRunner?: 'jest' | 'none';
|
||||||
|
e2eTestRunner?: 'cypress' | 'none';
|
||||||
|
skipFormat?: boolean;
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"id": "NxWebInit",
|
"id": "NxWebInit",
|
||||||
|
"cli": "nx",
|
||||||
"title": "Init Web Plugin",
|
"title": "Init Web Plugin",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1,217 +0,0 @@
|
|||||||
import { join, normalize } from '@angular-devkit/core';
|
|
||||||
import {
|
|
||||||
chain,
|
|
||||||
Rule,
|
|
||||||
Tree,
|
|
||||||
SchematicContext,
|
|
||||||
mergeWith,
|
|
||||||
apply,
|
|
||||||
template,
|
|
||||||
move,
|
|
||||||
url,
|
|
||||||
externalSchematic,
|
|
||||||
noop,
|
|
||||||
filter,
|
|
||||||
} from '@angular-devkit/schematics';
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import {
|
|
||||||
updateJsonInTree,
|
|
||||||
NxJson,
|
|
||||||
getNpmScope,
|
|
||||||
formatFiles,
|
|
||||||
updateWorkspaceInTree,
|
|
||||||
generateProjectLint,
|
|
||||||
addLintFiles,
|
|
||||||
} from '@nrwl/workspace';
|
|
||||||
import init from '../init/init';
|
|
||||||
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
|
||||||
import { names, offsetFromRoot } from '@nrwl/devkit';
|
|
||||||
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
|
|
||||||
|
|
||||||
interface NormalizedSchema extends Schema {
|
|
||||||
projectName: string;
|
|
||||||
appProjectRoot: string;
|
|
||||||
e2eProjectName: string;
|
|
||||||
e2eProjectRoot: string;
|
|
||||||
parsedTags: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createApplicationFiles(options: NormalizedSchema): Rule {
|
|
||||||
return mergeWith(
|
|
||||||
apply(url(`./files/app`), [
|
|
||||||
template({
|
|
||||||
...options,
|
|
||||||
...names(options.name),
|
|
||||||
tmpl: '',
|
|
||||||
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
|
||||||
}),
|
|
||||||
options.unitTestRunner === 'none'
|
|
||||||
? filter((file) => file !== '/src/app/app.spec.ts')
|
|
||||||
: noop(),
|
|
||||||
move(options.appProjectRoot),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateNxJson(options: NormalizedSchema): Rule {
|
|
||||||
return updateJsonInTree<NxJson>('nx.json', (json) => {
|
|
||||||
json.projects[options.projectName] = { tags: options.parsedTags };
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addProject(options: NormalizedSchema): Rule {
|
|
||||||
return updateWorkspaceInTree((json) => {
|
|
||||||
const architect: { [key: string]: any } = {};
|
|
||||||
|
|
||||||
architect.build = {
|
|
||||||
builder: '@nrwl/web:build',
|
|
||||||
outputs: ['{options.outputPath}'],
|
|
||||||
options: {
|
|
||||||
outputPath: join(normalize('dist'), options.appProjectRoot),
|
|
||||||
index: join(normalize(options.appProjectRoot), 'src/index.html'),
|
|
||||||
main: join(normalize(options.appProjectRoot), 'src/main.ts'),
|
|
||||||
polyfills: join(normalize(options.appProjectRoot), 'src/polyfills.ts'),
|
|
||||||
tsConfig: join(normalize(options.appProjectRoot), 'tsconfig.app.json'),
|
|
||||||
assets: [
|
|
||||||
join(normalize(options.appProjectRoot), 'src/favicon.ico'),
|
|
||||||
join(normalize(options.appProjectRoot), 'src/assets'),
|
|
||||||
],
|
|
||||||
styles: [
|
|
||||||
join(
|
|
||||||
normalize(options.appProjectRoot),
|
|
||||||
`src/styles.${options.style}`
|
|
||||||
),
|
|
||||||
],
|
|
||||||
scripts: [],
|
|
||||||
},
|
|
||||||
configurations: {
|
|
||||||
production: {
|
|
||||||
fileReplacements: [
|
|
||||||
{
|
|
||||||
replace: join(
|
|
||||||
normalize(options.appProjectRoot),
|
|
||||||
`src/environments/environment.ts`
|
|
||||||
),
|
|
||||||
with: join(
|
|
||||||
normalize(options.appProjectRoot),
|
|
||||||
`src/environments/environment.prod.ts`
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
optimization: true,
|
|
||||||
outputHashing: 'all',
|
|
||||||
sourceMap: false,
|
|
||||||
extractCss: true,
|
|
||||||
namedChunks: false,
|
|
||||||
extractLicenses: true,
|
|
||||||
vendorChunk: false,
|
|
||||||
budgets: [
|
|
||||||
{
|
|
||||||
type: 'initial',
|
|
||||||
maximumWarning: '2mb',
|
|
||||||
maximumError: '5mb',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
architect.serve = {
|
|
||||||
builder: '@nrwl/web:dev-server',
|
|
||||||
options: {
|
|
||||||
buildTarget: `${options.projectName}:build`,
|
|
||||||
},
|
|
||||||
configurations: {
|
|
||||||
production: {
|
|
||||||
buildTarget: `${options.projectName}:build:production`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
architect.lint = generateProjectLint(
|
|
||||||
normalize(options.appProjectRoot),
|
|
||||||
join(normalize(options.appProjectRoot), 'tsconfig.app.json'),
|
|
||||||
options.linter,
|
|
||||||
[`${options.appProjectRoot}/**/*.ts`]
|
|
||||||
);
|
|
||||||
|
|
||||||
json.projects[options.projectName] = {
|
|
||||||
root: options.appProjectRoot,
|
|
||||||
sourceRoot: join(normalize(options.appProjectRoot), 'src'),
|
|
||||||
projectType: 'application',
|
|
||||||
architect,
|
|
||||||
};
|
|
||||||
|
|
||||||
json.defaultProject = json.defaultProject || options.projectName;
|
|
||||||
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function (schema: Schema): Rule {
|
|
||||||
return (host: Tree, context: SchematicContext) => {
|
|
||||||
const options = normalizeOptions(host, schema);
|
|
||||||
|
|
||||||
return chain([
|
|
||||||
init({
|
|
||||||
...options,
|
|
||||||
skipFormat: true,
|
|
||||||
}),
|
|
||||||
addLintFiles(options.appProjectRoot, options.linter),
|
|
||||||
createApplicationFiles(options),
|
|
||||||
updateNxJson(options),
|
|
||||||
addProject(options),
|
|
||||||
options.e2eTestRunner === 'cypress'
|
|
||||||
? externalSchematic('@nrwl/cypress', 'cypress-project', {
|
|
||||||
...options,
|
|
||||||
name: options.name + '-e2e',
|
|
||||||
directory: options.directory,
|
|
||||||
project: options.projectName,
|
|
||||||
})
|
|
||||||
: noop(),
|
|
||||||
options.unitTestRunner === 'jest'
|
|
||||||
? externalSchematic('@nrwl/jest', 'jest-project', {
|
|
||||||
project: options.projectName,
|
|
||||||
skipSerializers: true,
|
|
||||||
setupFile: 'web-components',
|
|
||||||
babelJest: options.babelJest,
|
|
||||||
})
|
|
||||||
: noop(),
|
|
||||||
formatFiles(options),
|
|
||||||
])(host, context);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|
||||||
const appDirectory = options.directory
|
|
||||||
? `${names(options.directory).fileName}/${names(options.name).fileName}`
|
|
||||||
: names(options.name).fileName;
|
|
||||||
|
|
||||||
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
|
||||||
const e2eProjectName = `${appProjectName}-e2e`;
|
|
||||||
|
|
||||||
const appProjectRoot = `${appsDir(host)}/${appDirectory}`;
|
|
||||||
const e2eProjectRoot = `${appsDir(host)}/${appDirectory}-e2e`;
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const defaultPrefix = getNpmScope(host);
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
prefix: options.prefix ? options.prefix : defaultPrefix,
|
|
||||||
name: names(options.name).fileName,
|
|
||||||
projectName: appProjectName,
|
|
||||||
appProjectRoot,
|
|
||||||
e2eProjectRoot,
|
|
||||||
e2eProjectName,
|
|
||||||
parsedTags,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const applicationGenerator = wrapAngularDevkitSchematic(
|
|
||||||
'@nrwl/web',
|
|
||||||
'application'
|
|
||||||
);
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
export interface Schema {
|
|
||||||
name: string;
|
|
||||||
prefix?: string;
|
|
||||||
style?: string;
|
|
||||||
skipFormat: boolean;
|
|
||||||
directory?: string;
|
|
||||||
tags?: string;
|
|
||||||
unitTestRunner: 'jest' | 'none';
|
|
||||||
e2eTestRunner: 'cypress' | 'none';
|
|
||||||
linter: Linter;
|
|
||||||
babelJest?: boolean;
|
|
||||||
}
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
|
||||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
|
||||||
import { addDepsToPackageJson, readJsonInTree } from '@nrwl/workspace';
|
|
||||||
import { callRule, runSchematic } from '../../utils/testing';
|
|
||||||
import { nxVersion } from '../../utils/versions';
|
|
||||||
|
|
||||||
describe('init', () => {
|
|
||||||
let tree: Tree;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
tree = Tree.empty();
|
|
||||||
tree = createEmptyWorkspace(tree);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add web dependencies', async () => {
|
|
||||||
const existing = 'existing';
|
|
||||||
const existingVersion = '1.0.0';
|
|
||||||
await callRule(
|
|
||||||
addDepsToPackageJson(
|
|
||||||
{ '@nrwl/web': nxVersion, [existing]: existingVersion },
|
|
||||||
{ [existing]: existingVersion },
|
|
||||||
false
|
|
||||||
),
|
|
||||||
tree
|
|
||||||
);
|
|
||||||
const result = await runSchematic('init', {}, tree);
|
|
||||||
const packageJson = readJsonInTree(result, 'package.json');
|
|
||||||
expect(packageJson.devDependencies['@nrwl/web']).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies[existing]).toBeDefined();
|
|
||||||
expect(packageJson.dependencies['@nrwl/web']).toBeUndefined();
|
|
||||||
expect(packageJson.dependencies['document-register-element']).toBeDefined();
|
|
||||||
expect(packageJson.dependencies[existing]).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('defaultCollection', () => {
|
|
||||||
it('should be set if none was set before', async () => {
|
|
||||||
const result = await runSchematic('init', {}, tree);
|
|
||||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
|
||||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/web');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not add jest config if unitTestRunner is none', async () => {
|
|
||||||
const result = await runSchematic(
|
|
||||||
'init',
|
|
||||||
{
|
|
||||||
unitTestRunner: 'none',
|
|
||||||
},
|
|
||||||
tree
|
|
||||||
);
|
|
||||||
expect(result.exists('jest.config.js')).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('babel config', () => {
|
|
||||||
it('should create babel config if not present', async () => {
|
|
||||||
const result = await runSchematic(
|
|
||||||
'init',
|
|
||||||
{
|
|
||||||
unitTestRunner: 'none',
|
|
||||||
},
|
|
||||||
tree
|
|
||||||
);
|
|
||||||
expect(result.exists('babel.config.json')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not overwrite existing babel config', async () => {
|
|
||||||
tree.create('babel.config.json', '{ "preset": ["preset-awesome"] }');
|
|
||||||
|
|
||||||
const result = await runSchematic(
|
|
||||||
'init',
|
|
||||||
{
|
|
||||||
unitTestRunner: 'none',
|
|
||||||
},
|
|
||||||
tree
|
|
||||||
);
|
|
||||||
|
|
||||||
const existing = result.read('babel.config.json').toString();
|
|
||||||
expect(existing).toMatch('{ "preset": ["preset-awesome"] }');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not overwrite existing babel config (.js)', async () => {
|
|
||||||
tree.create('/babel.config.js', 'module.exports = () => {};');
|
|
||||||
const result = await runSchematic(
|
|
||||||
'init',
|
|
||||||
{
|
|
||||||
unitTestRunner: 'none',
|
|
||||||
},
|
|
||||||
tree
|
|
||||||
);
|
|
||||||
expect(result.exists('babel.config.json')).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
import { chain, noop, Rule, Tree } from '@angular-devkit/schematics';
|
|
||||||
import {
|
|
||||||
addPackageWithInit,
|
|
||||||
formatFiles,
|
|
||||||
setDefaultCollection,
|
|
||||||
updateJsonInTree,
|
|
||||||
} from '@nrwl/workspace';
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import {
|
|
||||||
documentRegisterElementVersion,
|
|
||||||
nxVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import { initRootBabelConfig } from '../../utils/rules';
|
|
||||||
|
|
||||||
function updateDependencies(): Rule {
|
|
||||||
return updateJsonInTree('package.json', (json) => {
|
|
||||||
delete json.dependencies['@nrwl/web'];
|
|
||||||
json.dependencies = {
|
|
||||||
...json.dependencies,
|
|
||||||
'core-js': '^3.6.5',
|
|
||||||
'document-register-element': documentRegisterElementVersion,
|
|
||||||
tslib: '^2.0.0',
|
|
||||||
};
|
|
||||||
json.devDependencies = {
|
|
||||||
...json.devDependencies,
|
|
||||||
'@nrwl/web': nxVersion,
|
|
||||||
};
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function (schema: Schema) {
|
|
||||||
return chain([
|
|
||||||
setDefaultCollection('@nrwl/web'),
|
|
||||||
schema.unitTestRunner === 'jest'
|
|
||||||
? addPackageWithInit('@nrwl/jest')
|
|
||||||
: noop(),
|
|
||||||
schema.e2eTestRunner === 'cypress'
|
|
||||||
? addPackageWithInit('@nrwl/cypress')
|
|
||||||
: noop(),
|
|
||||||
updateDependencies(),
|
|
||||||
initRootBabelConfig(),
|
|
||||||
formatFiles(schema),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
5
packages/web/src/schematics/init/schema.d.ts
vendored
5
packages/web/src/schematics/init/schema.d.ts
vendored
@ -1,5 +0,0 @@
|
|||||||
export interface Schema {
|
|
||||||
unitTestRunner: 'jest' | 'none';
|
|
||||||
e2eTestRunner: 'cypress' | 'none';
|
|
||||||
skipFormat: boolean;
|
|
||||||
}
|
|
||||||
@ -24,7 +24,7 @@ export interface BuildBuilderOptions {
|
|||||||
maxWorkers?: number;
|
maxWorkers?: number;
|
||||||
poll?: number;
|
poll?: number;
|
||||||
|
|
||||||
fileReplacements: FileReplacement[];
|
fileReplacements?: FileReplacement[];
|
||||||
assets?: any[];
|
assets?: any[];
|
||||||
|
|
||||||
progress?: boolean;
|
progress?: boolean;
|
||||||
|
|||||||
@ -62,7 +62,9 @@ describe('new', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('--packageManager', () => {
|
describe('--packageManager', () => {
|
||||||
describe.each([['npm'], ['yarn'], ['pnpm']])('%s', (packageManager) => {
|
describe.each([['npm'], ['yarn'], ['pnpm']])(
|
||||||
|
'%s',
|
||||||
|
(packageManager: 'npm' | 'yarn' | 'pnpm') => {
|
||||||
it('should set the packageManager in workspace.json', async () => {
|
it('should set the packageManager in workspace.json', async () => {
|
||||||
await newGenerator(tree, {
|
await newGenerator(tree, {
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
@ -77,7 +79,8 @@ describe('new', () => {
|
|||||||
const workspaceJson = readJson(tree, 'my-workspace/angular.json');
|
const workspaceJson = readJson(tree, 'my-workspace/angular.json');
|
||||||
expect(workspaceJson.cli.packageManager).toEqual(packageManager);
|
expect(workspaceJson.cli.packageManager).toEqual(packageManager);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not modify any existing files', async () => {
|
it('should not modify any existing files', async () => {
|
||||||
|
|||||||
@ -8,6 +8,9 @@ import {
|
|||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
names,
|
names,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
|
readWorkspaceConfiguration,
|
||||||
|
updateWorkspaceConfiguration,
|
||||||
|
WorkspaceConfiguration,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
@ -45,7 +48,7 @@ export interface Schema {
|
|||||||
commit?: { name: string; email: string; message?: string };
|
commit?: { name: string; email: string; message?: string };
|
||||||
defaultBase: string;
|
defaultBase: string;
|
||||||
linter: 'tslint' | 'eslint';
|
linter: 'tslint' | 'eslint';
|
||||||
packageManager?: string;
|
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
||||||
}
|
}
|
||||||
|
|
||||||
function generatePreset(host: Tree, opts: Schema) {
|
function generatePreset(host: Tree, opts: Schema) {
|
||||||
@ -344,13 +347,17 @@ function setDefaultPackageManager(host: Tree, options: Schema) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateJson(host, getWorkspacePath(host, options), (json) => {
|
updateJson<WorkspaceConfiguration>(
|
||||||
|
host,
|
||||||
|
getWorkspacePath(host, options),
|
||||||
|
(json) => {
|
||||||
if (!json.cli) {
|
if (!json.cli) {
|
||||||
json.cli = {};
|
json.cli = {};
|
||||||
}
|
}
|
||||||
json.cli['packageManager'] = options.packageManager;
|
json.cli.packageManager = options.packageManager;
|
||||||
return json;
|
return json;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDefault(
|
function setDefault(
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Tree } from '@nrwl/devkit';
|
import { readJson, Tree } from '@nrwl/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import { presetGenerator } from './preset';
|
import { presetGenerator } from './preset';
|
||||||
|
|
||||||
@ -9,9 +9,9 @@ describe('preset', () => {
|
|||||||
tree = createTreeWithEmptyWorkspace();
|
tree = createTreeWithEmptyWorkspace();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('--preset', () => {
|
||||||
// TODO: reenable. This doesn't work because wrapAngularDevkit uses the fs
|
// TODO: reenable. This doesn't work because wrapAngularDevkit uses the fs
|
||||||
xdescribe('--preset', () => {
|
xdescribe('angular', () => {
|
||||||
describe('angular', () => {
|
|
||||||
it('should create files (preset = angular)', async () => {
|
it('should create files (preset = angular)', async () => {
|
||||||
await presetGenerator(tree, {
|
await presetGenerator(tree, {
|
||||||
name: 'proj',
|
name: 'proj',
|
||||||
@ -29,6 +29,20 @@ describe('preset', () => {
|
|||||||
).toBe('@nrwl/angular');
|
).toBe('@nrwl/angular');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('web-components', () => {
|
||||||
|
it('should create files (preset = web-components)', async () => {
|
||||||
|
await presetGenerator(tree, {
|
||||||
|
name: 'proj',
|
||||||
|
preset: 'web-components',
|
||||||
|
cli: 'nx',
|
||||||
|
});
|
||||||
|
expect(tree.exists('/apps/proj/src/main.ts')).toBe(true);
|
||||||
|
expect(readJson(tree, '/workspace.json').cli.defaultCollection).toBe(
|
||||||
|
'@nrwl/web'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// it('should create files (preset = react)', async () => {
|
// it('should create files (preset = react)', async () => {
|
||||||
@ -43,17 +57,6 @@ describe('preset', () => {
|
|||||||
// ).toBe('@nrwl/react');
|
// ).toBe('@nrwl/react');
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// it('should create files (preset = web-components)', async () => {
|
|
||||||
// const tree = await runSchematic(
|
|
||||||
// 'preset',
|
|
||||||
// { name: 'proj', preset: 'web-components' },
|
|
||||||
// tree
|
|
||||||
// );
|
|
||||||
// expect(tree.exists('/apps/proj/src/main.ts')).toBe(true);
|
|
||||||
// expect(
|
|
||||||
// JSON.parse(tree.readContent('/workspace.json')).cli.defaultCollection
|
|
||||||
// ).toBe('@nrwl/web');
|
|
||||||
// });
|
|
||||||
//
|
//
|
||||||
// it('should create files (preset = next)', async () => {
|
// it('should create files (preset = next)', async () => {
|
||||||
// const tree = await runSchematic(
|
// const tree = await runSchematic(
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
"@nrwl/workspace/*": ["./packages/workspace/*"],
|
"@nrwl/workspace/*": ["./packages/workspace/*"],
|
||||||
"@nrwl/cli": ["./packages/cli"],
|
"@nrwl/cli": ["./packages/cli"],
|
||||||
"@nrwl/cli/*": ["./packages/cli/*"],
|
"@nrwl/cli/*": ["./packages/cli/*"],
|
||||||
|
"@nrwl/cypress": ["./packages/cypress"],
|
||||||
"@nrwl/express": ["./packages/express"],
|
"@nrwl/express": ["./packages/express"],
|
||||||
"@nrwl/nest": ["./packages/nest"],
|
"@nrwl/nest": ["./packages/nest"],
|
||||||
"@nrwl/next": ["./packages/next"],
|
"@nrwl/next": ["./packages/next"],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user