webpack的loader和plugin的区别
webpack 的常见配置
1 | const webpack = require("webpack"); |
webpack 的打包原理
- 识别入口文件
- 通过逐层识别模块依赖(Commonjs、amd 或者 es6 的 import,webpack 都会对其进行分析,来获取代码的依赖)
- webpack 做的就是分析代码,转换代码,编译代码,输出代码
- 最终形成打包后的代码
什么是 loader
loader 是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中
- 处理一个文件可以使用多个 loader,loader 的执行顺序和配置中的顺序是相反的,即最后一个 loader 最先执行,第一个 loader 最后执行
- 第一个执行的 loader 接收源文件内容作为参数,其它 loader 接收前一个执行的 loader 的返回值作为参数,最后执行的 loader 会返回此模块的 JavaScript 源码
loader 的使用方式
一般 loader 的使用方式分为三种:
在配置文件 webpack.config.js 中配置
1 | module.exports = { |
通过命令行参数方式
1 | webpack --module-bind 'txt=raw-loader' |
通过内联使用
1 | import txt from "raw-loader!./file.txt"; |
webpack 常用的 loader
作用 | loader |
---|---|
处理样式,转成 css | style-loader、css-loader、less-loader、sass-loader |
加载图片和字体等文件 | raw-loader、file-loader 、url-loader |
加载数据 xml 和 csv | csv-loader xml-loader |
编译 | babel-loader、coffee-loader 、ts-loader |
校验测试 | mocha-loader、jshint-loader 、eslint-loader |
读取 html 生成模板字符串 | html-loader |
将 js 模块暴露到全局 | expose-loader |
将第三方库注入到模块中 | import-loader |
css-loader、sass-loader 与 style-loader
- css-loader 处理其中的@import 和 url()。
- sass-loader 转化 sass 为 css 文件,并且包一层 module.exports 成为一个 js module。
- style-loader 将创建一个 style 标签将 css 文件嵌入到 html 中。
file-loader、url-loader 与 raw-loader
- file-loader 可以复制和放置资源位置,并可以指定文件名模板,用 hash 命名更好利用缓存。
- url-loader 可以将小于配置 limit 大小的文件转换成内敛 Data Url 的方式,减少请求。
- raw-loader 可以将文件以字符串的形式返回
什么是 plugin
在 webpack 运行的生命周期中会广播出许多事件,plugin 可以监听这些事件,在合适的时机通过 webpack 提供的 API 改变输出结果。
1 | class MyPlugin { |
使用该 plugin 后,执行的顺序:
- webpack 启动后,在读取配置的过程中会执行 new MyPlugin(options)初始化一个 MyPlugin 获取其实例
- 在初始化 compiler 对象后,就会通过 compiler.plugin(事件名称,回调函数)监听到 webpack 广播出来的事件
- 并且可以通过 compiler 对象去操作 webpack
webpack 常用的 plugin
Plugin | 作用 |
---|---|
UglifyJsPlugin | webpack 内置,压缩和混淆代码 |
optimize-css-assets-webpack-plugin | 不同组件中重复的 css 可以快速去重 |
CommonsChunkPlugin | webpack 内置,提高打包效率,将第三方库和业务代码分开打包,多个 html 共用一个 js 文件(chunk) |
ProvidePlugin | 自动加载模块,代替 require 和 import |
DefinePlugin | 编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用 |
NormalModuleReplacementPlugin | 匹配 resourceRegExp,替换为 newResource |
ContextReplacementPlugin | 替换上下文的插件 |
IgnorePlugin | 不打包匹配文件 |
ResolverPlugin | 替换上下文的插件 |
ContextReplacementPlugin | 替换上下文的插件 |
html-webpack-plugin | 可以根据模板自动生成 html 代码,并自动引用 css 和 js 文件 |
extract-text-webpack-plugin | 将 js 文件中引用的样式单独抽离成 css 文件,非内联 |
HotModuleReplacementPlugin | 热更新 |
Externals | 常用于引入外链作为 library |
DllPlugin、DllReferencePlugin | 前置第三方包的构建,只构建业务代码,同时能解决 Externals 多次引用问题 |
compression-webpack-plugin | 生产环境可采用 gzip 压缩 JS 和 CSS |
happypack | 通过多进程模型,来加速代码构建 |
PrefetchPlugin | 预加载的插件,提高性能 |
clean-webpack-plugin | 清理每次打包下没有使用的文件 |
webpack-bundle-analyzer | 一个 webpack 的 bundle 文件分析工具,将 bundle 文件以可交互缩放的 treemap 的形式展示 |
loader 和 plugin 的区别
Loader
Loader 直译为”加载器”。Webpack 将一切文件视为模块,但是 webpack 原生是只能解析 js 文件,如果想将其他文件也打包的话,就会用到 loader。 所以 Loader 的作用是让 webpack 拥有了加载和解析非 JavaScript 文件的能力。
对于 loader,它是一个转换器,将 A 文件进行编译形成 B 文件,这里操作的是文件,比如将 A.scss 转换为 A.css,单纯的文件转换过程
Plugin
Plugin 直译为”插件”。Plugin 可以扩展 webpack 的功能,让 webpack 具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
plugin 是一个扩展器,它丰富了 webpack 本身,针对是 loader 结束后,webpack 打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听 webpack 打包过程中的某些节点,执行广泛的任务
如何编写 loader 或 plugin
编写思路
- 编写 Loader 时要遵循单一原则,每个 Loader 只做一种”转义”工作, 每个 Loader 的拿到的是源文件内容(source),可以通过返回值的方式将处理后的内容输出,也可 以调用 this.callback()方法,将内容返回给 webpack,还可以通过 this.async()生成一个 callback 函数,再用这个 callback 将处理后的内容输出出去,此外 webpack 还为开发者准备了开发 loader 的工具函数集——
loader-utils
- 相对于 Loader 而言,Plugin 的编写就灵活了许多, webpack 在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 webpack 提供的 API 改变输出结果
编写注意事项
- Loader 支持链式调用,所以开发上需要严格遵循“单一职责”,每个 Loader 只负责自己需要负责的事情
- Loader 运行在 node.js 中,我们可以调用任意 node.js 自带的 API 或者安装 第三方模块进行调用
- webpack 传给 Loader 的原内容都是 UTF-8 格式编码的字符串,当某些场景下
Loader 处理二进制文件时,需要通过 exports.raw = true 告诉 webpack 该 Loader 是否需要
二进制数据 - 尽可能的异步化 Loader,如果计算量很小,同步也可以
- Loader 是无状态的,我们不应该在 Loader 中保留状态
- 使用 loader-utils 和 schema-utils 为我们提供的实用工具
- 加载本地 Loader 方法