Skip to content

Commit 5038325

Browse files
committed
fix(@angular/build): allow disabling sourcemaps in the dev server
This change introduces the ability to disable sourcemaps when running the development server. A new Vite plugin has been added to remove sourcemap comments from generated assets. The dev server's configuration has been updated to conditionally apply this plugin and control CSS sourcemap generation based on the project's sourceMap setting. Closes #31331
1 parent 44d9539 commit 5038325

File tree

5 files changed

+108
-28
lines changed

5 files changed

+108
-28
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { executeDevServer } from '../../index';
10+
import { executeOnceAndFetch } from '../execute-fetch';
11+
import { describeServeBuilder } from '../jasmine-helpers';
12+
import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup';
13+
14+
describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => {
15+
describe('Behavior: "buildTarget sourceMap"', () => {
16+
beforeEach(async () => {
17+
// Application code is not needed for these tests
18+
await harness.writeFile('src/main.ts', 'console.log("foo");');
19+
});
20+
21+
it('should not include sourcemaps when disabled', async () => {
22+
setupTarget(harness, {
23+
sourceMap: false,
24+
});
25+
26+
harness.useTarget('serve', {
27+
...BASE_OPTIONS,
28+
});
29+
30+
const { result, response } = await executeOnceAndFetch(harness, '/main.js');
31+
expect(result?.success).toBeTrue();
32+
expect(await response?.text()).not.toContain('//# sourceMappingURL=');
33+
});
34+
35+
it('should include sourcemaps when enabled', async () => {
36+
setupTarget(harness, {
37+
sourceMap: true,
38+
});
39+
40+
harness.useTarget('serve', {
41+
...BASE_OPTIONS,
42+
});
43+
44+
const { result, response } = await executeOnceAndFetch(harness, '/main.js');
45+
expect(result?.success).toBeTrue();
46+
expect(await response?.text()).toContain('//# sourceMappingURL=');
47+
});
48+
});
49+
});

packages/angular/build/src/builders/dev-server/vite/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,11 @@ export async function* serveWithVite(
130130
browserOptions.forceI18nFlatOutput = true;
131131
}
132132

133-
const { vendor: thirdPartySourcemaps, scripts: scriptsSourcemaps } = normalizeSourceMaps(
134-
browserOptions.sourceMap ?? false,
135-
);
133+
const {
134+
vendor: thirdPartySourcemaps,
135+
scripts: scriptsSourcemaps,
136+
styles: stylesSourceMap,
137+
} = normalizeSourceMaps(browserOptions.sourceMap ?? false);
136138

137139
if (scriptsSourcemaps && browserOptions.server) {
138140
// https://nodejs.org/api/process.html#processsetsourcemapsenabledval
@@ -441,6 +443,7 @@ export async function* serveWithVite(
441443
},
442444
extensions?.middleware,
443445
transformers?.indexHtml,
446+
scriptsSourcemaps || stylesSourceMap || thirdPartySourcemaps,
444447
thirdPartySourcemaps,
445448
);
446449

packages/angular/build/src/builders/dev-server/vite/server.ts

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { readFile } from 'node:fs/promises';
1010
import { join } from 'node:path';
11-
import type { Connect, InlineConfig, SSROptions, ServerOptions } from 'vite';
11+
import type { Connect, InlineConfig, Plugin, SSROptions, ServerOptions } from 'vite';
1212
import type { ComponentStyleRecord } from '../../../tools/vite/middlewares';
1313
import {
1414
ServerSsrMode,
@@ -17,6 +17,7 @@ import {
1717
createAngularSetupMiddlewaresPlugin,
1818
createAngularSsrTransformPlugin,
1919
createRemoveIdPrefixPlugin,
20+
removeSourceMapsPlugin,
2021
} from '../../../tools/vite/plugins';
2122
import { EsbuildLoaderOption, getDepOptimizationConfig } from '../../../tools/vite/utils';
2223
import { loadProxyConfiguration } from '../../../utils';
@@ -151,6 +152,7 @@ export async function setupServer(
151152
define: ApplicationBuilderInternalOptions['define'],
152153
extensionMiddleware?: Connect.NextHandleFunction[],
153154
indexHtmlTransformer?: (content: string) => Promise<string>,
155+
sourceMaps = true,
154156
thirdPartySourcemaps = false,
155157
): Promise<InlineConfig> {
156158
// dynamically import Vite for ESM compatibility
@@ -172,6 +174,34 @@ export async function setupServer(
172174
externalMetadata.explicitBrowser.length === 0 && ssrMode === ServerSsrMode.NoSsr;
173175
const cacheDir = join(serverOptions.cacheOptions.path, serverOptions.buildTarget.project, 'vite');
174176

177+
const plugins: Plugin[] = [
178+
createAngularLocaleDataPlugin(),
179+
createAngularSetupMiddlewaresPlugin({
180+
outputFiles,
181+
assets,
182+
indexHtmlTransformer,
183+
extensionMiddleware,
184+
componentStyles,
185+
templateUpdates,
186+
ssrMode,
187+
resetComponentUpdates: () => templateUpdates.clear(),
188+
projectRoot: serverOptions.projectRoot,
189+
}),
190+
createRemoveIdPrefixPlugin(externalMetadata.explicitBrowser),
191+
await createAngularSsrTransformPlugin(serverOptions.workspaceRoot),
192+
await createAngularMemoryPlugin({
193+
virtualProjectRoot,
194+
outputFiles,
195+
templateUpdates,
196+
external: externalMetadata.explicitBrowser,
197+
disableViteTransport: !serverOptions.liveReload,
198+
}),
199+
];
200+
201+
if (!sourceMaps) {
202+
plugins.push(removeSourceMapsPlugin);
203+
}
204+
175205
const configuration: InlineConfig = {
176206
configFile: false,
177207
envFile: false,
@@ -183,7 +213,7 @@ export async function setupServer(
183213
// We use custom as we do not rely on Vite's htmlFallbackMiddleware and indexHtmlMiddleware.
184214
appType: 'custom',
185215
css: {
186-
devSourcemap: true,
216+
devSourcemap: sourceMaps,
187217
},
188218
// Ensure custom 'file' loader build option entries are handled by Vite in application code that
189219
// reference third-party libraries. Relative usage is handled directly by the build and not Vite.
@@ -220,29 +250,7 @@ export async function setupServer(
220250
thirdPartySourcemaps,
221251
define,
222252
),
223-
plugins: [
224-
createAngularLocaleDataPlugin(),
225-
createAngularSetupMiddlewaresPlugin({
226-
outputFiles,
227-
assets,
228-
indexHtmlTransformer,
229-
extensionMiddleware,
230-
componentStyles,
231-
templateUpdates,
232-
ssrMode,
233-
resetComponentUpdates: () => templateUpdates.clear(),
234-
projectRoot: serverOptions.projectRoot,
235-
}),
236-
createRemoveIdPrefixPlugin(externalMetadata.explicitBrowser),
237-
await createAngularSsrTransformPlugin(serverOptions.workspaceRoot),
238-
await createAngularMemoryPlugin({
239-
virtualProjectRoot,
240-
outputFiles,
241-
templateUpdates,
242-
external: externalMetadata.explicitBrowser,
243-
disableViteTransport: !serverOptions.liveReload,
244-
}),
245-
],
253+
plugins,
246254
// Browser only optimizeDeps. (This does not run for SSR dependencies).
247255
optimizeDeps: getDepOptimizationConfig({
248256
// Only enable with caching since it causes prebundle dependencies to be cached

packages/angular/build/src/tools/vite/plugins/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export { createAngularLocaleDataPlugin } from './i18n-locale-plugin';
1111
export { createRemoveIdPrefixPlugin } from './id-prefix-plugin';
1212
export { createAngularSetupMiddlewaresPlugin, ServerSsrMode } from './setup-middlewares-plugin';
1313
export { createAngularSsrTransformPlugin } from './ssr-transform-plugin';
14+
export { removeSourceMapsPlugin } from './remove-sourcemaps';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import type { Plugin } from 'vite';
10+
11+
export const removeSourceMapsPlugin: Plugin = {
12+
name: 'vite:angular-remove-sourcemaps',
13+
transform(code) {
14+
return {
15+
code,
16+
map: { mappings: '' },
17+
};
18+
},
19+
};

0 commit comments

Comments
 (0)