返回博客首页
← 所有文章

NativeScript Angular 8.0 中的延迟加载

2019 年 9 月 24 日 — 作者:Stanimira Vlaeva

Angular 8.0 不再推荐使用字符串语法来配置延迟加载路由,而是推荐使用 EcmaScript 动态导入。import(specifier) 语法形式返回一个包含模块命名空间对象的 Promise。在 Promise 解析后,我们获取导出的 LazyModule。

之前

const routes: Routes = [{
  path: 'lazy',
  // The following string syntax for loadChildren is deprecated
  loadChildren: './lazy/lazy.module#LazyModule'
}];

之后

const routes: Routes = [{
  path: 'lazy',
  // The new import() syntax
  loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
}];

NativeScript Angular 支持

您也可以在 NativeScript Angular 中使用新的延迟加载语法!

动态导入提案已计划在 ES2020 中发布。它也被所有主流浏览器实现。由于它比较新,因此您需要告诉 TypeScript 在编译代码时使用最新的 EcmaScript 模块规范。打开您的 tsconfig.tns.json 文件并将 module 属性设置为 esNext

tsconfig.tns.json

{
    "extends": "./tsconfig",
    "compilerOptions": {
        "module": "esNext",
        "moduleResolution": "node"
    }
}
重要提示! NativeScript Playground 目前不支持动态导入。在 Playground 中编写 NativeScript Angular 应用程序时,目前请坚持使用旧的延迟加载语法。

自动路由迁移

将所有路由迁移到新的语法可能相当繁琐。但是您可以告诉 TSLint 为您执行此操作!

首先,确保您的项目中安装了 TSLint

npm install tslint --save-dev

之后,安装由 Craig Spence 创建的 angular-lazy-routes-fix TSLint 规则

npm install @phenomnomnominal/angular-lazy-routes-fix --save-dev

然后,将该规则添加到您的 TSLint 配置文件中。如果您没有配置文件,则只需创建一个新的 tslint.json 文件

tslint.json

{
  "extends": [
    "@phenomnomnominal/angular-lazy-routes-fix"
  ],
  "rules": {
    "no-lazy-module-paths": [true]
  }
}

最后,使用 --fix 标志运行 TSLint

npx tslint -p tsconfig.json --fix

代码 linter 会找到所有旧延迟加载语法的使用情况,并将其替换为动态导入。

它是如何工作的?

NativeScript 运行时并不原生支持 import() 语法。但是,借助 webpackAngular,您可以在路由配置中使用它。当您使用 webpack 构建项目时,以下代码

const routes: Routes = [{
  path: 'lazy',
  loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
}];

大致转换为

const routes: Routes = [{
  path: 'lazy',
  loadChildren: requireEnsure('./1.js').LazyModule
}];

文件 1.js/lazy 路由的 延迟加载捆绑包。它包含名为 LazyModuleNgModule 以及它所依赖的所有 ComponentsDirectives 和其他 NgModules

旁注:1.js 不包含任何第三方包。相反,应用程序中任何地方所需的来自 node_modules 的所有包都将最终出现在名为 vendor.js 的捆绑包中。

延迟加载捆绑包requireEnsure 函数从文件系统加载。该函数由 webpack 插入。如果您是为浏览器、Node 或 NativeScript 构建,则 requireEnsure 函数的定义会有所不同。

旁注:在 NativeScript 中,该函数的定义是从位于 nativescript-target for webpack 中的模板生成的。

对于 NativeScript,requireEnsure 函数的实现仅使用 require() 调用加载文件,然后对其进行缓存。因此,最终您永远不会在应用程序中实际发布动态 import(),而是将其全部转换为传统的 CommonJS require()。NativeScript 运行时通过从设备文件系统加载文件来实现 require() 函数。

总结

整个模块加载故事中的主要要点是

  • Angular 8.0 现在建议使用动态 import() 加载延迟加载模块。
  • NativeScript Angular 8.0 支持新的配置语法,尽管您仍然无法在 NativeScript Playground 中使用它。
  • 您可以使用 TSLint 迁移现有的路由配置。
  • 动态 import() 并非原生支持,但在构建过程中 webpack 会将其替换为 require()