piral-ng 1.12.3 → 1.12.4-beta.36dc2ff

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -482,6 +482,39 @@ For AoT (i.e. `jitMode: false`) to work correctly the `compilationMode: 'partial
482
482
  For AoT to work correctly the Angular sources need to be bundled. This is not the case in scenarios where you installed `piral-ng` as a plugin in your shell or distribute the Angular packages as shared dependencies from your app shell.
483
483
  :::
484
484
 
485
+ Alternatively, if you want to use Rspack instead of Webpack you can use the convenience `extend-rspack` module.
486
+
487
+ This is how your *rspack.config.js* can look like:
488
+
489
+ ```js
490
+ const extendRspack = require('piral-ng/extend-rspack');
491
+
492
+ module.exports = extendRspack();
493
+ ```
494
+
495
+ For using `piral-ng/extend-rspack` you must have installed:
496
+
497
+ - `@rspack/core`
498
+ - `sass-loader` (only required if you use `.scss`/`.sass` component styles)
499
+ - `piral-cli-rspack`
500
+
501
+ You can do that via:
502
+
503
+ ```sh
504
+ npm i @rspack/core sass-loader piral-cli-rspack --save-dev
505
+ ```
506
+
507
+ The available options for `piral-ng/extend-rspack` are:
508
+
509
+ - `ngOptions` (currently only `jitMode`, which must stay at its default of `true`)
510
+ - `patterns` (providing input to the Rspack `CopyRspackPlugin`)
511
+
512
+ `piral-ng/extend-rspack` relies on Rspack's built-in CSS support (`css/auto`) for regular stylesheets, its built-in `asset/source` module type to inline component templates and component-scoped styles as raw strings, and its built-in `builtin:swc-loader` (configured for legacy decorators and decorator metadata) to compile TypeScript.
513
+
514
+ ::: failure: AoT is not supported with Rspack
515
+ Angular's AoT compiler (`@ngtools/webpack`'s `AngularWebpackPlugin`) depends on Webpack-only compiler internals and does not work with Rspack. `piral-ng/extend-rspack` therefore only supports JIT builds (`jitMode: true`, the default) and throws if `jitMode: false` is requested. If you need an AoT production build with Rspack, use a dedicated Angular/Rspack builder such as [`@nx/angular-rspack`](https://www.npmjs.com/package/@nx/angular-rspack) instead.
516
+ :::
517
+
485
518
  If you have set up the build process then you need to make sure that your application has an entry point (*index.ts*). That entry point has to be a valid pilet entry module. It may look as follows:
486
519
 
487
520
  ```ts
@@ -0,0 +1,21 @@
1
+ // Rewrites `templateUrl`/`styleUrls`/`styleUrl` in `@Component()` metadata to inline
2
+ // `require()` calls, since Angular's JIT compiler needs the actual template/styles at
3
+ // class-decoration time - it does not fetch `templateUrl`/`styleUrls` over the network
4
+ // unless `resolveComponentResources()` was run, which we don't wire up here.
5
+ const templateUrlRegex = /templateUrl\s*:\s*(['"`])((?:\\.|(?!\1).)*)\1/g;
6
+ const styleUrlRegex = /styleUrl\s*:\s*(['"`])((?:\\.|(?!\1).)*)\1/g;
7
+ const styleUrlsRegex = /styleUrls\s*:\s*\[([^\]]*)\]/g;
8
+ const stringLiteralRegex = /(['"`])((?:\\.|(?!\1).)*)\1/g;
9
+
10
+ module.exports = function angularResourceLoader(source) {
11
+ source = source.replace(templateUrlRegex, (_, quote, url) => `template: require(${quote}${url}${quote})`);
12
+
13
+ source = source.replace(styleUrlRegex, (_, quote, url) => `styles: [require(${quote}${url}${quote})]`);
14
+
15
+ source = source.replace(styleUrlsRegex, (_, urls) => {
16
+ const requires = [...urls.matchAll(stringLiteralRegex)].map(([, quote, url]) => `require(${quote}${url}${quote})`);
17
+ return `styles: [${requires.join(', ')}]`;
18
+ });
19
+
20
+ return source;
21
+ };
@@ -0,0 +1,143 @@
1
+ const { CopyRspackPlugin } = require('@rspack/core');
2
+
3
+ const { resolve } = require('path');
4
+
5
+ const sassLoader = require.resolve('sass-loader');
6
+ const angularResourceLoader = require.resolve('./angular-resource-loader');
7
+
8
+ module.exports =
9
+ (options = {}) =>
10
+ (config) => {
11
+ const {
12
+ patterns = [{ from: resolve(process.cwd(), 'src/assets'), noErrorOnMissing: true }],
13
+ ngOptions = {},
14
+ } = options;
15
+ const jitMode = ngOptions.jitMode ?? true;
16
+
17
+ if (!jitMode) {
18
+ // Angular AOT relies on @ngtools/webpack's AngularWebpackPlugin, which reaches into
19
+ // webpack-only compiler internals (e.g. resolverFactory) that Rspack does not provide.
20
+ // There is no drop-in AOT compiler for Rspack yet, so only JIT builds are supported here.
21
+ // For AOT with Rspack use a dedicated Angular/Rspack builder, e.g. `@nx/angular-rspack`.
22
+ throw new Error('piral-ng/extend-rspack only supports jitMode: true (AOT is not supported with Rspack).');
23
+ }
24
+
25
+ // piral-cli-rspack nests all its rules in a single top-level `oneOf` array, with separate
26
+ // (non-merged) entries for `.ts` and `.tsx` - not a combined `/\.tsx?$/` pattern
27
+ const oneOf = config.module.rules.find((rule) => Array.isArray(rule.oneOf))?.oneOf;
28
+
29
+ if (!oneOf) {
30
+ throw new Error(
31
+ 'piral-ng/extend-rspack could not find the expected module.rules[].oneOf array - is this an unsupported Rspack config?',
32
+ );
33
+ }
34
+
35
+ oneOf.forEach((rule) => {
36
+ const test = rule.test?.toString();
37
+
38
+ // exclude component-scoped styles from the regular (global) stylesheet handling,
39
+ // they are inlined into the component as raw text below instead
40
+ if (test === /\.css$/i.toString()) {
41
+ rule.exclude = /\.component.css$/i;
42
+ } else if (test === /\.s[ac]ss$/i.toString()) {
43
+ rule.exclude = /\.component.s[ac]ss$/i;
44
+ } else if (test === /\.ts$/.toString() || test === /\.tsx$/.toString()) {
45
+ // Angular's JIT mode only needs TypeScript's decorator/metadata transform - no
46
+ // Angular-specific compiler is required, so Rspack's native SWC loader handles it
47
+ delete rule.loader;
48
+ delete rule.options;
49
+ rule.use = [
50
+ {
51
+ loader: 'builtin:swc-loader',
52
+ options: {
53
+ jsc: {
54
+ parser: {
55
+ syntax: 'typescript',
56
+ tsx: test === /\.tsx$/.toString(),
57
+ decorators: true,
58
+ // Angular puts decorators before `export`, e.g. `@Component() export class`
59
+ decoratorsBeforeExport: true,
60
+ },
61
+ transform: {
62
+ legacyDecorator: true,
63
+ decoratorMetadata: true,
64
+ useDefineForClassFields: false,
65
+ },
66
+ },
67
+ },
68
+ },
69
+ // loaders run right-to-left, so this rewrites templateUrl/styleUrls to require()
70
+ // calls before the SWC loader compiles the result
71
+ angularResourceLoader,
72
+ ];
73
+ }
74
+ });
75
+
76
+ // Angular templates/styles are consumed as plain strings - Rspack's built-in asset/source
77
+ // type exports the raw content without any loader; unshifted so it runs before the catch-all rule
78
+ oneOf.unshift(
79
+ {
80
+ test: /\.component.html$/i,
81
+ type: 'asset/source',
82
+ },
83
+ {
84
+ test: /\.component.css$/i,
85
+ type: 'asset/source',
86
+ },
87
+ {
88
+ // sass-loader compiles to CSS first, asset/source then exports the result as a string
89
+ test: /\.component.s[ac]ss$/i,
90
+ use: [sassLoader],
91
+ type: 'asset/source',
92
+ },
93
+ );
94
+
95
+ // The job of this plugin is
96
+ // (1)
97
+ // to make @angular/core depend on @angular/compiler - this way @angular/compiler
98
+ // does not need to be loaded separately and @angular/compiler is present *before*
99
+ // @angular/core; this is only required in jit mode - as otherwise everything should
100
+ // be pre-compiled.
101
+ // (2)
102
+ // to introduce a dynamic version of the window.ng global, which supports running
103
+ // with multiple versions of Angular.
104
+ config.plugins.push({
105
+ apply(compiler) {
106
+ const { entry } = compiler.options;
107
+ const coreEntry = entry['angular-core'];
108
+ const compilerEntry = entry['angular-compiler'];
109
+
110
+ if (typeof coreEntry !== 'undefined') {
111
+ const compilerDependency = resolve(__dirname, 'core-dynamic.js');
112
+ coreEntry.import = [compilerDependency, ...coreEntry.import];
113
+ }
114
+
115
+ if (typeof compilerEntry !== 'undefined') {
116
+ const compilerDependency = resolve(__dirname, 'compiler-dynamic.js');
117
+ compilerEntry.import = [compilerDependency, ...compilerEntry.import];
118
+ }
119
+
120
+ // if @angular/core / @angular/compiler aren't split into their own shared-dependency
121
+ // entries (e.g. a plain pilet build), make sure @angular/compiler still loads before
122
+ // any Angular code runs - otherwise JIT compilation fails at runtime
123
+ if (typeof coreEntry === 'undefined' && typeof compilerEntry === 'undefined') {
124
+ const compilerDependency = resolve(__dirname, 'core-dynamic.js');
125
+
126
+ Object.values(entry).forEach((e) => {
127
+ if (e && Array.isArray(e.import)) {
128
+ e.import = [compilerDependency, ...e.import];
129
+ }
130
+ });
131
+ }
132
+ },
133
+ });
134
+
135
+ config.plugins.push(
136
+ new CopyRspackPlugin({
137
+ patterns,
138
+ }),
139
+ );
140
+
141
+ return config;
142
+ };
143
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "piral-ng",
3
- "version": "1.12.3",
3
+ "version": "1.12.4-beta.36dc2ff",
4
4
  "description": "Plugin for integrating Angular components in Piral.",
5
5
  "keywords": [
6
6
  "piral",
@@ -25,6 +25,7 @@
25
25
  "./compiler-dynamic": "./compiler-dynamic.js",
26
26
  "./convert": "./convert.js",
27
27
  "./core-dynamic": "./core-dynamic.js",
28
+ "./extend-rspack": "./extend-rspack.js",
28
29
  "./extend-webpack": "./extend-webpack.js",
29
30
  "./standalone": "./lib/standalone.js",
30
31
  "./lib/*": {
@@ -37,12 +38,14 @@
37
38
  "files": [
38
39
  "lib",
39
40
  "src",
41
+ "angular-resource-loader.js",
40
42
  "common.d.ts",
41
43
  "common.js",
42
44
  "compiler-dynamic.js",
43
45
  "convert.d.ts",
44
46
  "convert.js",
45
47
  "core-dynamic.js",
48
+ "extend-rspack.js",
46
49
  "extend-webpack.js"
47
50
  ],
48
51
  "repository": {
@@ -71,7 +74,7 @@
71
74
  "@angular/platform-browser": "^16.0.0",
72
75
  "@angular/platform-browser-dynamic": "^16.0.0",
73
76
  "@angular/router": "^16.0.0",
74
- "piral-core": "^1.12.3",
77
+ "piral-core": "^1.12.4-beta.36dc2ff",
75
78
  "piral-ng-common": "^16.0.0",
76
79
  "rxjs": "^7.3.0"
77
80
  }