Skip to content

Commit 5ae264e

Browse files
authored
feat(angular-rspack,angular-rsbuild): add sourcemap option (#29)
1 parent 4919981 commit 5ae264e

19 files changed

+347
-19
lines changed

e2e/fixtures/rsbuild-csr-css/eslint.next.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,7 @@ module.exports = [
3939
parser: require('jsonc-eslint-parser'),
4040
},
4141
},
42+
{
43+
ignores: ['build'],
44+
},
4245
];

e2e/fixtures/rspack-csr-css/rspack.config.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ module.exports = () => {
1212
polyfills: ['zone.js'],
1313
main: './src/main.ts',
1414
outputPath: {
15-
base: './build',
16-
browser: './build/static',
15+
base: './dist',
16+
browser: './dist/static',
17+
},
18+
sourceMap: {
19+
scripts: true,
20+
styles: true,
1721
},
1822
outputHashing: 'none',
1923
tsConfig: join(__dirname, './tsconfig.app.json'),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
div {
2+
color: red;
3+
}

packages/angular-rsbuild/src/lib/config/create-config.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export async function _createConfig(
4444
stylePlugins.push(
4545
pluginSass({
4646
sassLoaderOptions: {
47+
sourceMap: normalizedOptions.sourceMap.styles,
4748
sassOptions: {
4849
includePaths:
4950
normalizedOptions.stylePreprocessorOptions?.includePaths,
@@ -53,13 +54,20 @@ export async function _createConfig(
5354
})
5455
);
5556
} else {
56-
stylePlugins.push(pluginSass());
57+
stylePlugins.push(
58+
pluginSass({
59+
sassLoaderOptions: {
60+
sourceMap: normalizedOptions.sourceMap.styles,
61+
},
62+
})
63+
);
5764
}
5865
} else if (normalizedOptions.inlineStyleLanguage === 'less') {
5966
if (normalizedOptions.stylePreprocessorOptions?.includePaths) {
6067
stylePlugins.push(
6168
pluginLess({
6269
lessLoaderOptions: {
70+
sourceMap: normalizedOptions.sourceMap.styles,
6371
lessOptions: {
6472
javascriptEnabled: true,
6573
paths: normalizedOptions.stylePreprocessorOptions?.includePaths,
@@ -71,6 +79,7 @@ export async function _createConfig(
7179
stylePlugins.push(
7280
pluginLess({
7381
lessLoaderOptions: {
82+
sourceMap: normalizedOptions.sourceMap.styles,
7483
lessOptions: {
7584
javascriptEnabled: true,
7685
},
@@ -153,6 +162,10 @@ export async function _createConfig(
153162
js: `[name]${hashFormat.chunk}.js`,
154163
css: `[name]${hashFormat.file}.css`,
155164
},
165+
sourceMap: {
166+
js: normalizedOptions.sourceMap.scripts ? 'source-map' : false,
167+
css: normalizedOptions.sourceMap.styles,
168+
},
156169
distPath: {
157170
root: normalizedOptions.outputPath.browser,
158171
js: '',

packages/angular-rsbuild/src/lib/config/create-config.unit.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ describe('createConfig', () => {
108108
server: 'dist/server',
109109
media: 'dist/browser/media',
110110
},
111+
sourceMap: {
112+
scripts: true,
113+
styles: true,
114+
hidden: false,
115+
vendor: false,
116+
},
111117
},
112118
rsbuildConfigOverrides: {
113119
source: {
@@ -145,6 +151,12 @@ describe('createConfig', () => {
145151
server: 'dist/server',
146152
media: 'dist/browser/media',
147153
},
154+
sourceMap: {
155+
scripts: true,
156+
styles: true,
157+
hidden: false,
158+
vendor: false,
159+
},
148160
devServer: {
149161
port: 8080,
150162
},

packages/angular-rsbuild/src/lib/models/normalize-options.ts

+30
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
type DevServerOptions,
55
OutputPath,
66
NormalizedPluginAngularOptions,
7+
SourceMap,
78
} from './plugin-options';
89
import { join, resolve } from 'node:path';
910
import { existsSync } from 'node:fs';
@@ -89,6 +90,7 @@ export const DEFAULT_PLUGIN_ANGULAR_OPTIONS: PluginAngularOptions = {
8990
optimization: true,
9091
outputPath: normalizeOutputPath(process.cwd(), undefined),
9192
outputHashing: 'all',
93+
sourceMap: false,
9294
useTsProjectReferences: false,
9395
skipTypeChecking: false,
9496
devServer: {
@@ -132,6 +134,7 @@ export function normalizeOptions(
132134
...(ssr != null ? { ssr: normalizedSsr } : {}),
133135
optimization: normalizedOptimization,
134136
outputPath: normalizeOutputPath(root, options.outputPath),
137+
sourceMap: normalizeSourceMap(options.sourceMap),
135138
advancedOptimizations,
136139
aot,
137140
outputHashing: options.outputHashing ?? 'all',
@@ -141,6 +144,33 @@ export function normalizeOptions(
141144
};
142145
}
143146

147+
function normalizeSourceMap(
148+
sourceMap: boolean | Partial<SourceMap> | undefined
149+
): SourceMap {
150+
if (sourceMap === undefined || sourceMap === true) {
151+
return {
152+
scripts: true,
153+
styles: true,
154+
hidden: false,
155+
vendor: false,
156+
};
157+
}
158+
if (sourceMap === false) {
159+
return {
160+
scripts: false,
161+
styles: false,
162+
hidden: false,
163+
vendor: false,
164+
};
165+
}
166+
return {
167+
scripts: sourceMap.scripts ?? true,
168+
styles: sourceMap.styles ?? true,
169+
hidden: sourceMap.hidden ?? false,
170+
vendor: sourceMap.vendor ?? false,
171+
};
172+
}
173+
144174
function normalizeDevServer(
145175
devServer: DevServerOptions | undefined
146176
): DevServerOptions & { port: number } {

packages/angular-rsbuild/src/lib/models/normalize-options.unit.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ describe('normalizeOptions', () => {
126126
defaultOptions = {
127127
...DEFAULT_PLUGIN_ANGULAR_OPTIONS,
128128
outputPath: normalizeOutputPath(process.cwd(), undefined),
129+
sourceMap: {
130+
scripts: true,
131+
styles: true,
132+
hidden: false,
133+
vendor: false,
134+
},
129135
};
130136
});
131137

packages/angular-rsbuild/src/lib/models/plugin-options.ts

+9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ export interface OutputPath {
3333
media: string;
3434
}
3535

36+
export interface SourceMap {
37+
scripts: boolean;
38+
styles: boolean;
39+
hidden: boolean;
40+
vendor: boolean;
41+
}
42+
3643
export interface PluginAngularOptions {
3744
index: string;
3845
browser: string;
@@ -52,6 +59,7 @@ export interface PluginAngularOptions {
5259
aot: boolean;
5360
inlineStyleLanguage: InlineStyleLanguage;
5461
tsConfig: string;
62+
sourceMap?: boolean | Partial<SourceMap>;
5563
optimization?: boolean | OptimizationOptions;
5664
outputHashing?: OutputHashing;
5765
hasServer: boolean;
@@ -67,4 +75,5 @@ export interface NormalizedPluginAngularOptions extends PluginAngularOptions {
6775
optimization: boolean | OptimizationOptions;
6876
outputHashing: OutputHashing;
6977
outputPath: OutputPath;
78+
sourceMap: SourceMap;
7079
}

packages/angular-rsbuild/src/lib/plugin/plugin-hoisted-js-transformer.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,15 @@ export const pluginHoistedJsTransformer = (
2929
} = { errors: undefined, warnings: undefined };
3030
const javascriptTransformer = new JavaScriptTransformer(
3131
{
32-
sourcemap: false,
33-
thirdPartySourcemaps: false,
32+
/**
33+
* Matches https://github.com/angular/angular-cli/blob/33ed6e875e509ebbaa0cbdb57be9e932f9915dff/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts#L89
34+
* where pluginOptions.sourcemap is set https://github.com/angular/angular-cli/blob/61d98fde122468978de9b17bd79761befdbf2fac/packages/angular/build/src/tools/esbuild/compiler-plugin-options.ts#L34
35+
*/
36+
sourcemap: !!(
37+
pluginOptions.sourceMap.scripts &&
38+
(pluginOptions.sourceMap.hidden ? 'external' : true)
39+
),
40+
thirdPartySourcemaps: pluginOptions.sourceMap.vendor,
3441
// @TODO: it should be `pluginOptions.advancedOptimizations` but it currently fails the build
3542
advancedOptimizations: false,
3643
jit: !pluginOptions.aot,

packages/angular-rspack/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@nx/angular-rspack-compiler": "workspace:*",
4949
"@nx/devkit": "^20.0.0",
5050
"express": "4.21.1",
51+
"source-map-loader": "^5.0.0",
5152
"jsonc-parser": "^3.3.1",
5253
"less-loader": "^12.2.0",
5354
"license-webpack-plugin": "^4.0.2",

packages/angular-rspack/src/lib/config/create-config.ts

+77-3
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,79 @@ import {
33
Configuration,
44
DevServer,
55
SwcJsMinimizerRspackPlugin,
6+
SourceMapDevToolPlugin,
7+
RspackPluginInstance,
8+
RuleSetRule,
69
} from '@rspack/core';
710
import { merge as rspackMerge } from 'webpack-merge';
811
import { resolve } from 'path';
9-
import { AngularRspackPluginOptions, normalizeOptions } from '../models';
12+
import {
13+
AngularRspackPluginOptions,
14+
normalizeOptions,
15+
SourceMap,
16+
} from '../models';
1017
import {
1118
JS_ALL_EXT_REGEX,
1219
TS_ALL_EXT_REGEX,
1320
} from '@nx/angular-rspack-compiler';
1421
import { getStyleLoaders } from './style-config-utils';
1522
import { getOutputHashFormat } from './helpers';
1623
import { getProxyConfig } from './dev-server-config-utils';
24+
import { DevToolsIgnorePlugin } from '../plugins/tools/dev-tools-ignore-plugin';
25+
26+
function configureSourceMap(sourceMap: SourceMap) {
27+
const { scripts, styles, hidden, vendor } = sourceMap;
28+
29+
const sourceMapRules: RuleSetRule[] = [];
30+
const sourceMapPlugins: RspackPluginInstance[] = [];
31+
32+
if (scripts || styles) {
33+
const include: RegExp[] = [];
34+
if (scripts) {
35+
include.push(/js$/);
36+
}
37+
38+
if (styles) {
39+
include.push(/css$/);
40+
}
41+
42+
sourceMapPlugins.push(new DevToolsIgnorePlugin());
43+
44+
sourceMapPlugins.push(
45+
new SourceMapDevToolPlugin({
46+
filename: '[file].map',
47+
include,
48+
// We want to set sourceRoot to `webpack:///` for non
49+
// inline sourcemaps as otherwise paths to sourcemaps will be broken in browser
50+
// `webpack:///` is needed for Visual Studio breakpoints to work properly as currently
51+
// there is no way to set the 'webRoot'
52+
sourceRoot: 'webpack:///',
53+
moduleFilenameTemplate: '[resource-path]',
54+
append: hidden ? false : undefined,
55+
})
56+
);
57+
58+
sourceMapRules.push({
59+
test: /\.[cm]?jsx?$/,
60+
enforce: 'pre',
61+
loader: require.resolve('source-map-loader'),
62+
options: {
63+
filterSourceMappingUrl: (_mapUri: string, resourcePath: string) => {
64+
if (vendor) {
65+
// Consume all sourcemaps when vendor option is enabled.
66+
return true;
67+
}
68+
69+
// Don't consume sourcemaps in node_modules when vendor is disabled.
70+
// But, do consume local libraries sourcemaps.
71+
return !resourcePath.includes('node_modules');
72+
},
73+
},
74+
});
75+
}
76+
77+
return { sourceMapRules, sourceMapPlugins };
78+
}
1779

1880
export async function _createConfig(
1981
options: AngularRspackPluginOptions,
@@ -24,15 +86,23 @@ export async function _createConfig(
2486
const hashFormat = getOutputHashFormat(normalizedOptions.outputHashing);
2587
const root = process.cwd();
2688

89+
const { sourceMapRules, sourceMapPlugins } = configureSourceMap(
90+
normalizedOptions.sourceMap
91+
);
92+
2793
const defaultConfig: Configuration = {
2894
context: root,
2995
mode: isProduction ? 'production' : 'development',
96+
devtool: normalizedOptions.sourceMap.scripts ? 'source-map' : undefined,
3097
output: {
3198
uniqueName: 'rspack-angular',
3299
publicPath: 'auto',
33100
clean: true,
34101
crossOriginLoading: false,
35102
trustedTypes: { policyName: 'angular#bundler' },
103+
sourceMapFilename: normalizedOptions.sourceMap.scripts
104+
? '[file].map'
105+
: undefined,
36106
},
37107
resolve: {
38108
extensions: ['.ts', '.tsx', '.mjs', '.js'],
@@ -57,7 +127,11 @@ export async function _createConfig(
57127
},
58128
},
59129
rules: [
60-
...getStyleLoaders(options.stylePreprocessorOptions),
130+
...getStyleLoaders(
131+
normalizedOptions.stylePreprocessorOptions,
132+
normalizedOptions.sourceMap
133+
),
134+
...sourceMapRules,
61135
{ test: /[/\\]rxjs[/\\]add[/\\].+\.js$/, sideEffects: true },
62136
{
63137
test: TS_ALL_EXT_REGEX,
@@ -92,7 +166,7 @@ export async function _createConfig(
92166
},
93167
],
94168
},
95-
plugins: [],
169+
plugins: [...sourceMapPlugins],
96170
};
97171

98172
const configs: Configuration[] = [];

0 commit comments

Comments
 (0)