Skip to content

feat(@angular/cli): Add hmr support for ng new #5396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const environment = {
production: false,<% if (hmr) { %>
hmr: true,<% } %>
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const environment = {
production: true
production: true,<% if (hmr) { %>
hmr: false,<% } %>
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const environment = {
production: false
production: false,<% if (hmr) { %>
hmr: false,<% } %>
};
15 changes: 15 additions & 0 deletions packages/@angular/cli/blueprints/ng/files/__path__/hmr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { NgModuleRef, ApplicationRef } from '@angular/core';
import { createNewHosts } from '@angularclass/hmr';

export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => {
let ngModule: NgModuleRef<any>;
module.hot.accept();
bootstrap().then(mod => ngModule = mod);
module.hot.dispose(() => {
let appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
let elements = appRef.components.map(c => c.location.nativeElement);
let makeVisible = createNewHosts(elements);
ngModule.destroy();
makeVisible();
});
};
19 changes: 17 additions & 2 deletions packages/@angular/cli/blueprints/ng/files/__path__/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,23 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
<% if (hmr) { %>import { hmrBootstrap } from './hmr';

<% } %>if (environment.production) {
enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule);
<% if (!hmr) { %>platformBrowserDynamic().bootstrapModule(AppModule);<% } %><% if (hmr) { %>const bootstrap = () => {
return platformBrowserDynamic().bootstrapModule(AppModule);
};

if (environment.hmr) {
if (module[ 'hot' ]) {
hmrBootstrap(module, bootstrap);
} else {
console.error('HMR is not enabled for webpack-dev-server!');
console.log('Are you using the --hmr flag for ng serve?');
}
} else {
bootstrap();
}<% } %>
3 changes: 2 additions & 1 deletion packages/@angular/cli/blueprints/ng/files/angular-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"dev": "environments/environment.ts",<% if (hmr) { %>
"hmr": "environments/environment.hmr.ts",<% } %>
"prod": "environments/environment.prod.ts"
}
}
Expand Down
6 changes: 4 additions & 2 deletions packages/@angular/cli/blueprints/ng/files/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"start": "ng serve",<% if (hmr) { %>
"hmr": "ng serve --hmr -e=hmr",<% } %>
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
Expand All @@ -26,7 +27,8 @@
},
"devDependencies": {
"@angular/cli": "<%= version %>",
"@angular/compiler-cli": "<%= ng4 ? '>=4.0.0-beta <5.0.0' : '^2.4.0' %>",
"@angular/compiler-cli": "<%= ng4 ? '>=4.0.0-beta <5.0.0' : '^2.4.0' %>",<% if (hmr) { %>
"@angularclass/hmr": "^1.2.2",<% } %>
"@types/jasmine": "2.5.38",
"@types/node": "~6.0.60",
"codelyzer": "~2.0.0",
Expand Down
8 changes: 7 additions & 1 deletion packages/@angular/cli/blueprints/ng/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export default Blueprint.extend({
{ name: 'routing', type: Boolean, default: false },
{ name: 'inline-style', type: Boolean, default: false, aliases: ['is'] },
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] },
{ name: 'skip-git', type: Boolean, default: false, aliases: ['sg'] }
{ name: 'skip-git', type: Boolean, default: false, aliases: ['sg'] },
{ name: 'hmr', type: Boolean, default: false }
],

beforeInstall: function(options: any) {
Expand Down Expand Up @@ -54,6 +55,7 @@ export default Blueprint.extend({
routing: options.routing,
inlineStyle: options.inlineStyle,
inlineTemplate: options.inlineTemplate,
hmr: options.hmr,
ng4: options.ng4,
tests: this.tests
};
Expand All @@ -71,6 +73,10 @@ export default Blueprint.extend({
if (this.options && this.options.inlineStyle) {
fileList = fileList.filter(p => p.indexOf('app.component.__styleext__') < 0);
}
if (this.options && !this.options.hmr) {
fileList = fileList.filter(p => p.indexOf('environment.hmr.ts') < 0);
fileList = fileList.filter(p => p.indexOf('hmr.ts') < 0);
}
if (this.options && this.options.skipGit) {
fileList = fileList.filter(p => p.indexOf('gitignore') < 0);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/@angular/cli/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const InitCommand: any = Command.extend({
{ name: 'prefix', type: String, default: 'app', aliases: ['p'] },
{ name: 'routing', type: Boolean, default: false },
{ name: 'inline-style', type: Boolean, default: false, aliases: ['is'] },
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] }
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] },
{ name: 'hmr', type: Boolean, default: false }
],

anonymousOptions: ['<glob-pattern>'],
Expand Down
8 changes: 7 additions & 1 deletion packages/@angular/cli/commands/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,13 @@ const NewCommand = Command.extend({
default: false,
aliases: ['it'],
description: 'Should have an inline template.'
}
},
{
name: 'hmr',
type: Boolean,
default: false,
description: 'Should enable hot module replacement.'
}
],

isProject: function (projectPath: string) {
Expand Down
1 change: 1 addition & 0 deletions packages/@angular/cli/tasks/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default Task.extend({
routing: commandOptions.routing,
inlineStyle: commandOptions.inlineStyle,
inlineTemplate: commandOptions.inlineTemplate,
hmr: commandOptions.hmr,
ignoredUpdateFiles: ['favicon.ico'],
ng4: commandOptions.ng4,
skipGit: commandOptions.skipGit,
Expand Down
6 changes: 0 additions & 6 deletions packages/@angular/cli/tasks/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,9 @@ export default Task.extend({
`webpack-dev-server/client?${clientAddress}`
];
if (serveTaskOptions.hmr) {
const webpackHmrLink = 'https://webpack.github.io/docs/hot-module-replacement.html';
ui.writeLine(oneLine`
${chalk.yellow('NOTICE')} Hot Module Replacement (HMR) is enabled for the dev server.
`);
ui.writeLine(' The project will still live reload when HMR is enabled,');
ui.writeLine(' but to take advantage of HMR additional application code is required');
ui.writeLine(' (not included in an Angular CLI project by default).');
ui.writeLine(` See ${chalk.blue(webpackHmrLink)}`);
ui.writeLine(' for information on working with HMR for Webpack.');
entryPoints.push('webpack/hot/dev-server');
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
webpackConfig.plugins.push(new webpack.NamedModulesPlugin());
Expand Down