-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Current Behavior
Building an Angular app with @nx/angular-rspack
(either through the plugin or via the Rspack executor) fails when the app imports JSON (or any non-JS/TS) modules. Angular’s JavaScript transformer treats the JSON as JavaScript and forwards it to Babel parser, which then fails with a parse error:
SyntaxError: .../data/timezones.json: Missing semicolon.
at .../@angular/build/node_modules/@babel/core/lib/parser/index.js
at .../@angular/build/node_modules/@babel/core/lib/transformation/normalize-file.js
The same project builds successfully when using the Webpack executor (@nx/angular:webpack-browser
).
Expected Behavior
Non-JS/TS assets such as .json
should be handled by Rspack’s native JSON module support and should not be pre-processed by Angular’s Babel step.
GitHub Repo
No response
Steps to Reproduce
- Create a new workspace and generate Angular app with Rspack as bundler:
npx create-nx-workspace myorg
npx nx g @nx/angular:app myapp --bundler=rspack
-
In
apps/myapp/tsconfig.app.json
, ensure"resolveJsonModule": true
. -
Create a JSON file with an object at the top level, for example
apps/myapp/src/app/data/timezones.json
:
{ "UTC": "+00:00" }
- Import it from a TypeScript file, for example
apps/<app>/src/app/app.component.ts
:
import timezones from './data/timezones.json';
console.log(timezones.UTC);
- Build the app with Rspack:
npx nx build myapp
- Observe a Babel parse error like:
SyntaxError: .../data/timezones.json: Missing semicolon.
Nx Report
Node : 22.16.0
OS : darwin-arm64
Native Target : aarch64-macos
yarn : 1.22.19
nx (global) : 21.3.11
nx : 21.4.1
@nx/js : 21.4.1
@nx/jest : 21.4.1
@nx/eslint : 21.4.1
@nx/workspace : 21.4.1
@nx/angular : 21.4.1
@nx/cypress : 21.4.1
@nx/devkit : 21.4.1
@nx/eslint-plugin : 21.4.1
@nx/module-federation : 21.4.1
@nx/plugin : 21.4.1
@nx/react : 21.4.1
@nx/rollup : 21.4.1
@nx/rspack : 21.4.1
@nx/storybook : 21.4.1
@nx/vite : 21.4.1
@nx/web : 21.4.1
@nx/webpack : 21.4.1
typescript : 5.8.3
---------------------------------------
Community plugins:
@ngrx/component-store : 20.0.1
@ngrx/effects : 20.0.1
@ngrx/entity : 20.0.1
@ngrx/operators : 20.0.1
@ngrx/schematics : 20.0.1
@ngrx/store : 20.0.1
@nx/s3-cache : 2.1.0
@testing-library/angular : 16.0.0
ng2-charts : 4.1.1
---------------------------------------
Operating System
- macOS
- Linux
- Windows
- Other (Please specify)
Additional Information
Nx’s Rspack integration runs Angular compilation and then invokes Angular’s JavaScriptTransformer.transformData
on every emitted file, including non-JS assets like JSON. This causes JSON to be forwarded to Babel parser and parsed as JavaScript, which fails for object-top-level JSON.
Relevant code: packages/angular-rspack-compiler/src/compilation/build-and-analyze.ts
for (const {
filename,
contents
} of await angularCompilation.emitAffectedFiles()) {
const normalizedFilename = normalize(filename.replace(/^[A-Z]:/, ''));
// This line unconditionally passes any asset to `@angular/build` which uses Babel parser to parse it
await javascriptTransformer
.transformData(normalizedFilename, contents, true, false)
.then((contents) => {
typescriptFileCache.set(
normalizedFilename,
Buffer.from(contents).toString()
);
});
}
The impact is that JSON imports (both static and dynamic) fail, and potentially any non-JS/TS asset referenced from TypeScript (e.g., CSS, SVG-as-source) could be incorrectly handed to Babel.
A fix in @nx/angular-rspack-compiler
would be to skip non-JS/TS files before calling transformData
, letting Rspack process them via its module rules. For example:
const JS_LIKE = /\.[cm]?[jt]sx?$/;
for (const { filename, contents } of await angularCompilation.emitAffectedFiles()) {
const normalizedFilename = normalize(filename.replace(/^[A-Z]:/, ''));
if (!JS_LIKE.test(normalizedFilename)) {
const text = typeof contents === 'string' ? contents : Buffer.from(contents).toString();
typescriptFileCache.set(normalizedFilename, text);
continue;
}
const out = await javascriptTransformer.transformData(normalizedFilename, contents, true, false);
typescriptFileCache.set(normalizedFilename, Buffer.from(out).toString());
}