Skip to content

Commit 49841f8

Browse files
alan-agius4mgechev
authored andcommitted
fix(@angular-devkit/build-angular): include HMR accept code in main.ts
This fixes as issue where in some cases the changed module is not accepted which cases the dev-server to fallback to live-reload. This is because the hmr.js and main.ts have different module ids.
1 parent 871dd6a commit 49841f8

File tree

5 files changed

+303
-212
lines changed

5 files changed

+303
-212
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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.io/license
7+
*/
8+
import { Architect, BuilderRun } from '@angular-devkit/architect';
9+
import { DevServerBuilderOutput } from '@angular-devkit/build-angular';
10+
import fetch from 'node-fetch'; // tslint:disable-line:no-implicit-dependencies
11+
import { createArchitect, host } from '../test-utils';
12+
13+
14+
describe('Dev Server Builder hmr', () => {
15+
const target = { project: 'app', target: 'serve' };
16+
let architect: Architect;
17+
// We use runs like this to ensure it WILL stop the servers at the end of each tests.
18+
let runs: BuilderRun[];
19+
20+
beforeEach(async () => {
21+
await host.initialize().toPromise();
22+
architect = (await createArchitect(host.root())).architect;
23+
runs = [];
24+
});
25+
afterEach(async () => {
26+
await host.restore().toPromise();
27+
await Promise.all(runs.map(r => r.stop()));
28+
});
29+
30+
it('adds HMR accept code in all JS bundles', async () => {
31+
const run = await architect.scheduleTarget(target, { hmr: true });
32+
runs.push(run);
33+
const output = await run.result as DevServerBuilderOutput;
34+
expect(output.success).toBe(true);
35+
expect(output.baseUrl).toBe('https://localhost:4200/');
36+
37+
const polyfills = await fetch('https://localhost:4200/polyfills.js');
38+
expect(await polyfills.text()).toContain('ngHmrAccept(module);');
39+
40+
const main = await fetch('https://localhost:4200/main.js');
41+
expect(await main.text()).toContain('ngHmrAccept(module);');
42+
}, 30000);
43+
});

packages/angular_devkit/build_angular/src/dev-server/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { assertCompatibleAngularVersion } from '../utils/version';
3838
import { getIndexInputFile, getIndexOutputFile } from '../utils/webpack-browser-config';
3939
import { addError, addWarning } from '../utils/webpack-diagnostics';
4040
import { normalizeExtraEntryPoints } from '../webpack/configs';
41+
import { HmrLoader } from '../webpack/plugins/hmr/hmr-loader';
4142
import { IndexHtmlWebpackPlugin } from '../webpack/plugins/index-html-webpack-plugin';
4243
import { createWebpackLoggingCallback } from '../webpack/utils/stats';
4344
import { Schema } from './schema';
@@ -591,6 +592,20 @@ function _addLiveReload(
591592
}
592593

593594
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
595+
596+
const hmrLoader: webpack.RuleSetRule = {
597+
loader: HmrLoader,
598+
include: [browserOptions.main].map(p => path.resolve(root, p)),
599+
};
600+
601+
if (typeof webpackConfig.module !== 'object') {
602+
webpackConfig.module = {
603+
rules: [hmrLoader],
604+
};
605+
} else {
606+
webpackConfig.module.rules.unshift(hmrLoader);
607+
}
608+
594609
}
595610
if (typeof webpackConfig.entry !== 'object' || Array.isArray(webpackConfig.entry)) {
596611
webpackConfig.entry = {};

packages/angular_devkit/build_angular/src/webpack/hmr.js

-212
This file was deleted.

0 commit comments

Comments
 (0)