diff --git a/docs/generated/packages/angular/generators/application.json b/docs/generated/packages/angular/generators/application.json index 9d8c205e12..d20f83cba5 100644 --- a/docs/generated/packages/angular/generators/application.json +++ b/docs/generated/packages/angular/generators/application.json @@ -168,7 +168,7 @@ "bundler": { "description": "Bundler to use to build the application.", "type": "string", - "enum": ["esbuild", "webpack"], + "enum": ["esbuild", "rspack", "webpack"], "default": "esbuild", "x-prompt": "Which bundler do you want to use to build the application?", "x-priority": "important" diff --git a/e2e/angular/src/projects.test.ts b/e2e/angular/src/projects.test.ts index 402f133798..0d8d419103 100644 --- a/e2e/angular/src/projects.test.ts +++ b/e2e/angular/src/projects.test.ts @@ -149,6 +149,19 @@ describe('Angular Projects', () => { await killProcessAndPorts(esbProcess.pid, appPort); }, 1000000); + it('should successfully work with rspack for build', async () => { + const app = uniq('app'); + runCLI( + `generate @nx/angular:app my-dir/${app} --bundler=rspack --no-interactive` + ); + runCLI(`build ${app}`); + + if (runE2ETests()) { + expect(() => runCLI(`e2e ${app}-e2e`)).not.toThrow(); + expect(await killPort(4200)).toBeTruthy(); + } + }, 1000000); + it('should successfully work with playwright for e2e tests', async () => { const app = uniq('app'); diff --git a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap index 4cff4fb21e..8695e7805f 100644 --- a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap +++ b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap @@ -1,5 +1,74 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`app --minimal should generate a correct setup when --bundler=rspack including a correct config file and no build target 1`] = ` +" + import { createConfig }from '@nx/angular-rspack'; + + + export default createConfig({ + options: { + root: __dirname, + + "outputPath": { + "base": "../dist/app1" + }, + "index": "./src/index.html", + "browser": "./src/main.ts", + "polyfills": [ + "./zone.js" + ], + "tsConfig": "./tsconfig.app.json", + "assets": [ + { + "glob": "**/*", + "input": "./public" + } + ], + "styles": [ + "./src/styles.css" + ], + "scripts": [], + "devServer": {} + + } + }, { + production: { + options: { + + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kb", + "maximumError": "8kb" + } + ], + "outputHashing": "all", + "devServer": {} + + } + }, + + development: { + options: { + + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true, + "devServer": {} + + } + }}); + + " +`; + exports[`app --minimal should skip "nx-welcome.component.ts" file and references for non-standalone apps with routing 1`] = ` "import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; diff --git a/packages/angular/src/generators/application/application.spec.ts b/packages/angular/src/generators/application/application.spec.ts index 4eab12de43..5868fe9d72 100644 --- a/packages/angular/src/generators/application/application.spec.ts +++ b/packages/angular/src/generators/application/application.spec.ts @@ -1242,6 +1242,16 @@ describe('app', () => { ] `); }); + it('should generate a correct setup when --bundler=rspack including a correct config file and no build target', async () => { + await generateApp(appTree, 'app1', { + bundler: 'rspack', + }); + + const project = readProjectConfiguration(appTree, 'app1'); + expect(project.targets.build).not.toBeDefined(); + expect(appTree.exists('app1/rspack.config.ts')).toBeTruthy(); + expect(appTree.read('app1/rspack.config.ts', 'utf-8')).toMatchSnapshot(); + }); it('should generate target options "browser" and "buildTarget"', async () => { await generateApp(appTree, 'my-app', { standalone: true }); diff --git a/packages/angular/src/generators/application/application.ts b/packages/angular/src/generators/application/application.ts index 230b5c5fce..978c95ddba 100644 --- a/packages/angular/src/generators/application/application.ts +++ b/packages/angular/src/generators/application/application.ts @@ -1,4 +1,5 @@ import { + addDependenciesToPackageJson, formatFiles, GeneratorCallback, installPackagesTask, @@ -11,6 +12,7 @@ import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-com import { initGenerator as jsInitGenerator } from '@nx/js'; import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { angularInitGenerator } from '../init/init'; +import { convertToRspack } from '../convert-to-rspack/convert-to-rspack'; import { setupSsr } from '../setup-ssr/setup-ssr'; import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind'; import { ensureAngularDependencies } from '../utils/ensure-angular-dependencies'; @@ -29,12 +31,17 @@ import { updateEditorTsConfig, } from './lib'; import type { Schema } from './schema'; +import { tsNodeVersion } from '../../utils/versions'; export async function applicationGenerator( tree: Tree, schema: Partial ): Promise { assertNotUsingTsSolutionSetup(tree, 'angular', 'application'); + const isRspack = schema.bundler === 'rspack'; + if (isRspack) { + schema.bundler = 'webpack'; + } const options = await normalizeOptions(tree, schema); const rootOffset = offsetFromRoot(options.appProjectRoot); @@ -102,6 +109,14 @@ export async function applicationGenerator( }); } + if (isRspack) { + await convertToRspack(tree, { + project: options.name, + skipInstall: options.skipPackageJson, + skipFormat: true, + }); + } + if (!options.skipFormat) { await formatFiles(tree); } diff --git a/packages/angular/src/generators/application/schema.d.ts b/packages/angular/src/generators/application/schema.d.ts index e51984ef7a..3f701b9d5e 100644 --- a/packages/angular/src/generators/application/schema.d.ts +++ b/packages/angular/src/generators/application/schema.d.ts @@ -27,7 +27,7 @@ export interface Schema { standalone?: boolean; rootProject?: boolean; minimal?: boolean; - bundler?: 'webpack' | 'esbuild'; + bundler?: 'webpack' | 'esbuild' | 'rspack'; ssr?: boolean; serverRouting?: boolean; nxCloudToken?: string; diff --git a/packages/angular/src/generators/application/schema.json b/packages/angular/src/generators/application/schema.json index f67c2d794c..31af40b553 100644 --- a/packages/angular/src/generators/application/schema.json +++ b/packages/angular/src/generators/application/schema.json @@ -171,7 +171,7 @@ "bundler": { "description": "Bundler to use to build the application.", "type": "string", - "enum": ["esbuild", "webpack"], + "enum": ["esbuild", "rspack", "webpack"], "default": "esbuild", "x-prompt": "Which bundler do you want to use to build the application?", "x-priority": "important" diff --git a/packages/angular/src/generators/convert-to-rspack/convert-to-rspack.ts b/packages/angular/src/generators/convert-to-rspack/convert-to-rspack.ts index b238afba49..f61ccd83c3 100644 --- a/packages/angular/src/generators/convert-to-rspack/convert-to-rspack.ts +++ b/packages/angular/src/generators/convert-to-rspack/convert-to-rspack.ts @@ -13,7 +13,11 @@ import { writeJson, } from '@nx/devkit'; import type { ConvertToRspackSchema } from './schema'; -import { angularRspackVersion, nxVersion } from '../../utils/versions'; +import { + angularRspackVersion, + nxVersion, + tsNodeVersion, +} from '../../utils/versions'; import { createConfig } from './lib/create-config'; import { getCustomWebpackConfig } from './lib/get-custom-webpack-config'; import { updateTsconfig } from './lib/update-tsconfig'; @@ -451,6 +455,7 @@ export async function convertToRspack( {}, { '@nx/angular-rspack': angularRspackVersion, + 'ts-node': tsNodeVersion, } ); tasks.push(installTask);