feat(angular): support for Angular 15 (#12112)
This commit is contained in:
parent
032a9d17d6
commit
b084dddff0
@ -184,13 +184,13 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
||||
// check project configuration
|
||||
const projectConfig = readJson(`apps/${project}/project.json`);
|
||||
expect(projectConfig.sourceRoot).toEqual(`apps/${project}/src`);
|
||||
expect(projectConfig.targets.build).toEqual({
|
||||
expect(projectConfig.targets.build).toStrictEqual({
|
||||
executor: '@angular-devkit/build-angular:browser',
|
||||
options: {
|
||||
outputPath: `dist/apps/${project}`,
|
||||
index: `apps/${project}/src/index.html`,
|
||||
main: `apps/${project}/src/main.ts`,
|
||||
polyfills: `apps/${project}/src/polyfills.ts`,
|
||||
polyfills: [`zone.js`],
|
||||
tsConfig: `apps/${project}/tsconfig.app.json`,
|
||||
assets: [
|
||||
`apps/${project}/src/favicon.ico`,
|
||||
@ -201,12 +201,6 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
||||
},
|
||||
configurations: {
|
||||
production: {
|
||||
fileReplacements: [
|
||||
{
|
||||
replace: `apps/${project}/src/environments/environment.ts`,
|
||||
with: `apps/${project}/src/environments/environment.prod.ts`,
|
||||
},
|
||||
],
|
||||
budgets: [
|
||||
{
|
||||
type: 'initial',
|
||||
@ -240,13 +234,11 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
||||
},
|
||||
defaultConfiguration: 'development',
|
||||
});
|
||||
expect(projectConfig.targets.test).toEqual({
|
||||
expect(projectConfig.targets.test).toStrictEqual({
|
||||
executor: '@angular-devkit/build-angular:karma',
|
||||
options: {
|
||||
main: `apps/${project}/src/test.ts`,
|
||||
polyfills: `apps/${project}/src/polyfills.ts`,
|
||||
polyfills: [`zone.js`, `zone.js/testing`],
|
||||
tsConfig: `apps/${project}/tsconfig.spec.json`,
|
||||
karmaConfig: `apps/${project}/karma.conf.js`,
|
||||
assets: [
|
||||
`apps/${project}/src/favicon.ico`,
|
||||
`apps/${project}/src/assets`,
|
||||
|
||||
@ -35,7 +35,6 @@ describe('Move Angular Project', () => {
|
||||
|
||||
// just check the output
|
||||
expect(moveOutput).toContain(`DELETE apps/${app1}`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/.browserslistrc`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.ts`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`);
|
||||
@ -44,7 +43,6 @@ describe('Move Angular Project', () => {
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/favicon.ico`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/index.html`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/main.ts`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/polyfills.ts`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/styles.css`);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/test-setup.ts`);
|
||||
expect(moveOutput).toContain(
|
||||
@ -54,12 +52,6 @@ describe('Move Angular Project', () => {
|
||||
`CREATE apps/${newPath}/src/app/app.module.ts`
|
||||
);
|
||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/assets/.gitkeep`);
|
||||
expect(moveOutput).toContain(
|
||||
`CREATE apps/${newPath}/src/environments/environment.prod.ts`
|
||||
);
|
||||
expect(moveOutput).toContain(
|
||||
`CREATE apps/${newPath}/src/environments/environment.ts`
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
27
package.json
27
package.json
@ -26,19 +26,19 @@
|
||||
"echo": "echo 123458"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect": "~0.1402.0",
|
||||
"@angular-devkit/build-angular": "~14.2.0",
|
||||
"@angular-devkit/core": "~14.2.0",
|
||||
"@angular-devkit/schematics": "~14.2.0",
|
||||
"@angular-devkit/architect": "~0.1500.0",
|
||||
"@angular-devkit/build-angular": "~15.0.0",
|
||||
"@angular-devkit/core": "~15.0.0",
|
||||
"@angular-devkit/schematics": "~15.0.0",
|
||||
"@angular-eslint/eslint-plugin": "~14.0.4",
|
||||
"@angular-eslint/eslint-plugin-template": "~14.0.4",
|
||||
"@angular-eslint/template-parser": "~14.0.4",
|
||||
"@angular/cli": "~14.2.0",
|
||||
"@angular/common": "~14.2.0",
|
||||
"@angular/compiler": "~14.2.0",
|
||||
"@angular/compiler-cli": "~14.2.0",
|
||||
"@angular/core": "~14.2.0",
|
||||
"@angular/router": "~14.2.0",
|
||||
"@angular/cli": "~15.0.0",
|
||||
"@angular/common": "~15.0.0",
|
||||
"@angular/compiler": "~15.0.0",
|
||||
"@angular/compiler-cli": "~15.0.0",
|
||||
"@angular/core": "~15.0.0",
|
||||
"@angular/router": "~15.0.0",
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
@ -74,7 +74,7 @@
|
||||
"@rollup/plugin-image": "^2.1.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^13.0.4",
|
||||
"@schematics/angular": "~14.2.0",
|
||||
"@schematics/angular": "~15.0.0",
|
||||
"@storybook/addon-essentials": "~6.5.9",
|
||||
"@storybook/angular": "^6.5.12",
|
||||
"@storybook/builder-webpack5": "~6.5.9",
|
||||
@ -121,6 +121,7 @@
|
||||
"autoprefixer": "10.4.12",
|
||||
"babel-jest": "28.1.3",
|
||||
"babel-loader": "^8.2.2",
|
||||
"browserslist": "^4.21.4",
|
||||
"chalk": "4.1.0",
|
||||
"chokidar": "^3.5.1",
|
||||
"commitizen": "^4.0.3",
|
||||
@ -185,7 +186,7 @@
|
||||
"mini-css-extract-plugin": "~2.4.7",
|
||||
"minimatch": "3.0.5",
|
||||
"next-sitemap": "^3.1.10",
|
||||
"ng-packagr": "~14.2.0",
|
||||
"ng-packagr": "~15.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"nx": "15.1.0-beta.2",
|
||||
"open": "^8.4.0",
|
||||
@ -241,7 +242,7 @@
|
||||
"url-loader": "^4.1.1",
|
||||
"verdaccio": "^5.0.4",
|
||||
"vite": "^3.2.3",
|
||||
"webpack": "^5.58.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-dev-server": "^4.9.3",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
|
||||
@ -190,6 +190,42 @@
|
||||
"version": "15.0.0-beta.1",
|
||||
"description": "Stop hashing karma spec files and config files for build targets and dependent tasks",
|
||||
"factory": "./src/migrations/update-15-0-0/add-karma-inputs"
|
||||
},
|
||||
"update-angular-cli-version-15-0-0": {
|
||||
"cli": "nx",
|
||||
"version": "15.2.0-beta.0",
|
||||
"description": "Update the @angular/cli package version to ~15.0.0.",
|
||||
"factory": "./src/migrations/update-15-2-0/update-angular-cli"
|
||||
},
|
||||
"remove-browserlist-config": {
|
||||
"cli": "nx",
|
||||
"version": "15.2.0-beta.0",
|
||||
"description": "Remove browserlist config as it's handled by build-angular",
|
||||
"factory": "./src/migrations/update-15-2-0/remove-browserlist-config"
|
||||
},
|
||||
"update-typescript-target": {
|
||||
"cli": "nx",
|
||||
"version": "15.2.0-beta.0",
|
||||
"description": "Update typescript target to ES2022",
|
||||
"factory": "./src/migrations/update-15-2-0/update-typescript-target"
|
||||
},
|
||||
"update-workspace-config": {
|
||||
"cli": "nx",
|
||||
"version": "15.2.0-beta.0",
|
||||
"description": "Remove bundleDependencies from server targets",
|
||||
"factory": "./src/migrations/update-15-2-0/update-workspace-config"
|
||||
},
|
||||
"update-platform-server-exports": {
|
||||
"cli": "ng",
|
||||
"version": "15.2.0-beta.0",
|
||||
"description": "Remove exported `@angular/platform-server` `renderModule` method. The `renderModule` method is now exported by the Angular CLI.",
|
||||
"factory": "./src/migrations/update-15-2-0/remove-platform-server-exports"
|
||||
},
|
||||
"update-karma-main-file": {
|
||||
"cli": "ng",
|
||||
"version": "15.2.0-beta.0",
|
||||
"description": "Remove no longer needed require calls in Karma builder main file.",
|
||||
"factory": "./src/migrations/update-15-2-0/update-karma-main-file"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {
|
||||
@ -1557,6 +1593,63 @@
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"15.2.0": {
|
||||
"version": "15.2.0-beta.0",
|
||||
"packages": {
|
||||
"@angular-devkit/architect": {
|
||||
"version": "~0.1500.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@angular-devkit/build-angular": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@angular-devkit/build-webpack": {
|
||||
"version": "~0.1500.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@angular-devkit/core": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@angular-devkit/schematics": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@schematics/angular": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@angular/core": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": true
|
||||
},
|
||||
"@angular/material": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@angular/cdk": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@nguniversal/common": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@nguniversal/express-engine": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@nguniversal/builders": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"ng-packagr": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
"migrations": "./migrations.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular-devkit/schematics": "~14.2.0",
|
||||
"@angular-devkit/schematics": "~15.0.0",
|
||||
"@nrwl/cypress": "file:../cypress",
|
||||
"@nrwl/devkit": "file:../devkit",
|
||||
"@nrwl/jest": "file:../jest",
|
||||
@ -48,7 +48,7 @@
|
||||
"@nrwl/webpack": "file:../webpack",
|
||||
"@nrwl/workspace": "file:../workspace",
|
||||
"@phenomnomnominal/tsquery": "4.1.1",
|
||||
"@schematics/angular": "~14.2.0",
|
||||
"@schematics/angular": "~15.0.0",
|
||||
"chalk": "4.1.0",
|
||||
"chokidar": "^3.5.1",
|
||||
"http-server": "^14.1.0",
|
||||
@ -58,7 +58,7 @@
|
||||
"semver": "7.3.4",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"webpack": "^5.58.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-merge": "5.7.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@ -167,7 +167,12 @@ function normalizeBuildTargetOptions(
|
||||
const buildOptions = withSchemaDefaults(options);
|
||||
|
||||
// paths need to be unix paths for angular devkit
|
||||
buildOptions.polyfills = joinPathFragments(offset, buildOptions.polyfills);
|
||||
buildOptions.polyfills =
|
||||
Array.isArray(buildOptions.polyfills) && buildOptions.polyfills.length > 0
|
||||
? (buildOptions.polyfills as string[]).map((p) =>
|
||||
joinPathFragments(offset, p)
|
||||
)
|
||||
: joinPathFragments(offset, buildOptions.polyfills as string);
|
||||
buildOptions.main = joinPathFragments(offset, buildOptions.main);
|
||||
buildOptions.index =
|
||||
typeof buildOptions.index === 'string'
|
||||
|
||||
@ -37,8 +37,22 @@
|
||||
"description": "The full path for the main entry point to the app, relative to the current workspace."
|
||||
},
|
||||
"polyfills": {
|
||||
"description": "Polyfills to be included in the build.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"description": "A list of polyfills to include in the build. Can be a full path for a file, relative to the current workspace or module specifier. Example: 'zone.js'.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "The full path for the polyfills file, relative to the current workspace."
|
||||
"uniqueItems": true
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The full path for the polyfills file, relative to the current workspace or a module specifier. Example: 'zone.js'."
|
||||
}
|
||||
]
|
||||
},
|
||||
"tsConfig": {
|
||||
"type": "string",
|
||||
|
||||
@ -17,7 +17,7 @@ import {
|
||||
saveCacheEntry,
|
||||
} from 'ng-packagr/lib/utils/cache';
|
||||
import * as log from 'ng-packagr/lib/utils/log';
|
||||
import { dirname, extname, join, resolve } from 'path';
|
||||
import { dirname, extname, join } from 'path';
|
||||
import * as postcssPresetEnv from 'postcss-preset-env';
|
||||
import * as postcssUrl from 'postcss-url';
|
||||
import {
|
||||
@ -26,6 +26,7 @@ import {
|
||||
tailwindDirectives,
|
||||
TailwindSetup,
|
||||
} from '../../../utilities/tailwindcss';
|
||||
import { pathToFileURL } from 'url';
|
||||
|
||||
const postcss = require('postcss');
|
||||
|
||||
@ -250,12 +251,10 @@ export class StylesheetProcessor {
|
||||
case '.sass':
|
||||
case '.scss': {
|
||||
return (await import('sass'))
|
||||
.renderSync({
|
||||
file: filePath,
|
||||
data: css,
|
||||
indentedSyntax: '.sass' === ext,
|
||||
importer: customSassImporter,
|
||||
includePaths: this.styleIncludePaths,
|
||||
.compileString(css, {
|
||||
url: pathToFileURL(filePath),
|
||||
syntax: '.sass' === ext ? 'indented' : 'scss',
|
||||
loadPaths: this.styleIncludePaths,
|
||||
})
|
||||
.css.toString();
|
||||
}
|
||||
@ -271,27 +270,6 @@ export class StylesheetProcessor {
|
||||
|
||||
return content;
|
||||
}
|
||||
case '.styl':
|
||||
case '.stylus': {
|
||||
const stylus = (await import('stylus')).default;
|
||||
|
||||
return (
|
||||
stylus(css)
|
||||
// add paths for resolve
|
||||
.set('paths', [
|
||||
this.basePath,
|
||||
'.',
|
||||
...this.styleIncludePaths,
|
||||
'node_modules',
|
||||
])
|
||||
// add support for resolving plugins from node_modules
|
||||
.set('filename', filePath)
|
||||
// turn on url resolver in stylus, same as flag --resolve-url
|
||||
.set('resolve url', true)
|
||||
.define('url', stylus.resolver(undefined))
|
||||
.render()
|
||||
);
|
||||
}
|
||||
case '.css':
|
||||
default:
|
||||
return css;
|
||||
@ -340,19 +318,3 @@ function transformSupportedBrowsersToTargets(
|
||||
|
||||
return transformed.length ? transformed : undefined;
|
||||
}
|
||||
|
||||
function customSassImporter(
|
||||
url: string,
|
||||
prev: string
|
||||
): { file: string; prev: string } | undefined {
|
||||
// NB: Sass importer should always be sync as otherwise it will cause
|
||||
// sass to go in the async path which is slower.
|
||||
if (url[0] !== '~') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
file: url.substring(1),
|
||||
prev,
|
||||
};
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ import {
|
||||
tailwindDirectives,
|
||||
TailwindSetup,
|
||||
} from '../../../utilities/tailwindcss';
|
||||
import { pathToFileURL } from 'url';
|
||||
|
||||
const postcss = require('postcss');
|
||||
|
||||
@ -243,12 +244,10 @@ export class StylesheetProcessor {
|
||||
case '.sass':
|
||||
case '.scss': {
|
||||
return (await import('sass'))
|
||||
.renderSync({
|
||||
file: filePath,
|
||||
data: css,
|
||||
indentedSyntax: '.sass' === ext,
|
||||
importer: customSassImporter,
|
||||
includePaths: this.styleIncludePaths,
|
||||
.compileString(css, {
|
||||
url: pathToFileURL(filePath),
|
||||
syntax: '.sass' === ext ? 'indented' : 'scss',
|
||||
loadPaths: this.styleIncludePaths,
|
||||
})
|
||||
.css.toString();
|
||||
}
|
||||
@ -264,27 +263,6 @@ export class StylesheetProcessor {
|
||||
|
||||
return content;
|
||||
}
|
||||
case '.styl':
|
||||
case '.stylus': {
|
||||
const stylus = await import('stylus');
|
||||
|
||||
return (
|
||||
stylus(css)
|
||||
// add paths for resolve
|
||||
.set('paths', [
|
||||
this.basePath,
|
||||
'.',
|
||||
...this.styleIncludePaths,
|
||||
'node_modules',
|
||||
])
|
||||
// add support for resolving plugins from node_modules
|
||||
.set('filename', filePath)
|
||||
// turn on url resolver in stylus, same as flag --resolve-url
|
||||
.set('resolve url', true)
|
||||
.define('url', stylus.resolver(undefined))
|
||||
.render()
|
||||
);
|
||||
}
|
||||
case '.css':
|
||||
default:
|
||||
return css;
|
||||
@ -333,19 +311,3 @@ function transformSupportedBrowsersToTargets(
|
||||
|
||||
return transformed.length ? transformed : undefined;
|
||||
}
|
||||
|
||||
function customSassImporter(
|
||||
url: string,
|
||||
prev: string
|
||||
): { file: string; prev: string } | undefined {
|
||||
// NB: Sass importer should always be sync as otherwise it will cause
|
||||
// sass to go in the async path which is slower.
|
||||
if (url[0] !== '~') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
file: url.substring(1),
|
||||
prev,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,17 +1,11 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`app --standalone should generate a standalone app correctly with routing 1`] = `
|
||||
"import { enableProdMode } from '@angular/core';
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
"import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { environment } from './environments/environment';
|
||||
import { appRoutes } from './app/app.routes';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [provideRouter(appRoutes, withEnabledBlockingInitialNavigation())],
|
||||
}).catch((err) => console.error(err));"
|
||||
@ -74,16 +68,10 @@ describe('AppComponent', () => {
|
||||
`;
|
||||
|
||||
exports[`app --standalone should generate a standalone app correctly without routing 1`] = `
|
||||
"import { enableProdMode } from '@angular/core';
|
||||
import { bootstrapApplication } from '@angular/platform-browser';;
|
||||
"import { bootstrapApplication } from '@angular/platform-browser';;
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
bootstrapApplication(AppComponent).catch((err) => console.error(err));"
|
||||
`;
|
||||
|
||||
@ -164,12 +152,6 @@ Object {
|
||||
"type": "anyComponentStyle",
|
||||
},
|
||||
],
|
||||
"fileReplacements": Array [
|
||||
Object {
|
||||
"replace": "apps/my-dir/my-app/src/environments/environment.ts",
|
||||
"with": "apps/my-dir/my-app/src/environments/environment.prod.ts",
|
||||
},
|
||||
],
|
||||
"outputHashing": "all",
|
||||
},
|
||||
},
|
||||
@ -182,7 +164,9 @@ Object {
|
||||
"index": "apps/my-dir/my-app/src/index.html",
|
||||
"main": "apps/my-dir/my-app/src/main.ts",
|
||||
"outputPath": "dist/apps/my-dir/my-app",
|
||||
"polyfills": "apps/my-dir/my-app/src/polyfills.ts",
|
||||
"polyfills": Array [
|
||||
"zone.js",
|
||||
],
|
||||
"scripts": Array [],
|
||||
"styles": Array [
|
||||
"apps/my-dir/my-app/src/styles.css",
|
||||
@ -336,12 +320,6 @@ Object {
|
||||
"type": "anyComponentStyle",
|
||||
},
|
||||
],
|
||||
"fileReplacements": Array [
|
||||
Object {
|
||||
"replace": "apps/my-app/src/environments/environment.ts",
|
||||
"with": "apps/my-app/src/environments/environment.prod.ts",
|
||||
},
|
||||
],
|
||||
"outputHashing": "all",
|
||||
},
|
||||
},
|
||||
@ -354,7 +332,9 @@ Object {
|
||||
"index": "apps/my-app/src/index.html",
|
||||
"main": "apps/my-app/src/main.ts",
|
||||
"outputPath": "dist/apps/my-app",
|
||||
"polyfills": "apps/my-app/src/polyfills.ts",
|
||||
"polyfills": Array [
|
||||
"zone.js",
|
||||
],
|
||||
"scripts": Array [],
|
||||
"styles": Array [
|
||||
"apps/my-app/src/styles.css",
|
||||
|
||||
@ -1038,6 +1038,24 @@ describe('app', () => {
|
||||
).toContain('standalone: true');
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate correct main.ts', async () => {
|
||||
// ACT
|
||||
await generateApp(appTree, 'myapp');
|
||||
|
||||
// ASSERT
|
||||
expect(appTree.read('apps/myapp/src/main.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
async function generateApp(
|
||||
|
||||
@ -45,21 +45,15 @@ function updateMainEntrypoint(
|
||||
|
||||
const standaloneComponentMainContents = (
|
||||
routerModuleSetup
|
||||
) => `import { enableProdMode } from '@angular/core';
|
||||
import { bootstrapApplication } from '@angular/platform-browser';${
|
||||
) => `import { bootstrapApplication } from '@angular/platform-browser';${
|
||||
routerModuleSetup
|
||||
? `
|
||||
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router'`
|
||||
: ``
|
||||
};
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { environment } from './environments/environment';
|
||||
${routerModuleSetup ? `import { appRoutes } from './app/app.routes';` : ''}
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
bootstrapApplication(AppComponent${
|
||||
routerModuleSetup
|
||||
? `, {
|
||||
|
||||
@ -38,7 +38,11 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) {
|
||||
// tsconfig.json
|
||||
updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({
|
||||
...json,
|
||||
compilerOptions: { ...json.compilerOptions, target: 'es2020' },
|
||||
compilerOptions: {
|
||||
...json.compilerOptions,
|
||||
target: 'es2022',
|
||||
useDefineForClassFields: false, // This will eventually need updated when Angular switch to using TC39 Compliant code
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
@ -116,8 +120,4 @@ function updateAppAndE2EProjectConfigurations(
|
||||
removeProjectConfiguration(host, options.e2eProjectName);
|
||||
}
|
||||
}
|
||||
|
||||
// delete some default test configs
|
||||
host.delete(`${options.appProjectRoot}/karma.conf.js`);
|
||||
host.delete(`${options.appProjectRoot}/src/test.ts`);
|
||||
}
|
||||
|
||||
@ -1,76 +1,56 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`component Generator --flat should create the component correctly and export it in the entry point 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator --flat should create the component correctly and not export it when "export=false" 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator --path should create the component correctly and export it in the entry point 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator secondary entry points should create the component correctly and export it in the entry point 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -82,19 +62,14 @@ export * from \\"./lib/example/example.component\\";"
|
||||
`;
|
||||
|
||||
exports[`component Generator should create the component correctly and export it in the entry point when "export=true" 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -106,7 +81,7 @@ export * from \\"./lib/example/example.component\\";"
|
||||
`;
|
||||
|
||||
exports[`component Generator should create the component correctly and export it in the entry point when is standalone and "export=true" 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -116,38 +91,28 @@ import { CommonModule } from '@angular/common';
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should create the component correctly and not export it in the entry point when "export=false" 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should create the component correctly and not export it in the entry point when is standalone and "export=false" 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -157,50 +122,35 @@ import { CommonModule } from '@angular/common';
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should create the component correctly and not export it when "--skip-import=true" 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`component Generator should create the component correctly but not export it in the entry point when it does not exist 1`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example',
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
"
|
||||
|
||||
@ -16,14 +16,7 @@ describe(SomethingOneComponent.name, () => {
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
cy.mount(SomethingOneComponent, {
|
||||
componentProperties: {
|
||||
type: 'button',
|
||||
style: 'default',
|
||||
age: 0,
|
||||
isOn: false,
|
||||
}
|
||||
});
|
||||
cy.mount(SomethingOneComponent,);
|
||||
})
|
||||
|
||||
})
|
||||
@ -46,14 +39,7 @@ describe(SomethingTwoComponent.name, () => {
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
cy.mount(SomethingTwoComponent, {
|
||||
componentProperties: {
|
||||
type: 'button',
|
||||
style: 'default',
|
||||
age: 0,
|
||||
isOn: false,
|
||||
}
|
||||
});
|
||||
cy.mount(SomethingTwoComponent,);
|
||||
})
|
||||
|
||||
})
|
||||
@ -76,14 +62,7 @@ describe(SomethingThreeComponent.name, () => {
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
cy.mount(SomethingThreeComponent, {
|
||||
componentProperties: {
|
||||
type: 'button',
|
||||
style: 'default',
|
||||
age: 0,
|
||||
isOn: false,
|
||||
}
|
||||
});
|
||||
cy.mount(SomethingThreeComponent,);
|
||||
})
|
||||
|
||||
})
|
||||
@ -106,14 +85,7 @@ describe(SomethingOneComponent.name, () => {
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
cy.mount(SomethingOneComponent, {
|
||||
componentProperties: {
|
||||
type: 'button',
|
||||
style: 'default',
|
||||
age: 0,
|
||||
isOn: false,
|
||||
}
|
||||
});
|
||||
cy.mount(SomethingOneComponent,);
|
||||
})
|
||||
|
||||
})
|
||||
@ -136,14 +108,7 @@ describe(SomethingTwoComponent.name, () => {
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
cy.mount(SomethingTwoComponent, {
|
||||
componentProperties: {
|
||||
type: 'button',
|
||||
style: 'default',
|
||||
age: 0,
|
||||
isOn: false,
|
||||
}
|
||||
});
|
||||
cy.mount(SomethingTwoComponent,);
|
||||
})
|
||||
|
||||
})
|
||||
@ -166,14 +131,7 @@ describe(SomethingThreeComponent.name, () => {
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
cy.mount(SomethingThreeComponent, {
|
||||
componentProperties: {
|
||||
type: 'button',
|
||||
style: 'default',
|
||||
age: 0,
|
||||
isOn: false,
|
||||
}
|
||||
});
|
||||
cy.mount(SomethingThreeComponent,);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -19,17 +19,11 @@ module.exports = withModuleFederation(config);"
|
||||
`;
|
||||
|
||||
exports[`Host App Generator should generate a host with remotes using standalone components 1`] = `
|
||||
"import { enableProdMode } from '@angular/core';
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
"import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { environment } from './environments/environment';
|
||||
import { appRoutes } from './app/app.routes';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [provideRouter(appRoutes, withEnabledBlockingInitialNavigation())],
|
||||
}).catch((err) => console.error(err));"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
exports[`lib --standalone should generate a library with a standalone component and have it flat 1`] = `"export * from \\"./lib/my-lib.component\\";"`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component and have it flat 2`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -13,12 +13,7 @@ import { CommonModule } from '@angular/common';
|
||||
templateUrl: './my-lib.component.html',
|
||||
styleUrls: ['./my-lib.component.css']
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -57,7 +52,7 @@ exports[`lib --standalone should generate a library with a standalone component
|
||||
`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component and have it flat with routing setup 2`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -67,12 +62,7 @@ import { CommonModule } from '@angular/common';
|
||||
templateUrl: './my-lib.component.html',
|
||||
styleUrls: ['./my-lib.component.css']
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -117,7 +107,7 @@ exports[`lib --standalone should generate a library with a standalone component
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point 2`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -127,12 +117,7 @@ import { CommonModule } from '@angular/common';
|
||||
templateUrl: './my-lib.component.html',
|
||||
styleUrls: ['./my-lib.component.css']
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -168,7 +153,7 @@ describe('MyLibComponent', () => {
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point and set up view encapsulation and change detection 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point and set up view encapsulation and change detection 2`] = `
|
||||
"import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
"import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -185,12 +170,7 @@ import { CommonModule } from '@angular/common';
|
||||
encapsulation: ViewEncapsulation.ShadowDom,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -199,7 +179,7 @@ export class MyLibComponent implements OnInit {
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point and skip tests 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point and skip tests 2`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -214,12 +194,7 @@ import { CommonModule } from '@angular/common';
|
||||
styles: [
|
||||
]
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -228,7 +203,7 @@ export class MyLibComponent implements OnInit {
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point following SFC pattern 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point following SFC pattern 2`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -243,12 +218,7 @@ import { CommonModule } from '@angular/common';
|
||||
styles: [
|
||||
]
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
@ -296,7 +266,7 @@ exports[`lib --standalone should generate a library with a standalone component
|
||||
`;
|
||||
|
||||
exports[`lib --standalone should generate a library with a standalone component as entry point with routing setup 3`] = `
|
||||
"import { Component, OnInit } from '@angular/core';
|
||||
"import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -306,12 +276,7 @@ import { CommonModule } from '@angular/common';
|
||||
templateUrl: './my-lib.component.html',
|
||||
styleUrls: ['./my-lib.component.css']
|
||||
})
|
||||
export class MyLibComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class MyLibComponent {
|
||||
|
||||
}
|
||||
"
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
generateFiles,
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
readProjectConfiguration,
|
||||
@ -11,9 +10,9 @@ import {
|
||||
} from '@nrwl/devkit';
|
||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils';
|
||||
import * as path from 'path';
|
||||
import { NormalizedSchema } from './normalized-schema';
|
||||
import { updateNgPackage } from './update-ng-package';
|
||||
import { join } from 'path';
|
||||
|
||||
export async function updateProject(
|
||||
host: Tree,
|
||||
@ -28,41 +27,48 @@ export async function updateProject(
|
||||
|
||||
function updateFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
|
||||
const libRoot = `${options.projectRoot}/src/lib/`;
|
||||
const serviceSpecPath = path.join(libRoot, `${options.name}.service.spec.ts`);
|
||||
const componentSpecPath = path.join(
|
||||
const serviceSpecPath = joinPathFragments(
|
||||
libRoot,
|
||||
`${options.name}.service.spec.ts`
|
||||
);
|
||||
const componentSpecPath = joinPathFragments(
|
||||
libRoot,
|
||||
`${options.name}.component.spec.ts`
|
||||
);
|
||||
|
||||
host.delete(path.join(libRoot, `${options.name}.service.ts`));
|
||||
host.delete(joinPathFragments(libRoot, `${options.name}.service.ts`));
|
||||
|
||||
if (host.exists(serviceSpecPath)) {
|
||||
host.delete(serviceSpecPath);
|
||||
}
|
||||
|
||||
host.delete(path.join(libRoot, `${options.name}.component.ts`));
|
||||
host.delete(joinPathFragments(libRoot, `${options.name}.component.ts`));
|
||||
|
||||
if (host.exists(componentSpecPath)) {
|
||||
host.delete(path.join(libRoot, `${options.name}.component.spec.ts`));
|
||||
host.delete(
|
||||
joinPathFragments(libRoot, `${options.name}.component.spec.ts`)
|
||||
);
|
||||
}
|
||||
|
||||
if (!options.publishable && !options.buildable) {
|
||||
host.delete(path.join(options.projectRoot, 'ng-package.json'));
|
||||
host.delete(path.join(options.projectRoot, 'package.json'));
|
||||
host.delete(path.join(options.projectRoot, 'tsconfig.lib.prod.json'));
|
||||
host.delete(path.join(options.projectRoot, '.browserslistrc'));
|
||||
host.delete(joinPathFragments(options.projectRoot, 'ng-package.json'));
|
||||
host.delete(joinPathFragments(options.projectRoot, 'package.json'));
|
||||
host.delete(
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.lib.prod.json')
|
||||
);
|
||||
host.delete(joinPathFragments(options.projectRoot, '.browserslistrc'));
|
||||
}
|
||||
|
||||
host.delete(path.join(options.projectRoot, 'karma.conf.js'));
|
||||
host.delete(path.join(options.projectRoot, 'src/test.ts'));
|
||||
host.delete(path.join(options.projectRoot, 'tsconfig.spec.json'));
|
||||
host.delete(joinPathFragments(options.projectRoot, 'karma.conf.js'));
|
||||
host.delete(joinPathFragments(options.projectRoot, 'src/test.ts'));
|
||||
host.delete(joinPathFragments(options.projectRoot, 'tsconfig.spec.json'));
|
||||
|
||||
if (options.name !== options.fileName) {
|
||||
host.delete(path.join(libRoot, `${options.name}.module.ts`));
|
||||
host.delete(joinPathFragments(libRoot, `${options.name}.module.ts`));
|
||||
}
|
||||
if (!options.skipModule && !options.standalone) {
|
||||
host.write(
|
||||
path.join(libRoot, `${options.fileName}.module.ts`),
|
||||
joinPathFragments(libRoot, `${options.fileName}.module.ts`),
|
||||
`
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@ -78,7 +84,7 @@ function updateFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
|
||||
|
||||
if (options.unitTestRunner !== 'none' && options.addModuleSpec) {
|
||||
host.write(
|
||||
path.join(libRoot, `${options.fileName}.module.spec.ts`),
|
||||
joinPathFragments(libRoot, `${options.fileName}.module.spec.ts`),
|
||||
`
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { ${options.moduleName} } from './${options.fileName}.module';
|
||||
@ -117,19 +123,11 @@ function updateFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
|
||||
}
|
||||
|
||||
function createFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
|
||||
generateFiles(
|
||||
host,
|
||||
path.join(__dirname, '../files/lib'),
|
||||
options.projectRoot,
|
||||
{
|
||||
generateFiles(host, join(__dirname, '../files/lib'), options.projectRoot, {
|
||||
...options,
|
||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
||||
host,
|
||||
options.projectRoot
|
||||
),
|
||||
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
||||
tpl: '',
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function fixProjectWorkspaceConfig(
|
||||
|
||||
@ -54,7 +54,11 @@ function updateProjectConfig(
|
||||
// tsconfig.json
|
||||
updateJson(host, `${options.projectRoot}/tsconfig.json`, (json) => ({
|
||||
...json,
|
||||
compilerOptions: { ...json.compilerOptions, target: 'es2020' },
|
||||
compilerOptions: {
|
||||
...json.compilerOptions,
|
||||
target: 'es2022',
|
||||
useDefineForClassFields: false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@ -288,7 +288,8 @@ describe('lib', () => {
|
||||
noImplicitOverride: true,
|
||||
noImplicitReturns: true,
|
||||
strict: true,
|
||||
target: 'es2020',
|
||||
target: 'es2022',
|
||||
useDefineForClassFields: false,
|
||||
},
|
||||
files: [],
|
||||
include: [],
|
||||
@ -397,7 +398,6 @@ describe('lib', () => {
|
||||
// ASSERT
|
||||
const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.lib.json');
|
||||
expect(tsconfigJson.exclude).toEqual([
|
||||
'src/test.ts',
|
||||
'**/*.spec.ts',
|
||||
'jest.config.ts',
|
||||
'**/*.test.ts',
|
||||
@ -677,7 +677,8 @@ describe('lib', () => {
|
||||
noImplicitOverride: true,
|
||||
noImplicitReturns: true,
|
||||
strict: true,
|
||||
target: 'es2020',
|
||||
target: 'es2022',
|
||||
useDefineForClassFields: false,
|
||||
},
|
||||
files: [],
|
||||
include: [],
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { offsetFromRoot } from '@nrwl/devkit';
|
||||
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { basename } from 'path';
|
||||
import type {
|
||||
@ -88,8 +88,9 @@ export class AngularDevkitKarmaMigrator extends BuilderMigrator {
|
||||
|
||||
target.options.main =
|
||||
target.options.main && this.convertAsset(target.options.main);
|
||||
target.options.polyfills =
|
||||
target.options.polyfills && this.convertAsset(target.options.polyfills);
|
||||
target.options.polyfills = Array.isArray(target.options.polyfills)
|
||||
? target.options.polyfills.map((p) => this.convertAsset(p))
|
||||
: target.options.polyfills && this.convertAsset(target.options.polyfills);
|
||||
target.options.tsConfig =
|
||||
target.options.tsConfig &&
|
||||
joinPathFragments(
|
||||
|
||||
@ -722,6 +722,56 @@ describe('app migrator', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should update build target with array of polyfills', async () => {
|
||||
const project = addProject('app1', {
|
||||
root: '',
|
||||
sourceRoot: 'src',
|
||||
architect: {
|
||||
build: {
|
||||
builder: '@angular-devkit/build-angular:browser',
|
||||
options: {
|
||||
outputPath: 'dist/app1',
|
||||
index: 'src/index.html',
|
||||
main: 'src/main.ts',
|
||||
polyfills: ['zone.js'],
|
||||
tsConfig: 'tsconfig.app.json',
|
||||
assets: ['src/favicon.ico', 'src/assets'],
|
||||
styles: ['src/styles.css'],
|
||||
scripts: [],
|
||||
},
|
||||
configurations: {
|
||||
production: {},
|
||||
development: {},
|
||||
},
|
||||
defaultConfiguration: 'production',
|
||||
},
|
||||
},
|
||||
});
|
||||
const migrator = new AppMigrator(tree, {}, project);
|
||||
|
||||
await migrator.migrate();
|
||||
|
||||
const { targets } = readProjectConfiguration(tree, 'app1');
|
||||
expect(targets.build).toStrictEqual({
|
||||
executor: '@angular-devkit/build-angular:browser',
|
||||
options: {
|
||||
outputPath: 'dist/apps/app1',
|
||||
index: 'apps/app1/src/index.html',
|
||||
main: 'apps/app1/src/main.ts',
|
||||
polyfills: ['zone.js'],
|
||||
tsConfig: 'apps/app1/tsconfig.app.json',
|
||||
assets: ['apps/app1/src/favicon.ico', 'apps/app1/src/assets'],
|
||||
styles: ['apps/app1/src/styles.css'],
|
||||
scripts: [],
|
||||
},
|
||||
configurations: {
|
||||
production: {},
|
||||
development: {},
|
||||
},
|
||||
defaultConfiguration: 'production',
|
||||
});
|
||||
});
|
||||
|
||||
it('should update build target when using a target name different than "build"', async () => {
|
||||
const project = addProject('app1', {
|
||||
root: '',
|
||||
|
||||
@ -197,7 +197,10 @@ export class AppMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
buildOptions.main =
|
||||
buildOptions.main && this.convertAsset(buildOptions.main);
|
||||
buildOptions.polyfills =
|
||||
buildOptions.polyfills && this.convertAsset(buildOptions.polyfills);
|
||||
buildOptions.polyfills &&
|
||||
(Array.isArray(buildOptions.polyfills)
|
||||
? buildOptions.polyfills.map((asset) => this.convertAsset(asset))
|
||||
: this.convertAsset(buildOptions.polyfills as string));
|
||||
buildOptions.tsConfig =
|
||||
buildOptions.tsConfig &&
|
||||
joinPathFragments(this.project.newRoot, basename(buildOptions.tsConfig));
|
||||
|
||||
@ -257,17 +257,15 @@ import { StoreModule } from '@ngrx/store';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import * as fromUsers from './+state/users.reducer';
|
||||
import { UsersEffects } from './+state/users.effects';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { environment } from '../environments/environment';
|
||||
import { StoreRouterConnectingModule } from '@ngrx/router-store';
|
||||
@NgModule({
|
||||
imports: [BrowserModule, RouterModule.forRoot([]), StoreModule.forRoot({}, {
|
||||
metaReducers: !environment.production ? [] : [],
|
||||
metaReducers: [],
|
||||
runtimeChecks: {
|
||||
strictActionImmutability: true,
|
||||
strictStateImmutability: true
|
||||
}
|
||||
}), EffectsModule.forRoot([UsersEffects]), !environment.production ? StoreDevtoolsModule.instrument() : [], StoreRouterConnectingModule.forRoot(), StoreModule.forFeature(fromUsers.USERS_FEATURE_KEY, fromUsers.usersReducer)],
|
||||
}), EffectsModule.forRoot([UsersEffects]), StoreRouterConnectingModule.forRoot(), StoreModule.forFeature(fromUsers.USERS_FEATURE_KEY, fromUsers.usersReducer)],
|
||||
declarations: [AppComponent],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
@ -283,17 +281,15 @@ exports[`ngrx should add an empty root module when minimal and root are set to t
|
||||
import { AppComponent } from './app.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { environment } from '../environments/environment';
|
||||
import { StoreRouterConnectingModule } from '@ngrx/router-store';
|
||||
@NgModule({
|
||||
imports: [BrowserModule, RouterModule.forRoot([]), StoreModule.forRoot({}, {
|
||||
metaReducers: !environment.production ? [] : [],
|
||||
metaReducers: [],
|
||||
runtimeChecks: {
|
||||
strictActionImmutability: true,
|
||||
strictStateImmutability: true
|
||||
}
|
||||
}), EffectsModule.forRoot([]), !environment.production ? StoreDevtoolsModule.instrument() : [], StoreRouterConnectingModule.forRoot()],
|
||||
}), EffectsModule.forRoot([]), StoreRouterConnectingModule.forRoot()],
|
||||
declarations: [AppComponent],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
@ -332,7 +328,7 @@ export const loadUsersFailure = createAction(
|
||||
`;
|
||||
|
||||
exports[`ngrx should generate the ngrx effects 1`] = `
|
||||
"import { Injectable } from '@angular/core';
|
||||
"import { Injectable, inject } from '@angular/core';
|
||||
import { createEffect, Actions, ofType } from '@ngrx/effects';
|
||||
import { fetch } from '@nrwl/angular';
|
||||
|
||||
@ -341,6 +337,8 @@ import * as UsersFeature from './users.reducer';
|
||||
|
||||
@Injectable()
|
||||
export class UsersEffects {
|
||||
private actions$ = inject(Actions);
|
||||
|
||||
init$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(UsersActions.initUsers),
|
||||
fetch({
|
||||
@ -354,14 +352,12 @@ export class UsersEffects {
|
||||
}
|
||||
})
|
||||
));
|
||||
|
||||
constructor(private readonly actions$: Actions) {}
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ngrx should generate the ngrx facade 1`] = `
|
||||
"import { Injectable } from '@angular/core';
|
||||
"import { Injectable, inject } from '@angular/core';
|
||||
import { select, Store, Action } from '@ngrx/store';
|
||||
|
||||
import * as UsersActions from './users.actions';
|
||||
@ -370,6 +366,8 @@ import * as UsersSelectors from './users.selectors';
|
||||
|
||||
@Injectable()
|
||||
export class UsersFacade {
|
||||
private readonly store = inject(Store);
|
||||
|
||||
/**
|
||||
* Combine pieces of state using createSelector,
|
||||
* and expose them as observables through the facade.
|
||||
@ -378,8 +376,6 @@ export class UsersFacade {
|
||||
allUsers$ = this.store.pipe(select(UsersSelectors.getAllUsers));
|
||||
selectedUsers$ = this.store.pipe(select(UsersSelectors.getSelected));
|
||||
|
||||
constructor(private readonly store: Store) {}
|
||||
|
||||
/**
|
||||
* Use the initialization action to perform one
|
||||
* or more tasks in your Effects.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { createEffect, Actions, ofType } from '@ngrx/effects';
|
||||
import { fetch } from '@nrwl/angular';
|
||||
|
||||
@ -7,6 +7,8 @@ import * as <%= className %>Feature from './<%= fileName %>.reducer';
|
||||
|
||||
@Injectable()
|
||||
export class <%= className %>Effects {
|
||||
private actions$ = inject(Actions);
|
||||
|
||||
init$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(<%= className %>Actions.init<%= className %>),
|
||||
fetch({
|
||||
@ -20,6 +22,4 @@ export class <%= className %>Effects {
|
||||
}
|
||||
})
|
||||
));
|
||||
|
||||
constructor(private readonly actions$: Actions) {}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { select, Store, Action } from '@ngrx/store';
|
||||
|
||||
import * as <%= className %>Actions from './<%= fileName %>.actions';
|
||||
@ -7,6 +7,8 @@ import * as <%= className %>Selectors from './<%= fileName %>.selectors';
|
||||
|
||||
@Injectable()
|
||||
export class <%= className %>Facade {
|
||||
private readonly store = inject(Store);
|
||||
|
||||
/**
|
||||
* Combine pieces of state using createSelector,
|
||||
* and expose them as observables through the facade.
|
||||
@ -15,8 +17,6 @@ export class <%= className %>Facade {
|
||||
all<%= className %>$ = this.store.pipe(select(<%= className %>Selectors.getAll<%= className %>));
|
||||
selected<%= className %>$ = this.store.pipe(select(<%= className %>Selectors.getSelected));
|
||||
|
||||
constructor(private readonly store: Store) {}
|
||||
|
||||
/**
|
||||
* Use the initialization action to perform one
|
||||
* or more tasks in your Effects.
|
||||
|
||||
@ -50,7 +50,7 @@ export function addImportsToModule(
|
||||
const propertyName = `${names(options.name).propertyName}`;
|
||||
const reducerImports = `* as from${className}`;
|
||||
|
||||
const storeMetaReducers = `metaReducers: !environment.production ? [] : []`;
|
||||
const storeMetaReducers = `metaReducers: []`;
|
||||
|
||||
const storeForRoot = `StoreModule.forRoot({}, {
|
||||
${storeMetaReducers},
|
||||
@ -63,7 +63,6 @@ export function addImportsToModule(
|
||||
const effectsForEmptyRoot = `EffectsModule.forRoot([])`;
|
||||
const storeForFeature = `StoreModule.forFeature(from${className}.${constantName}_FEATURE_KEY, from${className}.${propertyName}Reducer)`;
|
||||
const effectsForFeature = `EffectsModule.forFeature([${effectsName}])`;
|
||||
const devTools = `!environment.production ? StoreDevtoolsModule.instrument() : []`;
|
||||
const storeRouterModule = 'StoreRouterConnectingModule.forRoot()';
|
||||
|
||||
// this is just a heuristic
|
||||
@ -73,17 +72,6 @@ export function addImportsToModule(
|
||||
sourceFile = addImport(sourceFile, 'EffectsModule', '@ngrx/effects');
|
||||
|
||||
if (options.minimal && options.root) {
|
||||
sourceFile = addImport(
|
||||
sourceFile,
|
||||
'StoreDevtoolsModule',
|
||||
'@ngrx/store-devtools'
|
||||
);
|
||||
sourceFile = addImport(
|
||||
sourceFile,
|
||||
'environment',
|
||||
'../environments/environment'
|
||||
);
|
||||
|
||||
sourceFile = addImportToModule(tree, sourceFile, modulePath, storeForRoot);
|
||||
sourceFile = addImportToModule(
|
||||
tree,
|
||||
@ -91,7 +79,6 @@ export function addImportsToModule(
|
||||
modulePath,
|
||||
effectsForEmptyRoot
|
||||
);
|
||||
sourceFile = addImportToModule(tree, sourceFile, modulePath, devTools);
|
||||
|
||||
if (hasRouter) {
|
||||
sourceFile = addImport(
|
||||
@ -127,17 +114,6 @@ export function addImportsToModule(
|
||||
if (options.root) {
|
||||
sourceFile = addCommonImports();
|
||||
|
||||
sourceFile = addImport(
|
||||
sourceFile,
|
||||
'StoreDevtoolsModule',
|
||||
'@ngrx/store-devtools'
|
||||
);
|
||||
sourceFile = addImport(
|
||||
sourceFile,
|
||||
'environment',
|
||||
'../environments/environment'
|
||||
);
|
||||
|
||||
sourceFile = addImportToModule(
|
||||
tree,
|
||||
sourceFile,
|
||||
@ -150,7 +126,6 @@ export function addImportsToModule(
|
||||
modulePath,
|
||||
effectsForRoot
|
||||
);
|
||||
sourceFile = addImportToModule(tree, sourceFile, modulePath, devTools);
|
||||
|
||||
if (hasRouter) {
|
||||
sourceFile = addImport(
|
||||
|
||||
@ -26,7 +26,7 @@ describe('scam-to-standalone', () => {
|
||||
|
||||
expect(tree.read('apps/foo/src/app/bar/bar.component.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -36,12 +36,7 @@ describe('scam-to-standalone', () => {
|
||||
templateUrl: './bar.component.html',
|
||||
styleUrls: ['./bar.component.css']
|
||||
})
|
||||
export class BarComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class BarComponent {
|
||||
|
||||
}
|
||||
"
|
||||
|
||||
@ -48,7 +48,7 @@ describe('convertComponentToScam', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -56,12 +56,7 @@ describe('convertComponentToScam', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
@ -177,7 +172,7 @@ describe('convertComponentToScam', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -185,12 +180,7 @@ describe('convertComponentToScam', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
@ -310,7 +300,7 @@ describe('convertComponentToScam', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -318,12 +308,7 @@ describe('convertComponentToScam', () => {
|
||||
templateUrl: './example.random.html',
|
||||
styleUrls: ['./example.random.css']
|
||||
})
|
||||
export class ExampleRandom implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleRandom {
|
||||
|
||||
}
|
||||
|
||||
@ -444,7 +429,7 @@ describe('convertComponentToScam', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentModuleSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -452,12 +437,7 @@ describe('convertComponentToScam', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
@ -517,7 +497,7 @@ describe('convertComponentToScam', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentModuleSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -525,12 +505,7 @@ describe('convertComponentToScam', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ describe('SCAM Generator', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -33,12 +33,7 @@ describe('SCAM Generator', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
@ -159,7 +154,7 @@ describe('SCAM Generator', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -167,12 +162,7 @@ describe('SCAM Generator', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
@ -208,7 +198,7 @@ describe('SCAM Generator', () => {
|
||||
'utf-8'
|
||||
);
|
||||
expect(componentSource).toMatchInlineSnapshot(`
|
||||
"import { Component, OnInit, NgModule } from '@angular/core';
|
||||
"import { Component, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
@ -216,12 +206,7 @@ describe('SCAM Generator', () => {
|
||||
templateUrl: './example.component.html',
|
||||
styleUrls: ['./example.component.css']
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
export class ExampleComponent {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import removeBrowserlistConfig, {
|
||||
DEFAULT_BROWSERS,
|
||||
} from './remove-browserlist-config';
|
||||
import applicationGenerator from '../../generators/application/application';
|
||||
|
||||
describe('Migration to delete Browserslist configurations', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(async () => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
await applicationGenerator(tree, {
|
||||
name: 'test',
|
||||
});
|
||||
});
|
||||
|
||||
describe('given the Browserslist config matches the default', () => {
|
||||
it('should delete ".browserslistrc" file', async () => {
|
||||
tree.write(
|
||||
'apps/test/src/app/.browserslistrc',
|
||||
DEFAULT_BROWSERS.join('\n')
|
||||
);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
|
||||
|
||||
await removeBrowserlistConfig(tree);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should not delete "browserslist" in 'node_modules'`, async () => {
|
||||
tree.write('node_modules/browserslist', DEFAULT_BROWSERS.join('\n'));
|
||||
tree.write('node_modules/.browserslistrc', DEFAULT_BROWSERS.join('\n'));
|
||||
|
||||
await removeBrowserlistConfig(tree);
|
||||
expect(tree.exists('node_modules/browserslist')).toBeTruthy();
|
||||
expect(tree.exists('node_modules/.browserslistrc')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('given the Browserslist config does not match the default', () => {
|
||||
it('should not delete "browserslist"', async () => {
|
||||
tree.write('apps/test/src/app/browserslist', 'last 1 Chrome version');
|
||||
|
||||
await removeBrowserlistConfig(tree);
|
||||
expect(tree.exists('apps/test/src/app/browserslist')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not delete ".browserslistrc"', async () => {
|
||||
tree.write('apps/test/src/app/.browserslistrc', 'last 1 Chrome version');
|
||||
|
||||
await removeBrowserlistConfig(tree);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should delete ".browserslistrc" file when it only includes non supported ES5 browsers', async () => {
|
||||
tree.write(
|
||||
'apps/test/src/app/.browserslistrc',
|
||||
[...DEFAULT_BROWSERS, 'IE 10'].join('\n')
|
||||
);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
|
||||
|
||||
await removeBrowserlistConfig(tree);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not delete ".browserslistrc" file when it includes additional config sections', async () => {
|
||||
tree.write(
|
||||
'apps/test/src/app/.browserslistrc',
|
||||
`
|
||||
${DEFAULT_BROWSERS.join('\n')}
|
||||
[modern]
|
||||
last 1 chrome version
|
||||
`
|
||||
);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
|
||||
|
||||
await removeBrowserlistConfig(tree);
|
||||
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,77 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import { logger, visitNotIgnoredFiles } from '@nrwl/devkit';
|
||||
import { basename } from 'path';
|
||||
|
||||
const validBrowserslistConfigFilenames = new Set([
|
||||
'browserslist',
|
||||
'.browserslistrc',
|
||||
]);
|
||||
|
||||
export const DEFAULT_BROWSERS = [
|
||||
'last 1 Chrome version',
|
||||
'last 1 Firefox version',
|
||||
'last 2 Edge major versions',
|
||||
'last 2 Safari major versions',
|
||||
'last 2 iOS major versions',
|
||||
'Firefox ESR',
|
||||
];
|
||||
|
||||
export default async function removeBrowserlistConfig(tree: Tree) {
|
||||
let browserslist: any;
|
||||
|
||||
try {
|
||||
browserslist = await import('browserslist');
|
||||
} catch {
|
||||
logger.warn(
|
||||
'Skipping migration because the "browserslist" package could not be loaded.'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the defaults to match the defaults in build-angular.
|
||||
browserslist.defaults = DEFAULT_BROWSERS;
|
||||
|
||||
const defaultSupportedBrowsers = new Set(browserslist(DEFAULT_BROWSERS));
|
||||
const es5Browsers = new Set(browserslist(['supports es6-module']));
|
||||
|
||||
visitNotIgnoredFiles(tree, '/', (path) => {
|
||||
const fileName = basename(path);
|
||||
if (
|
||||
!validBrowserslistConfigFilenames.has(fileName) ||
|
||||
path.startsWith('node_modules')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { defaults: browsersListConfig, ...otherConfigs } =
|
||||
browserslist.parseConfig(tree.read(path, 'utf-8'));
|
||||
|
||||
if (Object.keys(otherConfigs).length) {
|
||||
// The config contains additional sections.
|
||||
return;
|
||||
}
|
||||
|
||||
const browserslistInProject = browserslist(
|
||||
// Exclude from the list ES5 browsers which are not supported.
|
||||
browsersListConfig.map((s) => `${s} and supports es6-module`),
|
||||
{
|
||||
ignoreUnknownVersions: true,
|
||||
}
|
||||
);
|
||||
|
||||
if (defaultSupportedBrowsers.size !== browserslistInProject.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldDelete = browserslistInProject.every((browser) =>
|
||||
defaultSupportedBrowsers.has(browser)
|
||||
);
|
||||
|
||||
if (shouldDelete) {
|
||||
// All browsers are the same as the default config.
|
||||
// Delete file as it's redundant.
|
||||
tree.delete(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { DirEntry, Rule, UpdateRecorder } from '@angular-devkit/schematics';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> {
|
||||
for (const path of directory.subfiles) {
|
||||
if (path.endsWith('.ts') && !path.endsWith('.d.ts')) {
|
||||
const entry = directory.file(path);
|
||||
if (entry) {
|
||||
const content = entry.content;
|
||||
if (
|
||||
content.includes('@angular/platform-server') &&
|
||||
content.includes('renderModule')
|
||||
) {
|
||||
const source = ts.createSourceFile(
|
||||
entry.path,
|
||||
content.toString().replace(/^\uFEFF/, ''),
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
yield source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const path of directory.subdirs) {
|
||||
if (path === 'node_modules' || path.startsWith('.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield* visit(directory.dir(path));
|
||||
}
|
||||
}
|
||||
|
||||
export default function (): Rule {
|
||||
return (tree) => {
|
||||
for (const sourceFile of visit(tree.root)) {
|
||||
let recorder: UpdateRecorder | undefined;
|
||||
let printer: ts.Printer | undefined;
|
||||
|
||||
ts.forEachChild(sourceFile, function analyze(node) {
|
||||
if (
|
||||
!(
|
||||
ts.isExportDeclaration(node) &&
|
||||
node.moduleSpecifier &&
|
||||
ts.isStringLiteral(node.moduleSpecifier) &&
|
||||
node.moduleSpecifier.text === '@angular/platform-server' &&
|
||||
node.exportClause &&
|
||||
ts.isNamedExports(node.exportClause)
|
||||
)
|
||||
) {
|
||||
// Not a @angular/platform-server named export.
|
||||
return;
|
||||
}
|
||||
|
||||
const exportClause = node.exportClause;
|
||||
const newElements: ts.ExportSpecifier[] = [];
|
||||
for (const element of exportClause.elements) {
|
||||
if (element.name.text !== 'renderModule') {
|
||||
newElements.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (newElements.length === exportClause.elements.length) {
|
||||
// No changes
|
||||
return;
|
||||
}
|
||||
|
||||
recorder ??= tree.beginUpdate(sourceFile.fileName);
|
||||
|
||||
if (newElements.length) {
|
||||
// Update named exports as there are leftovers.
|
||||
const newExportClause = ts.factory.updateNamedExports(
|
||||
exportClause,
|
||||
newElements
|
||||
);
|
||||
printer ??= ts.createPrinter();
|
||||
const fix = printer.printNode(
|
||||
ts.EmitHint.Unspecified,
|
||||
newExportClause,
|
||||
sourceFile
|
||||
);
|
||||
|
||||
const index = exportClause.getStart();
|
||||
const length = exportClause.getWidth();
|
||||
recorder.remove(index, length).insertLeft(index, fix);
|
||||
} else {
|
||||
// Delete export as no exports remain.
|
||||
recorder.remove(node.getStart(), node.getWidth());
|
||||
}
|
||||
|
||||
ts.forEachChild(node, analyze);
|
||||
});
|
||||
|
||||
if (recorder) {
|
||||
tree.commitUpdate(recorder);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
import { readJson, Tree, writeJson } from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import updateAngularCli from './update-angular-cli';
|
||||
|
||||
describe('update-angular-cli migration', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should update @angular/cli version when defined as a dev dependency', async () => {
|
||||
writeJson(tree, 'package.json', {
|
||||
devDependencies: { '@angular/cli': '~13.3.0' },
|
||||
});
|
||||
|
||||
await updateAngularCli(tree);
|
||||
|
||||
const { devDependencies } = readJson(tree, 'package.json');
|
||||
expect(devDependencies['@angular/cli']).toEqual('~15.0.0');
|
||||
});
|
||||
|
||||
it('should update @angular/cli version when defined as a dependency', async () => {
|
||||
writeJson(tree, 'package.json', {
|
||||
dependencies: { '@angular/cli': '~13.3.0' },
|
||||
});
|
||||
|
||||
await updateAngularCli(tree);
|
||||
|
||||
const { dependencies } = readJson(tree, 'package.json');
|
||||
expect(dependencies['@angular/cli']).toEqual('~15.0.0');
|
||||
});
|
||||
|
||||
it('should add @angular/cli to package.json when it is not set', async () => {
|
||||
const initialPackageJson = readJson(tree, 'package.json');
|
||||
|
||||
await updateAngularCli(tree);
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson).toStrictEqual(initialPackageJson);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
import { formatFiles, Tree, updateJson } from '@nrwl/devkit';
|
||||
|
||||
const angularCliVersion = '~15.0.0';
|
||||
|
||||
export default async function (tree: Tree) {
|
||||
let shouldFormat = false;
|
||||
|
||||
updateJson(tree, 'package.json', (json) => {
|
||||
if (json.devDependencies?.['@angular/cli']) {
|
||||
json.devDependencies['@angular/cli'] = angularCliVersion;
|
||||
shouldFormat = true;
|
||||
} else if (json.dependencies?.['@angular/cli']) {
|
||||
json.dependencies['@angular/cli'] = angularCliVersion;
|
||||
shouldFormat = true;
|
||||
}
|
||||
|
||||
return json;
|
||||
});
|
||||
|
||||
if (shouldFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { Rule, Tree } from '@angular-devkit/schematics';
|
||||
import * as ts from 'typescript';
|
||||
import { readWorkspace } from '@schematics/angular/utility';
|
||||
import { Builders } from '@schematics/angular/utility/workspace-models';
|
||||
import { allTargetOptions } from '@schematics/angular/utility/workspace';
|
||||
|
||||
export default function (): Rule {
|
||||
return async (host) => {
|
||||
for (const file of await findTestMainFiles(host)) {
|
||||
updateTestFile(host, file);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function findTestMainFiles(host: Tree): Promise<Set<string>> {
|
||||
const testFiles = new Set<string>();
|
||||
const workspace = await readWorkspace(host);
|
||||
|
||||
// find all test.ts files.
|
||||
for (const project of workspace.projects.values()) {
|
||||
for (const target of project.targets.values()) {
|
||||
if (target.builder !== Builders.Karma) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const [, options] of allTargetOptions(target)) {
|
||||
if (typeof options.main === 'string' && host.exists(options.main)) {
|
||||
testFiles.add(options.main);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return testFiles;
|
||||
}
|
||||
|
||||
function updateTestFile(host: Tree, file: string): void {
|
||||
const content = host.readText(file);
|
||||
if (!content.includes('require.context')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceFile = ts.createSourceFile(
|
||||
file,
|
||||
content.replace(/^\uFEFF/, ''),
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
const usedVariableNames = new Set<string>();
|
||||
const recorder = host.beginUpdate(sourceFile.fileName);
|
||||
|
||||
ts.forEachChild(sourceFile, (node) => {
|
||||
if (ts.isVariableStatement(node)) {
|
||||
const variableDeclaration = node.declarationList.declarations[0];
|
||||
|
||||
if (
|
||||
ts
|
||||
.getModifiers(node)
|
||||
?.some((m) => m.kind === ts.SyntaxKind.DeclareKeyword)
|
||||
) {
|
||||
// `declare const require`
|
||||
if (variableDeclaration.name.getText() !== 'require') {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// `const context = require.context('./', true, /\.spec\.ts$/);`
|
||||
if (
|
||||
!variableDeclaration.initializer
|
||||
?.getText()
|
||||
.startsWith('require.context')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add variable name as used.
|
||||
usedVariableNames.add(variableDeclaration.name.getText());
|
||||
}
|
||||
|
||||
// Delete node.
|
||||
recorder.remove(node.getFullStart(), node.getFullWidth());
|
||||
}
|
||||
|
||||
if (
|
||||
usedVariableNames.size &&
|
||||
ts.isExpressionStatement(node) && // context.keys().map(context);
|
||||
ts.isCallExpression(node.expression) && // context.keys().map(context);
|
||||
ts.isPropertyAccessExpression(node.expression.expression) && // context.keys().map
|
||||
ts.isCallExpression(node.expression.expression.expression) && // context.keys()
|
||||
ts.isPropertyAccessExpression(
|
||||
node.expression.expression.expression.expression
|
||||
) && // context.keys
|
||||
ts.isIdentifier(
|
||||
node.expression.expression.expression.expression.expression
|
||||
) && // context
|
||||
usedVariableNames.has(
|
||||
node.expression.expression.expression.expression.expression.getText()
|
||||
)
|
||||
) {
|
||||
// `context.keys().map(context);`
|
||||
// `context.keys().forEach(context);`
|
||||
recorder.remove(node.getFullStart(), node.getFullWidth());
|
||||
}
|
||||
});
|
||||
|
||||
host.commitUpdate(recorder);
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
import {
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import applicationGenerator from '../../generators/application/application';
|
||||
import updateTypescriptTarget from './update-typescript-target';
|
||||
import { UnitTestRunner } from '@nrwl/angular/src/utils/test-runners';
|
||||
|
||||
describe('Migration to update target and add useDefineForClassFields', () => {
|
||||
let tree: Tree;
|
||||
beforeEach(async () => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
await applicationGenerator(tree, {
|
||||
name: 'test',
|
||||
});
|
||||
await applicationGenerator(tree, {
|
||||
name: 'karma',
|
||||
unitTestRunner: UnitTestRunner.Karma,
|
||||
});
|
||||
|
||||
// Create tsconfigs
|
||||
const compilerOptions = { target: 'es2015', module: 'es2020' };
|
||||
const configWithExtends = {
|
||||
extends: '../../tsconfig.base.json',
|
||||
compilerOptions,
|
||||
};
|
||||
|
||||
// Workspace
|
||||
writeJson(tree, 'tsconfig.base.json', { compilerOptions });
|
||||
|
||||
// Application
|
||||
writeJson(tree, 'apps/test/tsconfig.app.json', configWithExtends);
|
||||
writeJson(tree, 'apps/test/tsconfig.app.prod.json', configWithExtends);
|
||||
writeJson(tree, 'apps/test/tsconfig.spec.json', { compilerOptions });
|
||||
writeJson(tree, 'apps/karma/tsconfig.spec.json', { compilerOptions });
|
||||
});
|
||||
|
||||
it(`should not update target and not add useDefineForClassFields in workspace 'tsconfig.base.json'`, async () => {
|
||||
await updateTypescriptTarget(tree);
|
||||
const compilerOptions = readJson(
|
||||
tree,
|
||||
'tsconfig.base.json'
|
||||
).compilerOptions;
|
||||
expect(compilerOptions).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"module": "es2020",
|
||||
"target": "es2015",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it(`should add correct target value and useDefineForClassFields from tsconfig referenced in options and configuration`, async () => {
|
||||
const project = readProjectConfiguration(tree, 'test');
|
||||
project.targets.build.configurations.production.tsConfig =
|
||||
'apps/test/tsconfig.app.prod.json';
|
||||
updateProjectConfiguration(tree, 'test', project);
|
||||
|
||||
await updateTypescriptTarget(tree);
|
||||
|
||||
const compilerOptions = readJson(
|
||||
tree,
|
||||
'apps/test/tsconfig.app.prod.json'
|
||||
).compilerOptions;
|
||||
expect(compilerOptions['target']).toEqual('ES2022');
|
||||
expect(compilerOptions['useDefineForClassFields']).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should add target and useDefineForClassFields when tsconfig is not extended', async () => {
|
||||
await updateTypescriptTarget(tree);
|
||||
const compilerOptions = readJson(
|
||||
tree,
|
||||
'apps/karma/tsconfig.spec.json'
|
||||
).compilerOptions;
|
||||
expect(compilerOptions).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"module": "es2020",
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,53 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import { getProjects, updateJson } from '@nrwl/devkit';
|
||||
import { Builders } from '@schematics/angular/utility/workspace-models';
|
||||
|
||||
function updateTarget(tree: Tree, tsconfigPath: string) {
|
||||
updateJson(tree, tsconfigPath, (json) => ({
|
||||
...json,
|
||||
compilerOptions: {
|
||||
...(json.compilerOptions ?? {}),
|
||||
target: 'ES2022',
|
||||
useDefineForClassFields: false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
export default async function updateTypescriptTarget(tree: Tree) {
|
||||
const projects = getProjects(tree);
|
||||
for (const [, project] of projects) {
|
||||
for (const [, target] of Object.entries(project.targets)) {
|
||||
// Update all other known CLI builders that use a tsconfig
|
||||
const tsConfigs = [
|
||||
target.options || {},
|
||||
...Object.values(target.configurations || {}),
|
||||
]
|
||||
.filter((opt) => typeof opt?.tsConfig === 'string')
|
||||
.map((opt) => (opt as { tsConfig: string }).tsConfig);
|
||||
|
||||
const uniqueTsConfigs = [...new Set(tsConfigs)];
|
||||
|
||||
if (uniqueTsConfigs.length < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const supportedExecutors = new Set([
|
||||
Builders.Server,
|
||||
Builders.Karma,
|
||||
Builders.Browser,
|
||||
Builders.NgPackagr,
|
||||
'@nrwl/angular:webpack-browser',
|
||||
'@nrwl/angular:ng-packagr-lite',
|
||||
'@nrwl/angular:package',
|
||||
'@nrwl/angular:delegate-build',
|
||||
'@nrwl/jest:jest',
|
||||
]);
|
||||
|
||||
if (supportedExecutors.has(target.executor)) {
|
||||
for (const tsConfig of uniqueTsConfigs) {
|
||||
updateTarget(tree, tsConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import applicationGenerator from '../../generators/application/application';
|
||||
import updateWorkspaceConfig from './update-workspace-config';
|
||||
import {
|
||||
readProjectConfiguration,
|
||||
updateProjectConfiguration,
|
||||
} from 'nx/src/generators/utils/project-configuration';
|
||||
import { Builders } from '@schematics/angular/utility/workspace-models';
|
||||
|
||||
describe(`Migration to remove bundleDependencies`, () => {
|
||||
it(`should remove 'bundleDependencies'`, async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
await applicationGenerator(tree, {
|
||||
name: 'test',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'test');
|
||||
project.targets.server = {
|
||||
executor: Builders.Server,
|
||||
options: {
|
||||
main: './server.ts',
|
||||
bundleDependencies: false,
|
||||
sourceMaps: true,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any,
|
||||
configurations: {
|
||||
one: {
|
||||
aot: true,
|
||||
},
|
||||
two: {
|
||||
bundleDependencies: true,
|
||||
aot: true,
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any,
|
||||
};
|
||||
updateProjectConfiguration(tree, 'test', project);
|
||||
|
||||
await updateWorkspaceConfig(tree);
|
||||
|
||||
const updatedProject = readProjectConfiguration(tree, 'test');
|
||||
const { options, configurations } = updatedProject.targets.server;
|
||||
|
||||
expect(options.bundleDependencies).toBeUndefined();
|
||||
expect(configurations).toBeDefined();
|
||||
expect(configurations?.one.bundleDependencies).toBeUndefined();
|
||||
expect(configurations?.two.bundleDependencies).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,28 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import { getProjects, updateProjectConfiguration } from '@nrwl/devkit';
|
||||
import { Builders } from '@schematics/angular/utility/workspace-models';
|
||||
|
||||
export default function updateWorkspaceConfigurations(tree: Tree) {
|
||||
const projects = getProjects(tree);
|
||||
|
||||
const supportedExecutors: Set<string> = new Set([Builders.Server]);
|
||||
for (const [name, project] of projects) {
|
||||
for (const [targetName, target] of Object.entries(project.targets)) {
|
||||
if (!supportedExecutors.has(target.executor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
target.options.bundleDependencies = undefined;
|
||||
|
||||
for (const [configurationName, configuration] of Object.entries(
|
||||
target.configurations
|
||||
)) {
|
||||
configuration.bundleDependencies = undefined;
|
||||
target[configurationName] = configuration;
|
||||
}
|
||||
|
||||
project.targets[targetName] = target;
|
||||
updateProjectConfiguration(tree, name, project);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,15 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
|
||||
export const angularVersion = '~14.2.0';
|
||||
export const angularDevkitVersion = '~14.2.0';
|
||||
export const ngPackagrVersion = '~14.2.0';
|
||||
export const ngrxVersion = '~14.0.0';
|
||||
export const angularVersion = '~15.0.0';
|
||||
export const angularDevkitVersion = '~15.0.0';
|
||||
export const ngPackagrVersion = '~15.0.0';
|
||||
export const ngrxVersion = '~15.0.0-beta.0';
|
||||
export const rxjsVersion = '~7.5.0';
|
||||
export const zoneJsVersion = '~0.11.4';
|
||||
export const angularJsVersion = '1.7.9';
|
||||
export const tsLibVersion = '^2.3.0';
|
||||
|
||||
export const ngUniversalVersion = '~14.2.0';
|
||||
export const ngUniversalVersion = '~15.0.0';
|
||||
|
||||
export const angularEslintVersion = '~14.0.4';
|
||||
export const tailwindVersion = '^3.0.2';
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
|
||||
export const tslintToEslintConfigVersion = '^2.13.0';
|
||||
export const buildAngularVersion = '~14.2.0';
|
||||
|
||||
export const typescriptESLintVersion = '^5.36.1';
|
||||
export const eslintVersion = '~8.15.0';
|
||||
|
||||
@ -18,6 +18,7 @@ const latestVersionWithOldFlag = '13.8.3';
|
||||
const nxAngularVersionMap: Record<number, { range: string; max?: string }> = {
|
||||
13: { range: '>= 13.2.0 < 14.2.0', max: '~14.1.0' },
|
||||
14: { range: '>= 14.2.0' },
|
||||
15: { range: '>= 15.0.0' },
|
||||
};
|
||||
// latest major version of Angular that is compatible with Nx, based on the map above
|
||||
const latestCompatibleAngularMajorVersion = Math.max(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
|
||||
export const angularCliVersion = '~14.2.0';
|
||||
export const angularCliVersion = '~15.0.0';
|
||||
export const typescriptVersion = '~4.8.2';
|
||||
export const prettierVersion = '^2.6.2';
|
||||
export const typescriptESLintVersion = '^5.36.1';
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
"stylus": "^0.55.0",
|
||||
"stylus-loader": "^7.1.0",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.58.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
"@nrwl/workspace": "file:../workspace",
|
||||
"autoprefixer": "^10.4.9",
|
||||
"babel-loader": "^8.2.2",
|
||||
"browserslist": "^4.16.6",
|
||||
"browserslist": "^4.21.4",
|
||||
"caniuse-lite": "^1.0.30001394",
|
||||
"chalk": "4.1.0",
|
||||
"chokidar": "^3.5.1",
|
||||
@ -70,7 +70,7 @@
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||
"tslib": "^2.3.0",
|
||||
"webpack": "^5.58.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-dev-server": "^4.9.3",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
exports[`preset should create files (preset = angular) 1`] = `
|
||||
Array [
|
||||
".browserslistrc",
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"src",
|
||||
@ -18,10 +17,8 @@ Array [
|
||||
"favicon.ico",
|
||||
"index.html",
|
||||
"main.ts",
|
||||
"polyfills.ts",
|
||||
"styles.css",
|
||||
"assets",
|
||||
"environments",
|
||||
"app",
|
||||
"test-setup.ts",
|
||||
]
|
||||
|
||||
@ -94,7 +94,7 @@ describe('renameNpmPackages Rule', () => {
|
||||
tree = await runSchematic('lib', { name: 'library-1' }, tree);
|
||||
tree = await runSchematic('lib', { name: 'library-2' }, tree);
|
||||
tree = await runExternalSchematic(
|
||||
'@nrwl/angular',
|
||||
'@nrwl/react',
|
||||
'application',
|
||||
{ name: 'app-one' },
|
||||
tree
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import { UnitTestTree } from '@angular-devkit/schematics/testing';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { callRule, runSchematic, runExternalSchematic } from '../testing';
|
||||
import { callRule, runExternalSchematic, runSchematic } from '../testing';
|
||||
import { renamePackageImports } from './rename-package-imports';
|
||||
|
||||
describe('renamePackageImports Rule', () => {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
|
||||
export const angularCliVersion = '~14.2.0';
|
||||
export const angularCliVersion = '~15.0.0';
|
||||
export const typescriptVersion = '~4.8.2';
|
||||
export const prettierVersion = '^2.6.2';
|
||||
export const typescriptESLintVersion = '^5.36.1';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user