@nx/angular-rspack 20.6.2 → 20.7.0

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.
Files changed (40) hide show
  1. package/README.md +41 -0
  2. package/dist/lib/config/create-config.d.ts.map +1 -1
  3. package/dist/lib/config/create-config.js +51 -10
  4. package/dist/lib/config/dev-server-config-utils.d.ts +1 -0
  5. package/dist/lib/config/dev-server-config-utils.d.ts.map +1 -1
  6. package/dist/lib/config/dev-server-config-utils.js +10 -0
  7. package/dist/lib/config/helpers.d.ts +11 -0
  8. package/dist/lib/config/helpers.d.ts.map +1 -1
  9. package/dist/lib/config/helpers.js +36 -0
  10. package/dist/lib/config/i18n/create-i18n-options.d.ts +6 -0
  11. package/dist/lib/config/i18n/create-i18n-options.d.ts.map +1 -0
  12. package/dist/lib/config/i18n/create-i18n-options.js +122 -0
  13. package/dist/lib/models/angular-rspack-plugin-options.d.ts +46 -0
  14. package/dist/lib/models/angular-rspack-plugin-options.d.ts.map +1 -1
  15. package/dist/lib/models/augmented-compilation.d.ts +2 -0
  16. package/dist/lib/models/augmented-compilation.d.ts.map +1 -1
  17. package/dist/lib/models/i18n.d.ts +33 -0
  18. package/dist/lib/models/i18n.d.ts.map +1 -0
  19. package/dist/lib/models/i18n.js +39 -0
  20. package/dist/lib/models/index.d.ts +1 -0
  21. package/dist/lib/models/index.d.ts.map +1 -1
  22. package/dist/lib/models/index.js +1 -0
  23. package/dist/lib/models/normalize-options.d.ts.map +1 -1
  24. package/dist/lib/models/normalize-options.js +9 -1
  25. package/dist/lib/models/unsupported-options.d.ts +0 -8
  26. package/dist/lib/models/unsupported-options.d.ts.map +1 -1
  27. package/dist/lib/models/unsupported-options.js +0 -8
  28. package/dist/lib/plugins/angular-rspack-plugin.d.ts +2 -2
  29. package/dist/lib/plugins/angular-rspack-plugin.d.ts.map +1 -1
  30. package/dist/lib/plugins/angular-rspack-plugin.js +41 -1
  31. package/dist/lib/plugins/i18n-inline-plugin.d.ts +8 -0
  32. package/dist/lib/plugins/i18n-inline-plugin.d.ts.map +1 -0
  33. package/dist/lib/plugins/i18n-inline-plugin.js +226 -0
  34. package/dist/lib/plugins/ng-rspack.d.ts +3 -2
  35. package/dist/lib/plugins/ng-rspack.d.ts.map +1 -1
  36. package/dist/lib/plugins/ng-rspack.js +9 -2
  37. package/dist/lib/utils/find-project-for-path.d.ts +16 -0
  38. package/dist/lib/utils/find-project-for-path.d.ts.map +1 -0
  39. package/dist/lib/utils/find-project-for-path.js +44 -0
  40. package/package.json +7 -3
@@ -1,4 +1,5 @@
1
1
  export * from './angular-rspack-plugin-options';
2
2
  export * from './augmented-compilation';
3
+ export * from './i18n';
3
4
  export * from './normalize-options';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,QAAQ,CAAC;AACvB,cAAc,qBAAqB,CAAC"}
@@ -3,4 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./angular-rspack-plugin-options"), exports);
5
5
  tslib_1.__exportStar(require("./augmented-compilation"), exports);
6
+ tslib_1.__exportStar(require("./i18n"), exports);
6
7
  tslib_1.__exportStar(require("./normalize-options"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-options.d.ts","sourceRoot":"","sources":["../../../src/lib/models/normalize-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAkB9D,OAAO,KAAK,EACV,0BAA0B,EAI1B,oCAAoC,EAOrC,MAAM,iCAAiC,CAAC;AAMzC,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,gBAAgB,EAAE,eAAe,EAAE,EACnC,IAAI,EAAE,MAAM,GACX,eAAe,EAAE,CAKnB;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,GAAG,EAAE,0BAA0B,CAAC,KAAK,CAAC,GACrC,OAAO,CAQT;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,0BAA0B,CAAC,KAAK,CAAC,QAmBjE;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,0BAA0B,CAAC,cAAc,CAAC,QASzD;AA0BD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,0BAA0B,GAClC,oCAAoC,CA0ItC"}
1
+ {"version":3,"file":"normalize-options.d.ts","sourceRoot":"","sources":["../../../src/lib/models/normalize-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAkB9D,OAAO,KAAK,EACV,0BAA0B,EAI1B,oCAAoC,EAOrC,MAAM,iCAAiC,CAAC;AAMzC,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,gBAAgB,EAAE,eAAe,EAAE,EACnC,IAAI,EAAE,MAAM,GACX,eAAe,EAAE,CAKnB;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,GAAG,EAAE,0BAA0B,CAAC,KAAK,CAAC,GACrC,OAAO,CAQT;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,0BAA0B,CAAC,KAAK,CAAC,QAmBjE;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,0BAA0B,CAAC,cAAc,CAAC,QASzD;AA0BD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,0BAA0B,GAClC,oCAAoC,CA6ItC"}
@@ -157,7 +157,10 @@ function normalizeOptions(options) {
157
157
  aot,
158
158
  browser: options.browser ?? './src/main.ts',
159
159
  commonChunk: options.commonChunk ?? true,
160
+ define: options.define ?? {},
161
+ deleteOutputPath: options.deleteOutputPath ?? true,
160
162
  devServer: normalizeDevServer(options.devServer),
163
+ externalDependencies: options.externalDependencies ?? [],
161
164
  extractLicenses: options.extractLicenses ?? true,
162
165
  fileReplacements: resolveFileReplacements(fileReplacements, root),
163
166
  globalStyles,
@@ -208,10 +211,15 @@ function normalizeDevServer(devServer) {
208
211
  const defaultHost = 'localhost';
209
212
  const defaultPort = 4200;
210
213
  if (!devServer) {
211
- return { host: defaultHost, port: defaultPort };
214
+ return {
215
+ allowedHosts: [],
216
+ host: defaultHost,
217
+ port: defaultPort,
218
+ };
212
219
  }
213
220
  return {
214
221
  ...devServer,
222
+ allowedHosts: devServer.allowedHosts ?? [],
215
223
  host: devServer.host ?? defaultHost,
216
224
  port: devServer.port ?? defaultPort,
217
225
  };
@@ -10,7 +10,6 @@ export type BudgetEntry = {
10
10
  error?: string;
11
11
  };
12
12
  export interface DevServerUnsupportedOptions {
13
- allowedHosts?: string[] | boolean;
14
13
  headers?: Record<string, string>;
15
14
  open?: boolean;
16
15
  liveReload?: boolean;
@@ -28,19 +27,12 @@ export interface PluginUnsupportedOptions {
28
27
  unsafeEval?: boolean;
29
28
  };
30
29
  };
31
- externalDependencies?: string[];
32
30
  clearScreen?: boolean;
33
- define?: Record<string, string>;
34
31
  baseHref?: string;
35
32
  verbose?: boolean;
36
33
  progress?: boolean;
37
- i18nMissingTranslation?: 'warning' | 'error' | 'ignore';
38
- i18nDuplicateTranslation?: 'warning' | 'error' | 'ignore';
39
- localize?: boolean | string[];
40
34
  watch?: boolean;
41
35
  poll?: number;
42
- deleteOutputPath?: boolean;
43
- preserveSymlinks?: boolean;
44
36
  subresourceIntegrity?: boolean;
45
37
  serviceWorker?: string | false;
46
38
  statsJson?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"unsupported-options.d.ts","sourceRoot":"","sources":["../../../src/lib/models/unsupported-options.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EACA,KAAK,GACL,WAAW,GACX,KAAK,GACL,WAAW,GACX,mBAAmB,GACnB,QAAQ,GACR,SAAS,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,WAAW,2BAA2B;IAC1C,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,SAAS,CAAC,EACN,OAAO,GACP;QACE,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACP;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EACJ,OAAO,GACP;YACE,UAAU,CAAC,EAAE,OAAO,CAAC;SACtB,CAAC;KACP,CAAC;IACF,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACxD,wBAAwB,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC1D,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,iBAAiB,CAAC;IACvD,2BAA2B,CAAC,EAAE,MAAM,EAAE,CAAC;IACvC,SAAS,CAAC,EACN,OAAO,GACP;QACE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IACN,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAClC;AAED,eAAO,MAAM,iCAAiC,UA0B7C,CAAC;AAEF,eAAO,MAAM,kCAAkC,UAS9C,CAAC"}
1
+ {"version":3,"file":"unsupported-options.d.ts","sourceRoot":"","sources":["../../../src/lib/models/unsupported-options.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EACA,KAAK,GACL,WAAW,GACX,KAAK,GACL,WAAW,GACX,mBAAmB,GACnB,QAAQ,GACR,SAAS,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,SAAS,CAAC,EACN,OAAO,GACP;QACE,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACP;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EACJ,OAAO,GACP;YACE,UAAU,CAAC,EAAE,OAAO,CAAC;SACtB,CAAC;KACP,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,iBAAiB,CAAC;IACvD,2BAA2B,CAAC,EAAE,MAAM,EAAE,CAAC;IACvC,SAAS,CAAC,EACN,OAAO,GACP;QACE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IACN,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAClC;AAED,eAAO,MAAM,iCAAiC,UAmB7C,CAAC;AAEF,eAAO,MAAM,kCAAkC,UAQ9C,CAAC"}
@@ -4,19 +4,12 @@ exports.DEV_SERVER_OPTIONS_PENDING_SUPPORT = exports.TOP_LEVEL_OPTIONS_PENDING_S
4
4
  exports.TOP_LEVEL_OPTIONS_PENDING_SUPPORT = [
5
5
  'deployUrl',
6
6
  'security',
7
- 'externalDependencies',
8
7
  'clearScreen',
9
- 'define',
10
8
  'baseHref',
11
9
  'verbose',
12
10
  'progress',
13
- 'i18nMissingTranslation',
14
- 'i18nDuplicateTranslation',
15
- 'localize',
16
11
  'watch',
17
12
  'poll',
18
- 'deleteOutputPath',
19
- 'preserveSymlinks',
20
13
  'subresourceIntegrity',
21
14
  'serviceWorker',
22
15
  'statsJson',
@@ -29,7 +22,6 @@ exports.TOP_LEVEL_OPTIONS_PENDING_SUPPORT = [
29
22
  'outputMode',
30
23
  ];
31
24
  exports.DEV_SERVER_OPTIONS_PENDING_SUPPORT = [
32
- 'allowedHosts',
33
25
  'headers',
34
26
  'open',
35
27
  'liveReload',
@@ -1,8 +1,8 @@
1
1
  import { Compiler, RspackPluginInstance } from '@rspack/core';
2
- import { type NormalizedAngularRspackPluginOptions } from '../models';
2
+ import { I18nOptions, type NormalizedAngularRspackPluginOptions } from '../models';
3
3
  export declare class AngularRspackPlugin implements RspackPluginInstance {
4
4
  #private;
5
- constructor(options: NormalizedAngularRspackPluginOptions);
5
+ constructor(options: NormalizedAngularRspackPluginOptions, i18nOptions?: I18nOptions);
6
6
  apply(compiler: Compiler): void;
7
7
  private setupCompilation;
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"angular-rspack-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/angular-rspack-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAGR,oBAAoB,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,oCAAoC,EAC1C,MAAM,WAAW,CAAC;AAiBnB,qBAAa,mBAAoB,YAAW,oBAAoB;;gBAWlD,OAAO,EAAE,oCAAoC;IAqBzD,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAgJV,gBAAgB;CA0B/B"}
1
+ {"version":3,"file":"angular-rspack-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/angular-rspack-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAGR,oBAAoB,EAErB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EAGX,KAAK,oCAAoC,EAC1C,MAAM,WAAW,CAAC;AAiBnB,qBAAa,mBAAoB,YAAW,oBAAoB;;gBAa5D,OAAO,EAAE,oCAAoC,EAC7C,WAAW,CAAC,EAAE,WAAW;IAuB3B,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAiMV,gBAAgB;CA0B/B"}
@@ -10,14 +10,16 @@ const fs_2 = tslib_1.__importDefault(require("fs"));
10
10
  const PLUGIN_NAME = 'AngularRspackPlugin';
11
11
  class AngularRspackPlugin {
12
12
  #_options;
13
+ #i18n;
13
14
  #typescriptFileCache;
14
15
  #javascriptTransformer;
15
16
  // This will be defined in the apply method correctly
16
17
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
17
18
  // @ts-expect-error
18
19
  #angularCompilation;
19
- constructor(options) {
20
+ constructor(options, i18nOptions) {
20
21
  this.#_options = options;
22
+ this.#i18n = i18nOptions;
21
23
  this.#typescriptFileCache = new Map();
22
24
  this.#javascriptTransformer = new angular_rspack_compiler_1.JavaScriptTransformer({
23
25
  /**
@@ -70,6 +72,43 @@ class AngularRspackPlugin {
70
72
  }
71
73
  callback();
72
74
  });
75
+ compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
76
+ compilation.hooks.processAssets.tap({
77
+ name: PLUGIN_NAME,
78
+ stage: compiler.rspack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
79
+ }, (assets) => {
80
+ for (const assetName in assets) {
81
+ const asset = compilation.getAsset(assetName);
82
+ if (!asset) {
83
+ continue;
84
+ }
85
+ const assetHash = asset.info?.contenthash?.[0] ?? '';
86
+ const assetNameWithoutHash = assetName.replace(`.${assetHash}`, '');
87
+ if (assetNameWithoutHash !== 'main.js') {
88
+ continue;
89
+ }
90
+ const originalSource = asset.source.source();
91
+ let updatedSourceContent = typeof originalSource === 'string'
92
+ ? originalSource
93
+ : originalSource.toString();
94
+ if (this.#i18n?.shouldInline) {
95
+ // When inlining, a placeholder is used to allow the post-processing step to inject the $localize locale identifier.
96
+ updatedSourceContent +=
97
+ '(globalThis.$localize ??= {}).locale = "___NG_LOCALE_INSERT___";\n';
98
+ }
99
+ else if (this.#i18n?.hasDefinedSourceLocale) {
100
+ // If not inlining translations and source locale is defined, inject the locale specifier.
101
+ updatedSourceContent += `(globalThis.$localize ??= {}).locale = "${this.#i18n.sourceLocale}";\n`;
102
+ }
103
+ // Replace the asset with the modified content
104
+ const map = asset.source.map();
105
+ const updatedSource = map
106
+ ? new core_1.sources.SourceMapSource(updatedSourceContent, asset.name, map)
107
+ : new core_1.sources.RawSource(updatedSourceContent);
108
+ compilation.updateAsset(assetName, updatedSource);
109
+ }
110
+ });
111
+ });
73
112
  compiler.hooks.emit.tapAsync(PLUGIN_NAME, async (compilation, callback) => {
74
113
  if (!this.#_options.skipTypeChecking) {
75
114
  const { errors, warnings } = await this.#angularCompilation.diagnoseFiles(angular_rspack_compiler_1.DiagnosticModes.All);
@@ -111,6 +150,7 @@ class AngularRspackPlugin {
111
150
  javascriptTransformer: this
112
151
  .#javascriptTransformer,
113
152
  typescriptFileCache: this.#typescriptFileCache,
153
+ i18n: this.#i18n,
114
154
  });
115
155
  });
116
156
  compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
@@ -0,0 +1,8 @@
1
+ import { RspackPluginInstance, Compiler } from '@rspack/core';
2
+ import { I18nOptions, NormalizedAngularRspackPluginOptions } from '../models';
3
+ export declare class I18nInlinePlugin implements RspackPluginInstance {
4
+ #private;
5
+ constructor(pluginOptions: NormalizedAngularRspackPluginOptions, i18nOptions: I18nOptions);
6
+ apply(compiler: Compiler): void;
7
+ }
8
+ //# sourceMappingURL=i18n-inline-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n-inline-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/i18n-inline-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAW,MAAM,cAAc,CAAC;AASvE,OAAO,EAAE,WAAW,EAAE,oCAAoC,EAAE,MAAM,WAAW,CAAC;AAS9E,qBAAa,gBAAiB,YAAW,oBAAoB;;gBAUzD,aAAa,EAAE,oCAAoC,EACnD,WAAW,EAAE,WAAW;IAM1B,KAAK,CAAC,QAAQ,EAAE,QAAQ;CAuSzB"}
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.I18nInlinePlugin = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const core_1 = require("@rspack/core");
6
+ const core_2 = require("@babel/core");
7
+ const remapping_1 = tslib_1.__importDefault(require("@ampproject/remapping"));
8
+ const node_assert_1 = tslib_1.__importDefault(require("node:assert"));
9
+ const PLUGIN_NAME = 'I18nInlinePlugin';
10
+ class I18nInlinePlugin {
11
+ #pluginOptions;
12
+ #i18n;
13
+ /**
14
+ * Cached instance of the `@angular/localize/tools` module.
15
+ * This is used to remove the need to repeatedly import the module per file translation.
16
+ */
17
+ #localizeToolsModule;
18
+ constructor(pluginOptions, i18nOptions) {
19
+ this.#pluginOptions = pluginOptions;
20
+ this.#i18n = i18nOptions;
21
+ }
22
+ apply(compiler) {
23
+ compiler.hooks.emit.tapAsync(PLUGIN_NAME, async (compilation, callback) => {
24
+ const filesToInline = new Map();
25
+ const additionalFiles = new Map();
26
+ for (const [filename, source] of Object.entries(compilation.assets)) {
27
+ let contents = source.source();
28
+ if (typeof contents !== 'string') {
29
+ contents = contents.toString();
30
+ }
31
+ if (!filename.endsWith('.map') && contents.includes('$localize')) {
32
+ filesToInline.set(filename, { text: contents, map: source.map() });
33
+ }
34
+ else {
35
+ additionalFiles.set(filename, source);
36
+ }
37
+ }
38
+ // Map of locales to Map of files to output
39
+ const filesToOutput = new Map();
40
+ for (const localeKey of this.#i18n.inlineLocales) {
41
+ const locale = this.#i18n.locales[localeKey];
42
+ const localeFiles = new Map();
43
+ for (const [filename, { text, map }] of filesToInline.entries()) {
44
+ const result = await this.#transformWithBabel(text, map, filename, localeKey, locale.translation, this.#pluginOptions.advancedOptimizations);
45
+ localeFiles.set(filename, { text: result.code, map: result.map });
46
+ // TODO: Add support for diagnostics
47
+ }
48
+ for (const [filename, source] of additionalFiles.entries()) {
49
+ localeFiles.set(filename, {
50
+ text: source.source(),
51
+ map: source.map(),
52
+ });
53
+ }
54
+ filesToOutput.set(locale.subPath, localeFiles);
55
+ }
56
+ for (const [localeSubPath, files] of filesToOutput.entries()) {
57
+ for (const [filename, { text, map }] of files.entries()) {
58
+ const localeFileName = `${localeSubPath}/${filename}`;
59
+ if (localeFileName.endsWith('index.html')) {
60
+ // update the baseHref for the locale and set the lang attribute
61
+ const html = typeof text === 'string' ? text : text.toString();
62
+ const updatedHtml = await this.#updateBaseHrefAndLang(html, localeSubPath);
63
+ compilation.emitAsset(localeFileName, new core_1.sources.RawSource(updatedHtml));
64
+ if (compilation.getAsset(filename)) {
65
+ compilation.deleteAsset(filename);
66
+ }
67
+ continue;
68
+ }
69
+ if (map) {
70
+ compilation.emitAsset(localeFileName, new core_1.sources.SourceMapSource(text, localeFileName, map));
71
+ }
72
+ compilation.emitAsset(localeFileName, new core_1.sources.RawSource(text));
73
+ if (compilation.getAsset(filename)) {
74
+ compilation.deleteAsset(filename);
75
+ }
76
+ }
77
+ }
78
+ callback();
79
+ });
80
+ }
81
+ async #updateBaseHrefAndLang(html, localeSubPath) {
82
+ // TODO: add support for diagnostics
83
+ const dir = localeSubPath
84
+ ? await this.#getLanguageDirection(localeSubPath, [])
85
+ : undefined;
86
+ html = html.replace(/<base href="([^"]+)">/g, `<base href="/${localeSubPath}$1">`);
87
+ html = html.replace(/<html lang="([^"]+)">/g, `<html lang="${localeSubPath}"${dir ? ` dir="${dir}"` : ''}>`);
88
+ return html;
89
+ }
90
+ /**
91
+ * Attempts to load the `@angular/localize/tools` module containing the functionality to
92
+ * perform the file translations.
93
+ * This module must be dynamically loaded as it is an ESM module and this file is CommonJS.
94
+ */
95
+ async #loadLocalizeTools() {
96
+ // Load ESM `@angular/localize/tools` using the TypeScript dynamic import workaround.
97
+ // Once TypeScript provides support for keeping the dynamic import this workaround can be
98
+ // changed to a direct dynamic import.
99
+ this.#localizeToolsModule ??=
100
+ await this.#loadEsmModule('@angular/localize/tools');
101
+ }
102
+ /**
103
+ * Creates the needed Babel plugins to inline a given locale and translation for a JavaScript file.
104
+ * @param locale A string containing the locale specifier to use.
105
+ * @param translation A object record containing locale specific messages to use.
106
+ * @returns An array of Babel plugins.
107
+ */
108
+ async #createI18nPlugins(locale, translation) {
109
+ await this.#loadLocalizeTools();
110
+ const { Diagnostics, makeEs2015TranslatePlugin } =
111
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112
+ this.#localizeToolsModule;
113
+ const plugins = [];
114
+ const diagnostics = new Diagnostics();
115
+ plugins.push(makeEs2015TranslatePlugin(diagnostics, (translation || {}), {
116
+ missingTranslation: translation === undefined
117
+ ? 'ignore'
118
+ : this.#pluginOptions.i18nMissingTranslation,
119
+ }));
120
+ // Create a plugin to replace the locale specifier constant inject by the build system with the actual specifier
121
+ plugins.push({
122
+ visitor: {
123
+ StringLiteral(path) {
124
+ if (path.node.value === '___NG_LOCALE_INSERT___') {
125
+ path.replaceWith(core_2.types.stringLiteral(locale));
126
+ }
127
+ },
128
+ },
129
+ });
130
+ return { diagnostics, plugins };
131
+ }
132
+ #loadEsmModule(modulePath) {
133
+ const load = new Function('modulePath', `return import(modulePath);`);
134
+ return load(modulePath);
135
+ }
136
+ #assertIsError(value) {
137
+ const isError = value instanceof Error ||
138
+ // The following is needing to identify errors coming from RxJs.
139
+ (typeof value === 'object' &&
140
+ value &&
141
+ 'name' in value &&
142
+ 'message' in value);
143
+ (0, node_assert_1.default)(isError, 'catch clause variable is not an Error instance');
144
+ }
145
+ /**
146
+ * Transforms a JavaScript file using Babel to inline the request locale and translation.
147
+ * @param code A string containing the JavaScript code to transform.
148
+ * @param map A sourcemap object for the provided JavaScript code.
149
+ * @param options The inline request options to use.
150
+ * @returns An object containing the code, map, and diagnostics from the transformation.
151
+ */
152
+ async #transformWithBabel(code, map, filename, locale, translation, shouldOptimize) {
153
+ let ast;
154
+ try {
155
+ ast = (0, core_2.parseSync)(code, {
156
+ babelrc: false,
157
+ configFile: false,
158
+ sourceType: 'unambiguous',
159
+ filename,
160
+ });
161
+ }
162
+ catch (error) {
163
+ this.#assertIsError(error);
164
+ // Make the error more readable.
165
+ // Same errors will contain the full content of the file as the error message
166
+ // Which makes it hard to find the actual error message.
167
+ const index = error.message.indexOf(')\n');
168
+ const msg = index !== -1 ? error.message.slice(0, index + 1) : error.message;
169
+ throw new Error(`${msg}\nAn error occurred inlining file "${filename}"`);
170
+ }
171
+ if (!ast) {
172
+ throw new Error(`Unknown error occurred inlining file "${filename}"`);
173
+ }
174
+ const { diagnostics, plugins } = await this.#createI18nPlugins(locale, translation);
175
+ const transformResult = await (0, core_2.transformFromAstAsync)(ast, code, {
176
+ filename,
177
+ // false is a valid value but not included in the type definition
178
+ inputSourceMap: false,
179
+ sourceMaps: !!map,
180
+ compact: shouldOptimize,
181
+ configFile: false,
182
+ babelrc: false,
183
+ browserslistConfigFile: false,
184
+ plugins,
185
+ });
186
+ if (!transformResult || !transformResult.code) {
187
+ throw new Error(`Unknown error occurred processing bundle for "${filename}".`);
188
+ }
189
+ let outputMap;
190
+ if (map && transformResult.map) {
191
+ outputMap = (0, remapping_1.default)([transformResult.map, map], () => null);
192
+ }
193
+ return {
194
+ code: transformResult.code,
195
+ map: outputMap && JSON.stringify(outputMap),
196
+ diagnostics,
197
+ };
198
+ }
199
+ async #getLanguageDirection(locale, warnings) {
200
+ const dir = await this.#getLanguageDirectionFromLocales(locale);
201
+ if (!dir) {
202
+ warnings.push(`Locale data for '${locale}' cannot be found. 'dir' attribute will not be set for this locale.`);
203
+ }
204
+ return dir;
205
+ }
206
+ async #getLanguageDirectionFromLocales(locale) {
207
+ try {
208
+ const localeData = (await this.#loadEsmModule(`@angular/common/locales/${locale}`)).default;
209
+ const dir = localeData[localeData.length - 2];
210
+ return this.#isString(dir) ? dir : undefined;
211
+ }
212
+ catch {
213
+ // In some cases certain locales might map to files which are named only with language id.
214
+ // Example: `en-US` -> `en`.
215
+ const [languageId] = locale.split('-', 1);
216
+ if (languageId !== locale) {
217
+ return this.#getLanguageDirectionFromLocales(languageId);
218
+ }
219
+ }
220
+ return undefined;
221
+ }
222
+ #isString(value) {
223
+ return typeof value === 'string';
224
+ }
225
+ }
226
+ exports.I18nInlinePlugin = I18nInlinePlugin;
@@ -1,8 +1,9 @@
1
1
  import { Compiler, RspackPluginInstance } from '@rspack/core';
2
- import { NormalizedAngularRspackPluginOptions } from '../models';
2
+ import { I18nOptions, NormalizedAngularRspackPluginOptions } from '../models';
3
3
  export declare class NgRspackPlugin implements RspackPluginInstance {
4
4
  pluginOptions: NormalizedAngularRspackPluginOptions;
5
- constructor(options: NormalizedAngularRspackPluginOptions);
5
+ i18n: I18nOptions | undefined;
6
+ constructor(options: NormalizedAngularRspackPluginOptions, i18nOptions?: I18nOptions);
6
7
  apply(compiler: Compiler): void;
7
8
  }
8
9
  //# sourceMappingURL=ng-rspack.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ng-rspack.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/ng-rspack.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAMR,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAItB,OAAO,EAAE,oCAAoC,EAAc,MAAM,WAAW,CAAC;AAG7E,qBAAa,cAAe,YAAW,oBAAoB;IACzD,aAAa,EAAE,oCAAoC,CAAC;gBAExC,OAAO,EAAE,oCAAoC;IAIzD,KAAK,CAAC,QAAQ,EAAE,QAAQ;CA2GzB"}
1
+ {"version":3,"file":"ng-rspack.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/ng-rspack.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAMR,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,WAAW,EACX,oCAAoC,EAErC,MAAM,WAAW,CAAC;AAGnB,qBAAa,cAAe,YAAW,oBAAoB;IACzD,aAAa,EAAE,oCAAoC,CAAC;IACpD,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;gBAG5B,OAAO,EAAE,oCAAoC,EAC7C,WAAW,CAAC,EAAE,WAAW;IAM3B,KAAK,CAAC,QAAQ,EAAE,QAAQ;CA+GzB"}
@@ -5,11 +5,14 @@ const core_1 = require("@rspack/core");
5
5
  const node_path_1 = require("node:path");
6
6
  const rxjs_esm_resolution_1 = require("./rxjs-esm-resolution");
7
7
  const angular_rspack_plugin_1 = require("./angular-rspack-plugin");
8
+ const i18n_inline_plugin_1 = require("./i18n-inline-plugin");
8
9
  const angular_ssr_dev_server_1 = require("./angular-ssr-dev-server");
9
10
  class NgRspackPlugin {
10
11
  pluginOptions;
11
- constructor(options) {
12
+ i18n;
13
+ constructor(options, i18nOptions) {
12
14
  this.pluginOptions = options;
15
+ this.i18n = i18nOptions;
13
16
  }
14
17
  apply(compiler) {
15
18
  const root = this.pluginOptions.root;
@@ -58,6 +61,7 @@ class NgRspackPlugin {
58
61
  ngDevMode: isProduction ? 'false' : {},
59
62
  ngJitMode: this.pluginOptions.aot ? undefined : 'true',
60
63
  ngServerMode: this.pluginOptions.hasServer,
64
+ ...(this.pluginOptions.define ?? {}),
61
65
  }).apply(compiler);
62
66
  if (this.pluginOptions.assets) {
63
67
  new core_1.CopyRspackPlugin({
@@ -100,8 +104,11 @@ class NgRspackPlugin {
100
104
  skipChildCompilers: true,
101
105
  }).apply(compiler);
102
106
  }
107
+ if (this.i18n?.shouldInline) {
108
+ new i18n_inline_plugin_1.I18nInlinePlugin(this.pluginOptions, this.i18n).apply(compiler);
109
+ }
103
110
  new rxjs_esm_resolution_1.RxjsEsmResolutionPlugin().apply(compiler);
104
- new angular_rspack_plugin_1.AngularRspackPlugin(this.pluginOptions).apply(compiler);
111
+ new angular_rspack_plugin_1.AngularRspackPlugin(this.pluginOptions, this.i18n).apply(compiler);
105
112
  }
106
113
  }
107
114
  exports.NgRspackPlugin = NgRspackPlugin;
@@ -0,0 +1,16 @@
1
+ import { ProjectGraphProjectNode } from '@nx/devkit';
2
+ type ProjectRootMappings = Map<string, string>;
3
+ /**
4
+ * This creates a map of project roots to project names to easily look up the project of a file
5
+ * @param nodes This is the nodes from the project graph
6
+ */
7
+ export declare function createProjectRootMappings(nodes: Record<string, ProjectGraphProjectNode>): ProjectRootMappings;
8
+ /**
9
+ * Locates a project in projectRootMap based on a file within it
10
+ * @param filePath path that is inside of projectName. This should be relative from the workspace root
11
+ * @param projectRootMap Map<projectRoot, projectName> Use {@link createProjectRootMappings} to create this
12
+ */
13
+ export declare function findProjectForPath(filePath: string, projectRootMap: ProjectRootMappings): string | undefined;
14
+ export declare function normalizeProjectRoot(root: string): string;
15
+ export {};
16
+ //# sourceMappingURL=find-project-for-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-project-for-path.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/find-project-for-path.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAiB,MAAM,YAAY,CAAC;AAGpE,KAAK,mBAAmB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,GAC7C,mBAAmB,CAQrB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,mBAAmB,GAClC,MAAM,GAAG,SAAS,CAkBpB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,UAGhD"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createProjectRootMappings = createProjectRootMappings;
4
+ exports.findProjectForPath = findProjectForPath;
5
+ exports.normalizeProjectRoot = normalizeProjectRoot;
6
+ // TODO: Remove this once migrated to Nx
7
+ const devkit_1 = require("@nx/devkit");
8
+ const node_path_1 = require("node:path");
9
+ /**
10
+ * This creates a map of project roots to project names to easily look up the project of a file
11
+ * @param nodes This is the nodes from the project graph
12
+ */
13
+ function createProjectRootMappings(nodes) {
14
+ const projectRootMappings = new Map();
15
+ for (const projectName of Object.keys(nodes)) {
16
+ const root = nodes[projectName].data.root;
17
+ projectRootMappings.set(normalizeProjectRoot(root), projectName);
18
+ }
19
+ return projectRootMappings;
20
+ }
21
+ /**
22
+ * Locates a project in projectRootMap based on a file within it
23
+ * @param filePath path that is inside of projectName. This should be relative from the workspace root
24
+ * @param projectRootMap Map<projectRoot, projectName> Use {@link createProjectRootMappings} to create this
25
+ */
26
+ function findProjectForPath(filePath, projectRootMap) {
27
+ /**
28
+ * Project Mappings are in UNIX-style file paths
29
+ * Windows may pass Win-style file paths
30
+ * Ensure filePath is in UNIX-style
31
+ */
32
+ let currentPath = (0, devkit_1.normalizePath)(filePath);
33
+ for (; currentPath != (0, node_path_1.dirname)(currentPath); currentPath = (0, node_path_1.dirname)(currentPath)) {
34
+ const p = projectRootMap.get(currentPath);
35
+ if (p) {
36
+ return p;
37
+ }
38
+ }
39
+ return projectRootMap.get(currentPath);
40
+ }
41
+ function normalizeProjectRoot(root) {
42
+ root = root === '' ? '.' : root;
43
+ return root && root.endsWith('/') ? root.substring(0, root.length - 1) : root;
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/angular-rspack",
3
- "version": "20.6.2",
3
+ "version": "20.7.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -44,6 +44,8 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
+ "@ampproject/remapping": "2.3.0",
48
+ "@babel/core": "7.26.10",
47
49
  "@nx/devkit": "^20.0.0",
48
50
  "express": "4.21.1",
49
51
  "css-loader": "^7.1.2",
@@ -57,7 +59,7 @@
57
59
  "tslib": "^2.3.0",
58
60
  "webpack-merge": "^6.0.1",
59
61
  "ws": "^8.18.0",
60
- "@nx/angular-rspack-compiler": "20.6.2"
62
+ "@nx/angular-rspack-compiler": "20.7.0"
61
63
  },
62
64
  "devDependencies": {
63
65
  "@ng-rspack/testing-setup": "0.0.1"
@@ -65,7 +67,9 @@
65
67
  "peerDependencies": {
66
68
  "@rspack/core": ">=1.0.5 <2.0.0",
67
69
  "@angular/common": ">=19.0.0 <20.0.0",
68
- "@angular/ssr": ">=19.0.0 <20.0.0"
70
+ "@angular/ssr": ">=19.0.0 <20.0.0",
71
+ "@angular/build": ">=19.0.0 <20.0.0",
72
+ "@angular/localize": ">=19.0.0 <20.0.0"
69
73
  },
70
74
  "nx": {
71
75
  "name": "angular-rspack",