【问题标题】:Is there a reason why Angular CLI configures to not load scripts on demand?Angular CLI 配置为不按需加载脚本是否有原因?
【发布时间】:2016-12-27 17:02:27
【问题描述】:

我是 Angular 2 和模块加载器的新手。我正在使用 Angular CLI 构建我的项目。我了解到 Webpack 会加载应用程序所需的模块(tree-shaking?)并将它们打包到一个或几个文件中。我仍然对此和根据用户需求下载脚本文件感到困惑。完成后,我的 Angular 应用程序可能会有大约 100 个组件。采用默认的 CLI 方式并一次将所有组件交付给客户端是否明智,还是按需加载它们更好?

【问题讨论】:

  • 你说的“加载”是什么意思? Angular 2 和 CLI 支持延迟加载模块,但您在开始时下载文件一次。这避免了当用户使用时的网络开销,例如切换到不同的选项卡。摇树是关于删除你不需要需要的代码。
  • 加载是指将 JS 交付给客户端。所以我知道Webpack仅在需要时才将JS加载到内存中,但下载已经完成。我对吗?如果应用程序中有 100 个组件,您认为这样做是否明智?将组件拆分成多个模块会有帮助吗?
  • SPA 的一点是用户可以在应用程序中快速移动而无需等待页面加载,因为他们已经拥有这些页面。权衡是初始下载大小。如果这种折衷对您不起作用,也许 SPA 不适合?但我鼓励您在花时间解决之前找出是否确实存在性能问题

标签: angular webpack angular-cli


【解决方案1】:

对不起,答案很长,但从问题看来,我们需要先了解一些基础知识。

模块捆绑器

一个聪明的模块打包器可以:

  • 静态分析您的导入(以及您的导入等的导入),以进行 tree-shaking,其中不包括从未导入的代码。

    这仅适用于将脚本用作模块时。这就是为什么一个好的模块捆绑器会给你一种方法来从这个操作中排除一些遗留脚本。

    请注意,这不是丑化或最小化。 minifier / uglifier 可能会根据其对代码的理解删除看起来未使用的代码,但是如果走得太远,可以删除一些实际使用的代码(例如,尝试按名称加载函数,其中名称是动态的一个字符串。Minifier 可能认为该函数从未使用过)。

    Tree Shaking 仅适用于导入,因为它们是静态的,不能是动态的。 SystemJS 是一个模块捆绑器,可以使它们动态化,但这意味着在单独的请求中加载大量额外的文件,从而导致对用户的响应时间更长。

  • 适当优化文件总数,并以最佳方式为它们服务

    即单个文件保存HTTP请求,加载速度快,除非文件很大,浏览器没有被文件阻塞,可以加载多个文件。除了加载多个文件也有其局限性,因为浏览器不会并行化这么多文件。

    一个好的打包工具会在此基础上为您提供一些额外的东西,比如关于文件大小的统计信息,比如根据文件内容在文件名中生成唯一的哈希值,这样当文件内容发生更改时,更改文件的 URL 总是可以不同.它也会将动态名称注入到您的 HTML 中。

  • 它会给你一种延迟加载模块的方法--这就是你在说的

    您比任何人都更了解您的应用程序。你对你的用户有一定的期望。您知道当应用程序加载时应用程序的哪些部分可以更好地准备好并且不需要时间来加载,哪些只会使初始负载过大并且实际上会对用户体验产生负面影响。

    一个好的捆绑器允许您指定要“延迟加载”的位,或分离到不同的文件中,并在用户请求这些位时透明地为您加载该文件。

Webpack 和 Angular CLI

您可能已经猜到了,Webpack 2 完成了我们所说的优秀打包器应该做的所有事情。它:

  • 在适当的捆绑脚本中加载文件
  • 应用优化,如摇树、散列和最小化
  • 允许从 tree-shaking 或整个处理中排除文件
  • 将动态脚本名称注入您的 HTML
  • 透明地处理延迟加载,在构建时生成多个包,并在运行时为您透明地加载包

问题是:所有这些(以及更多功能)都是可选的。其中许多需要插件(内置和第 3 方)和配置(例如,缩小到多远、将脚本注入到哪个 HTML 文件、在包中加载哪些文件、使用什么文件名格式等. 等等)。

您使用的 Webpack 功能越多,您的 Webpack 配置就越失控。

这就是 Angular CLI 发挥作用的地方。

它具有完美的默认设置,并包含许多功能。它封装了用于添加这些功能的整个配置。

其中一个特定于您的问题的功能是延迟加载

延迟加载

告诉 Webpack 延迟加载某些内容的方法是调用尚未被批准为标准的 API。它还允许使用比标准 EcmaScript 模块更类似于节点模块的其他方式。

Angular 路由器允许您跳过此语法,并使用 Angular 路由器特定的语法来延迟加载 Angular 模块(想想 @NgModule({}) 而不是 EcmaScript/Node 模块)。

例如,延迟加载 /admin 模块,假设它看起来像这样:

@NgModule({ 进口:[CommonModule, ...], 声明:[ ... ], 提供者:[ RouterModule.forChild([ {路径:'',组件:AdminComponent } ]), ... ], }) 导出类 AdminModule {}

您将AppModule 的路由更改为:

常量路线 = [ ..., { path: '/admin', loadChildren: () => AdminModule } ];

收件人:

常量路线 = [ ..., { 路径:'/admin',loadChildren:'./admin/admin.module#AdminModule' } ];

然后您将离开 Angular 路由器、Angular CLI 和 Webpack 来发挥作用。

只是不要让您的import { AdminModule } from './admin/admin.module'; 行保持原状,因为即使不使用AdminModule,这也会将模块加载到主应用程序包中。因为如前所述,摇树是一个静态过程,仅适用于 EcmaScript 导入分析。

附加。

Angular CLI 将--routing 参数添加到ng generate moduleng new 命令,这些命令会添加新文件,例如admin-routing.module.tsapp-routing.module.ts 文件,以将路由分隔到它们自己的文件中。这很好,而且也只是组织性的。

一个常见的错误是认为需要在AppRoutesModule 中引用AdminRoutesModule 文件,这是错误的。不同的模块和额外的文件没有任何区别。

示例

如果您想查看更多代码,我这里有一个简单的存储库可供查看:

https://github.com/meligy/routing-angular-cli

注意:

不幸的是,Angular CLI beta 24 中的延迟加载被破坏了。它被跟踪 here。我会看看我是否可以根据问题中建议的解决方案处理拉取请求。

【讨论】:

    猜你喜欢
    • 2018-09-13
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多