十三、附录 B:使用 Webpack

Webpackhttps://webpack.github.io/ 是另一个在过去一年中广受欢迎的网络模块绑定器。Aurelia 已经为 ES next 和 Typescript 提供了使用 Webpack 的应用框架。

此外,还计划在 CLI 中添加对基于 Web 包的项目的支持。然而,目前,骨架是创建基于 Webpack 的 Aurelia 项目的最佳起点。

在本附录中,我们将看到在撰写本文时使用requirejs的基于 CLI 的项目与从框架开始的基于 Webpack 的项目之间的区别。

本附录的目的不是为了涵盖 Webpack 本身。因此,我强烈建议您在继续阅读之前,先熟悉一下 Webpack(如果您还没有熟悉的话)。

提示

我们的联系人管理应用是使用 Webpack 框架重建的,可以在本书资产的appendix-b\using-webpack中找到,并可作为本附录的参考。

开始

为了创建基于 Web 包的应用,第一步是从下载骨架 https://github.com/aurelia/skeleton-navigation/releases/latest 并解压缩文件。根文件夹包含每个可用骨架的不同目录。我们打算在这里保留的一个名为skeleton-esnext-webpack

Webpack 框架使用 NPM 作为其包管理器。因此,我们需要通过在项目目录中打开控制台并运行以下命令来安装项目的依赖项:

> npm install

完成后,示例应用就可以运行了。

正在运行的任务

Webpack 框架不使用 Gulp 作为其构建系统,而只是依赖于 NPM 任务。如果您查看package.json文件中的scripts部分,您将看到任务列表以及可以为项目运行的相应命令。以下是最常见的:

  • start:启动开发 web 服务器。第一次访问index.html时,应用被捆绑并提供服务,然后流程监视源文件,以便在检测到更改时可以重新创建捆绑包并刷新浏览器。start命令是server的别名,它本身就是server:dev的别名。
  • test:运行单元测试。使用伊斯坦布尔(启用代码覆盖率 https://github.com/gotwarlost/istanbul
  • e2e:运行端到端测试。此任务将启动将在端口 19876 上运行的应用和 E2E 测试套件。
  • build:prod:捆绑生产申请。捆绑包和index.html文件将针对生产进行优化,并将在dist文件夹中生成。此外,生产构建将在每个 bundle 的名称中添加一个基于内容的哈希,以便对其进行版本设置。这与在基于 CLI 的项目中通过在aurelia_project/aurelia.json中设置rev选项来启用捆绑修订具有相同的效果。
  • server:prod:启动一个 web 服务器来服务生产捆绑包。必须在build:prod之后运行。

添加库

外部库是使用 NPM 添加的,就像基于 CLI 的项目一样。但是,为了将文件包含在捆绑包中,必须在 JS 文件中引用外部库,因为 Webpack 通过分析应用中每个 JS 模块的import语句来确定捆绑包中必须包含的内容。

您可以通过检查骨架的main模块来查看此示例:

src/main.js

// we want font-awesome to load as soon as possible to show the fa-spinner 
import '../styles/styles.css'; 
import 'font-awesome/css/font-awesome.css'; 
import 'bootstrap/dist/css/bootstrap.css'; 
import 'bootstrap'; 
//Omitted snippet... 

在 skeleton 的示例应用中,所有全局资源(如应用的样式表、字体、Bootstrap 的样式表和 Bootstrap JS 文件)都导入到main.js文件中。这些导入将告诉 Webpack 在应用包中包含这些资源。此外,Webpack 足够智能,可以分析 CSS 文件的依赖关系。这意味着它知道如何处理导入的 CSS 文件、图像和字体文件。

捆扎

捆绑包本身在webpack.config.js文件中配置。默认情况下,骨架定义了三个条目捆绑包:

  • aurelia-bootstrap:包含 Aurelia 的引导程序、默认的 polyfills、Aurelia 的浏览器平台抽象和 Bluebird Promise 库
  • aurelia:包含 Aurelia 的所有默认库
  • app:包含所有应用模块

除了作为其直接内容列出的模块外,捆绑包还将包含其所有内容的依赖项,这些依赖项不包括在另一个捆绑包中。例如,在骨架的示例中,app捆绑包中包含引导 JS 文件,因为它不包含在任何其他捆绑包中,app捆绑包中包含的模块导入它。

例如,如果您希望aurelia包包含所有外部库,则应将bootstrap添加到其中包含的模块列表中:

webpack.config.js

//Omitted snippet... 
const coreBundles = { 
  bootstrap: [ 
    //Omitted snippet... 
  ], 
  aurelia: [ 
    //Omitted snippet... 
    'aurelia-templating-binding', 
    'aurelia-templating-router', 
    'aurelia-templating-resources', 
    'bootstrap' 
  ] 
} 
//Omitted snippet... 

如果此时运行示例应用,那么引导的 JS 文件现在应该包含在aurelia包中,而不是app包中。

延迟加载束

骨架的示例应用中定义的所有 bundle 都是条目 bundle,这意味着这些 bundle 直接由index.html文件加载。所有这些代码都是在应用启动之前预先加载的。

正如第 10 章生产捆绑中所述,根据应用的使用模式和结构,将应用的不同部分单独捆绑,并仅在需要时加载其中一些捆绑,可能会更好地提高性能。

惰性加载包的配置在package.json文件中完成:

{ 
  //Omitted snippet... 
  "aurelia": { 
 "build": { 
 "resources": [ 
 { 
 "bundle": "contacts", 
 "path": [ 
 "contacts/components/creation", 
 "contacts/components/details", 
 "contacts/components/edition", 
 "contacts/components/form", 
 "contacts/components/list", 
 "contacts/components/photo", 
 "contacts/models/address", 
 "contacts/models/contact", 
 "contacts/models/email-address", 
 "contacts/models/phone-number", 
 "contacts/models/social-profile", 
 "contacts/main" 
 ], 
 "lazy": true 
 } 
 ] 
 } 
 } 
  //Omitted snippet... 
} 

在本例中,我们将联系人管理应用的contacts功能中的所有组件和模型捆绑在一个不同的、延迟加载的捆绑包中。通过这种配置,只有当用户导航到联系人的某个路由组件时,才会从服务器加载contacts包。

至于包含依赖项,延迟加载的 bundle 的行为将类似于条目 bundle。除了配置中列出的模块外,延迟加载的捆绑包还将包含任何条目捆绑包中尚未包含的所有依赖项。这意味着,如果您import只在包含在给定捆绑包中的模块内(而不是应用中的其他模块内)从外部库中填充内容,并且如果您不将此外部库包含在其中一个条目捆绑包中,则该库将包含在延迟加载的捆绑包中。这是优化应用捆绑时要考虑的重要事项。

基于环境的配置

Webpack 骨架使用一个名为NODE_ENV的环境变量,以便根据上下文定制绑定过程。此环境变量通过package.json中描述的任务设置为developmenttestproduction

如果您查看webpack.config.js文件,您将看到一条switch语句,它根据环境生成一个 Webpack 配置对象。在这里,您可以根据环境自定义绑定。

例如,如果您使用aurelia-i18n插件,您可能希望在构建应用时将locales目录复制到dist目录。最简单的方法是将以下行添加到生产和开发配置中:

webpack.config.js

//Omitted snippet... 
config = generateConfig( 
  baseConfig, 
  //Omitted snippet... 
  require('@easy-webpack/config-copy-files') 
    ({patterns: [{ from: 'favicon.ico', to: 'favicon.ico' }]}),
  require('@easy-webpack/config-copy-files') 
 ({patterns: [{ from: 'locales', to: 'locales' }]}), 
  //Omitted snippet... 
); 
//Omitted snippet... 

此外,如果您想要使用aurelia-testing插件,或者在单元测试中使用 component tester,或者为了调试目的使用view-spycompile-spy属性,您应该使用 NPM 安装它,并将其添加到testdevelopment环境的aurelia包中:

webpack.config.js

//Omitted snippet... 
coreBundles.aurelia.push('aurelia-testing'); 
config = generateConfig( 
  baseConfig, 
  //Omitted snippet... 
); 
//Omitted snippet... 

首先,配置 Webpack 可能会很复杂,也很吓人。Webpack 骨架使用easy-webpackhttps://github.com/easy-webpack/core 简化此配置过程。使用easy-webpack的另一个巨大优势是它强制执行社区标准,并且使重用复杂的配置片段变得非常容易。

因此,您可以使用提供的许多配置模块中的一个 https://github.com/easy-webpack 或其他人,甚至您自己的,以进一步定制 Webpack 的配置。

总结

尽管它不是 Aurelia 的首选绑定器,但 Webpack 已经得到了很好的支持。此外,无论是使用 Webpack 还是 CLI 捆绑,Aurelia 应用本身并没有多大变化,主要是围绕这些变化的基础架构代码。这使得从一个 bundler 迁移到另一个 bundler 更加简单。