让@angular/cli项目支持Hot Module Replacement(HMR)

1,894 阅读2分钟
原文链接: zhuanlan.zhihu.com

什么是HMR?

噢,你自己看看[这里的官方文档](Hot Module Replacement)就好了,不解释。

@angluar/cli 默认没有很好地支持HMR,我们需要手动做一些事情。

请跟我一步一步来玩。

第一步:修改环境配置文件

为了后续操作能顺利进行,首先需要修改默认生成的两份环境配置文件:src/environments/environment.ts 和 src/environments/environment.prod.ts

在这两份配置文件里面都增加一个配置项hmr:false,变成这样:

    export const environment = {
         production: true,
         hmr: false,
         ...
    };

第二步:新建一份hmr配置文件

创建一份全新的环境配置文件:src/environments/environment.hmr.ts

environment.hmr.ts 里面的内容如下:

    export const environment = {
         production: false,
         hmr: true
    };

修改.angular-cli.json,加一行配置,变成这样:

    "environmentSource": "environments/environment.ts",
    "environments": {
          ...
          "hmr": "environments/environment.hmr.ts",
    }

修改package.json,加一行脚本:

    "scripts": {
          ...
          "hmr": "ng serve --hmr -e=hmr"
    }

第三步:安装第三方支持模块同时写一些代码

    npm install --save-dev @angularclass/hmr

创建一份文件:src/hmr.ts ,里面的完整内容如下:

    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(currentModule => ngModule = currentModule);
      module.hot.dispose(() => {
          const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
          const elements = appRef.components.map(c => c.location.nativeElement);
          const removeOldHosts = createNewHosts(elements);
          ngModule.destroy();
          removeOldHosts();
      });
    };

代码很简单,相信你能看懂,不解释了。

写一行代码很简单,解释一行代码可能需要一千行注释,故:一码胜千言。

修改默认生成的src/main.ts,把内容改成这样:

    import { enableProdMode } from '@angular/core';
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

    import { AppModule } from './app/app.module';
    import { environment } from './environments/environment';

    import { hmrBootstrap } from './hmr';

    if (environment.production) {
        enableProdMode();
    }

    const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);

    if (environment.hmr) {
        if (module[ 'hot' ]) {
            hmrBootstrap(module, bootstrap);
        } else {
            console.error('Ammm.. HMR is not enabled for webpack');
        }
    } else {
        bootstrap();
    }

第四步:启动项目

npm run hmr

然后你会看到这样的警告,无视就好了:

注意点

  • HMR的好处是:开发的时候不需要每次都整体刷新浏览器,只替换被修改过的模块
  • 不要把HMR在生产环境里面,因为你不能每次改了代码都去刷所有客户的浏览器
  • HMR启动的方式不是ng serve,而是npm run hmr,请特别注意一下。

cli v6.x已经内置了HMR支持

特别注意:最新的@angular/cli 6.x 版本已经内置了 HMR 支持,只要执行以下命令即可(上面的所有步骤都不需要了,所以赶紧升级到V6.0吧!):

ng serve --hmr

OpenWMS这个项目的前端已经升级到V6.0.0,有需要参考一下吧:

用户登录 - 码云 Gitee.com

本文由 @业余小编 意译改写,英文版原文在这里:

medium.com/wizardnet97…