loader
loader
是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中,处理一个文件可以使用多个loader
,loader
的执行顺序和配置中的顺序是相反的,即最后一个loader
最先执行,第一个loader
最后执行,第一个执行的loader
接收源文件内容作为参数,其它loader
接收前一个执行的loader
的返回值作为参数,最后执行的loader
会返回此模块的JavaScript
源码。
编写自己的loader
时需要引用官方提供的loader-utils
,调用loaderUtils.getOptions(this)
拿到webpack
的配置参数,然后进行自己的处理。
Loader
本身仅仅只是一个函数,接收模块代码的内容,然后返回代码内容转化后的结果,并且一个文件还可以链式的经过多个loader
转化(如 scss-loader => css-loader => style-loader
)。
一个Loader
的职责是单一的,只需要完成一种转化。如果一个源文件需要经历多步转化才能正常使用,就通过多个Loader
去转化。在调用多个Loader
去转化一个文件时,每个Loader
会链式的顺序执行,第一个Loader
将会拿到需要处理的原内容,上一个Loader
处理后的结果会传给下一个接着处理,最后的Loader
将处理后的最终结果返回给Webpack
。
一个最简单的Loader
例子:
module.exports = function(source) {
// source为compiler传递给loader的一个文件的原内容
// 该函数需要返回处理后的内容,这里为了简单示例,直接把原内容返回了,相当于该Loader没有做任何转换
return source
}
plugin
plugin
功能更强大,loader
不能做的都是它做。它的功能要更加丰富。从打包优化和压缩,到重新定义环境变量,功能强大到可以用来处理各种各样的任务。
plugin
让webpack
的机制更加灵活,它在编译过程中留下的一系列生命周期的钩子
,通过调用这些钩子来实现在不同编译结果时对源模块进行处理。它的编译是基于事件流来编译的,主要通过tapable
来实现插件的绑定和执行的,tapable
主要是基于发布订阅的插件架构,是用来创建生命周期钩子的库。调用compiler.hooks.run.tap
开始注册,创建compilation
,基于配置创建chunks
,在通过parser
解析chunks
,使用模块和依赖管理模块之间的依赖关系,最后使用template
基于compilation
数据生成结果代码。
plugin
的实现可以是一个类,使用时传入相关配置来创建一个实例,然后放到配置的plugins
字段中,而plugin
实例中最重要的方法是apply
,该方法在webpack compiler
安装插件时会被调用一次,apply
接收webpack compiler
对象实例的引用,你可以在compiler
对象实例上注册各种事件钩子函数,来影响webpack
的所有构件流程,以便完成更多其他的构建任务。
一个简单的plugin
例子:
class BasicPlugin{
// 在构造函数中获取用户给该插件传入的配置
constructor(options) {
}
// webpack 会调用 BasicPlugin 实例的 apply 方法给插件传入 compiler 对象
apply(compiler) {
compiler.plugin('compilation', function(compilation) {
})
}
}
// 导出 Plugin
module.exports = BasicPlugin
Webpack
启动后,在读取配置的过程中会先执行 new BasicPlugin(options)
初始化一个BasicPlugin
获得其实例。在初始化 compiler
对象后,再调用 basicPlugin.apply(compiler)
给插件实例传入compiler
对象。插件实例在获取到compiler
对象后,就可以通过compiler.plugin(事件名称,回调函数)
监听到webpack
广播出来的事件。并且可以通过compiler
对象去操作Webpack
。
开发Plugin
最主要的就是理解compiler
和compilation
,它们是plugin
和webpack
之间的桥梁。这两者提供的各种hooks
和api
,则是开发plugin
所必不可少的材料,通过compiler
和compilation
的生命周期hooks
,也可以更好的深入了解webpack
的整个构建工作是如何进行的。
常见的loader
和plugin
1. 常见loader
file-loader
: 文件加载url-loader
: 文件加载,可以设置阈值,小于时把文件base64
编码image-loader
: 加载并压缩图片json-loader
:webpack
默认已经包含了babel-loader
:ES6+
转成ES5
ts-loader
: 将ts
转成js
awesome-typescript-loader
: 比ts-loader
性能好一些 8.css-loader
:处理@import
和url
这样的外部资源style-loader
: 在head
创建style
标签把样式插入postcss-loader
: 扩展css
语法,使用postcss
各种插件autoprefixer,cssnext,cssnano
eslint-loader, tslint-loader
:通过这两种检查代码,tslint
不再维护vue-loader
: 加载vue
单文件组件i18n-loader
: 国际化cache-loader
:性能开销大的loader
前添加,将结果缓存到磁盘svg-inline-loader
:压缩后的svg
注入代码source-map-loader
: 加载source map
文件,方便调试expose-loader
: 暴露对象为全局变量 18.imports-loader、exports-loader
等可以想模块注入变量或者提供导出模块功能raw-loader
: 可以将文件以字符串的形式返回- 校验测试:
mocha-loader、jshint-loader、eslint-loader
等
2. 常见plugin
ignore-plugin
:忽略文件uglifyjs-webpack-plugin
: 不支持ES6
压缩(webpack4
以前使用)terser-webpack-plugin
:支持压缩ES6(webpack4)
webpack-arallel-uglify-plugin
: 多进程执行代码压缩,提升构建速度mini-css-extract-plugin
: 分离样式文件,css
提取为独立文件,支持按需加载serviceworker-webpack-plugin
: 为网页应用增加离线缓存功能clean-webpack-plugin
: 目录清理speed-measure-webpack-plugin
: 可以看到每个Loader
和Plugin
执行耗时webpack
内置UglifyJsPlugin
,压缩和混淆代码webpack
内置CommonsChunkPlugin
,提高打包效率,将第三方库和业务代码分开打包。ProviderPlugin
: 自动加载模块,代替require
和import
html-webpack-plugin
可以根据模板自动生成html
代码,并自动引用css
和js
文件extract-text-webpack-plugin
将js
文件中引用的样式单独抽离成css
文件DefinePlugin
编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用HotModuleReplacementPlugin
热更新DllPlugin
和DllReferencePlugin
相互配合,前者第三方包的构建,只构建业务代码,同事能解决Externals
多次引用问题。DllReferencePlugin
引用DllPlugin
配置生成的manifest.json
文件,manifest.json
包含了依赖模块和module id
的映射关系optimize-css-assets-webpack-plugin
不同组件中重复的css
可以快速去重webpack-bundle-analyzer
一个webpack
的bundle
文件分析工具,将bundle
文件可以交互缩放的treemap
的形式展示compression-webpack-plugin
生产环境可以采用gzip
压缩js
和css
happypack
: 通过多进程模式,来加速代码构建