这是一个读书笔记,原书: 深入浅出 Webpack
每天读一点,持续更新
1. 构建的工作:
- 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。
- 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
- 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
- 模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
- 自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器。
- 代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
- 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统
webpack
是一个打包模块化的js工具,从入口文件出发,识别出源码中的模块导入语句,递归的寻找出入口文件的所有依赖,把入口和其所有的依赖打包到一个导读的文件中。
-
Loader
Loader 可以看作具有文件转换功能的翻译员。配置里的 module.rules 数组配置了一组规则,告诉 Webpack 在遇到哪些文件时使用哪些 Loader 去加载和转换。
-
Plugin
Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现。
有了以上三个基本功能之后,我们在开发时还需要
- 提供 HTTP 服务而不是使用本地文件预览
- 监听文件的变化并自动刷新网页,做到实时预览
- 支持 Source Map,以方便调试
-
DevServer
DevServer 会启动一个 HTTP 服务器用于服务网页请求,同时会帮助启动 Webpack ,并接收 Webpack 发出的文件更变信号,通过 WebSocket 协议自动刷新网页做到实时预览。
DevServer 会把 Webpack 构建出的文件保存在内存中,在要访问输出的文件时,必须通过 HTTP 服务访问。DevServer 不会理会 webpack.config.js
里配置的 output.path
属性。
-
实时预览
通过 DevServer 启动的 Webpack 会开启监听模式,当发生变化时重新执行完构建后通知 DevServer。
DevServer 会让 Webpack 在构建出的 JavaScript 代码里注入一个代理客户端用于控制网页,网页和 DevServer 之间通过 WebSocket 协议通信, 以方便 DevServer 主动向客户端发送命令。 DevServer 在收到来自 Webpack 的文件变化通知时通过注入的客户端控制网页刷新。
-
模块热替换
模块热替换能做到在不重新加载整个网页的情况下,通过将被更新过的模块替换老的模块,再重新执行一次来实现实时预览。具体做法就是在使用devserver的时候加上--hot
参数。
-
Source Map
在浏览器中运行的 JavaScript 代码都是编译器输出的代码,这些代码的可读性很差。调试工具可以通过 Source Map 映射代码,让你在源代码上断点调试。具体做法,在启动devserver时带上--devtool source-map
参数。
![](https://img.haomeiwen.com/i4238751/290d0a05613be4f6.png)
-
核心概念
- Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
- Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
- Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。(一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk)
- Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
- Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
- Output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。
Webpack 启动后会从 Entry 里配置的 Module 开始递归解析 Entry 依赖的所有 Module。 每找到一个 Module, 就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前 Module 依赖的 Module。 这些模块会以 Entry 为单位进行分组,一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk。最后 Webpack 会把所有 Chunk 转换成文件输出。 在整个流程中 Webpack 会在恰当的时机执行 Plugin 里定义的逻辑。
2. 配置
Entry: 配置模块的入口;
Output: 配置如何输出最终想要的代码;
Module: 配置处理模块的规则;
Resolve: 配置寻找模块的规则;
Plugins: 配置扩展插件;
DevServer: 配置 DevServer;
其它零散的配置项....
-
entry
context
: 寻找相对路径的文件时会以 context
为根目录
Entry 类型: string, array, object
Chunk 名称: 如果 entry 是一个 string 或 array,就只会生成一个 Chunk,这时 Chunk 的名称是 main;
如果 entry 是一个 object,就可能会出现多个 Chunk,这时 Chunk 的名称是 object 键值对里键的名称。
-
output
filename: 配置输出文件的名称,为string 类型
chunkFilename: 配置无入口的 Chunk 在输出时的文件名称
entry:{
main:__dirname + '/app/main.js',
index:__dirname + '/app/index.js'
},
output:{
path:__dirname + '/public', //通过HtmlWebpackPlugin插件生成的html文件存放在这个目录下面
filename:'/js/[name].js', //编译生成的js文件存放到根目录下面的js目录下面,如果js目录不存在则自动创建
/*
* chunkFilename用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块则不会生成任何chunk块文件
* 比如在main.js文件中,require.ensure([],function(require){alert(11);}),这样不会打包块文件
* 只有这样才会打包生成块文件require.ensure([],function(require){alert(11);require('./greeter')})
* 或者这样require.ensure(['./greeter'],function(require){alert(11);})
* chunk的hash值只有在require.ensure中引入的模块发生变化,hash值才会改变
* 注意:对于不是在ensure方法中引入的模块,此属性不会生效,只能用CommonsChunkPlugin插件来提取
* */
chunkFilename:'js/[chunkhash:8].chunk.js'
},
path
:配置输出文件存放在本地的目录
publicPath
: 配置发布到线上资源的 URL 前缀
crossOriginLoading
: Webpack 输出的部分代码块可能需要异步加载,而异步加载是通过 JSONP 方式实现的。 JSONP 的原理是动态地向 HTML 中插入一个 <script src="url"></script>
标签去加载异步资源。用于配置这个异步插入的标签的crossorigin
值(script 标签的 crossorigin 属性可以取以下值:anonymous(默认) 在加载此脚本资源时不会带上用户的 Cookies;use-credentials 在加载此脚本资源时会带上用户的 Cookies。)
libraryTarget 和 library:当用 Webpack 去构建一个可以被其他模块导入使用的库时需要用到它们, libraryTarget配置以何种方式导出库,library配置导出库的名称。
libraryTarget
:配置以何种方式导出库(var, commonjs, commonjs2, this, window, global)
libraryExport
:配置要导出的模块中哪些子模块需要被导出
-
Module(配置如何处理模块)
loader
:
rules 配置模块的读取和解析规则,通常用来配置 Loader。
rules大致通过以下方式
![](https://img.haomeiwen.com/i4238751/8bf2276db598be2b.png)
noParse
: 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析和处理parser
: 可以更细粒度的配置哪些模块语法要解析哪些不解析
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
parser: {
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES6 import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用 browserify
requireJs: false, // 禁用 requirejs
}
},
]
}
-
Resolve(配置 Webpack 如何寻找模块所对应的文件)
alias
:配置项通过别名来把原导入路径映射成一个新的导入路径
mainFields
:先记录一下package.json
中的main
字段定义了我们程序的主要入口,程序会从main
字段中找到我们程序的主要入口,从而输出我们的代码依赖。main
字段用来指向commonjs的模块。jsnext:main
与 module
的作用是一样的, 但是由于module
更直白一点,所以现在使用module
. 在这里我们讨论module
。module
字段会指向一个ES2015 模块的入口, 当使用rollup这些模块的bundler时,由于使用了ES2015 的模块,可以再做tree shaking优化(tree shaking是什么后面再说)。browser
指定该模板供浏览器使用的版本
Webpack 会根据 mainFields
的配置去决定优先采用那份代码。
mainFields: ['browser', 'main'] //默认配置
Webpack 会按照数组里的顺序去package.json 文件里寻找,只会使用找到的第一个。
extensions
:在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在
modules
:配置 Webpack 去哪些目录下寻找第三方模块
enforceExtension
:如果配置为 true 所有导入语句都必须要带文件后缀
enforceModuleExtension
:enforceModuleExtension 和 enforceExtension 作用类似,但 enforceModuleExtension 只对 node_modules 下的模块生效
网友评论