webpack 管理脚本
(./dist)存放分发代码,(./src)放源代码。源代码是指用于书写和编辑的代码。分发代码是指在构建过程中,经过最小化和优化后产生的输出结果,最终将在浏览器中加载。调整后目录结构如下:
webpack-demo
|- package.json
+ |- /dist
+ |- index.html
- |- index.html
|- /src
|- index.js
打包到生产环境 bundle 中时,你应该使用 npm install --save。如果你在安装一个用于开发环境的 package 时(例如,linter, 测试库等),你应该使用 npm install --save-dev
webpack 能够利用这些信息去构建依赖图,然后使用图生成一个优化过的 bundle,并且会以正确顺序执行
使用一个配置文件
webpack.config.js高效
npm scripts
可以通过在 npm run build 命令与参数之间添加两个连接符的方式向 webpack 传递自定义参数,例如:npm run build -- --color。
管理资源
webpack 这样的工具,将动态打包所有依赖(创建所谓的 依赖图(dependency graph))。这是极好的创举,因为现在每个模块都可以明确表述它自身的依赖,可以避免打包未使用的模块。
webpack 最出色的功能之一就是,除了引入 JavaScript,还可以通过 loader 或内置的 Asset Modules 引入任何其他类型的文件。
加载 CSS
模块 loader 可以链式调用。链中的每个 loader 都将对资源进行转换。链会逆序执行。最后,webpack 期望链中的最后的 loader 返回 JavaScript。
应保证 loader 的先后顺序:'style-loader' 在前,而 'css-loader' 在后。
管理输出
开发环境
使用 source map
JavaScript 提供了 source maps 功能,可以将编译后的代码映射回原始源代码。
使用 webpack-dev-server
webpack-dev-server 为你提供了一个基本的 web server,并且具有 live reloading(实时重新加载) 功能。
webpack-dev-server 是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。如果你的页面希望在其他不同路径中找到 bundle 文件,则可以通过 dev server 配置中的 devMiddleware.publicPath 选项进行修改。
代码分离
- 入口起点:使用
entry配置手动地分离代码。 - 防止重复:使用 Entry dependencies 或者
SplitChunksPlugin去重和分离 chunk。 - 动态导入:通过模块的内联函数调用来分离代码
隐患 入口起点 如果入口 chunk 之间包含一些重复的模块,那些重复模块都会被引入到各个 bundle 中
可以在 webpack 中允许每个页面使用多入口,应尽可能避免使用多入口的入口:entry: { page: ['./analytics', './app'] }。如此,在使用 async 脚本标签时,会有更好的优化以及一致的执行顺序。
SplitChunksPlugin
SplitChunksPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。
mini-css-extract-plugin: 用于将 CSS 从主应用程序中分离。
动态导入
import() 调用会在内部用到 promises
import _ from 'lodash';
-
-function component() {
+function getComponent() {
const element = document.createElement('div');
- // Lodash, now imported by this script
- element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ return import('lodash')
+ .then(({ default: _ }) => {
+ const element = document.createElement('div');
+
+ element.innerHTML = _.join(['Hello', 'webpack'], ' ');
- return element;
+ return element;
+ })
+ .catch((error) => 'An error occurred while loading the component');
}
-document.body.appendChild(component());
+getComponent().then((component) => {
+ document.body.appendChild(component);
+});
我们之所以需要 default,是因为 webpack 4 在导入 CommonJS 模块时,将不再解析为 module.exports 的值,而是为 CommonJS 模块创建一个 artificial namespace 对象
缓存
将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法
因此通过实现以上步骤,利用 client 的长效缓存机制,命中缓存来消除请求,并减少向 server 获取资源,同时还能保证 client 代码和 server 代码版本一致。
构建性能
将 loader 应用于最少数量 通过使用 include 字段,仅将 loader 应用在实际需要将其转换的模块:
dll
使用 DllPlugin 为更改不频繁的代码生成单独的编译结果。这可以提高应用程序的编译速度,尽管它增加了构建过程的复杂度。
worker 池(worker pool)
thread-loader 可以将非常消耗资源的 loader 分流给一个 worker pool