webpack Loader
什么是 Loader
在webacpk 中万物皆模块,loader本质上是一个node模块,该模块导出了一个处理函数。在处理函数中输入我们的源模块、输出通用模块。借助loader我们不仅仅可以处理js类型的文件,其他任何类型的文件都可以被处理。loader 运行在nodejs 环境中,可以做任何在nodejs 中可以做的事情十分强大。
Loader 的基本配置
一般情况下我们可以通过webpack配置文件中的module.rules字段来loa配置loaders,常见的配置如下。
- 常用写法
module.exports = {
// ...
module: {
rules: [
// 单loader
{
test: /\.js$/,
use: ['babel-loader']
}
// 多loader
{
test: /\.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: module: true
},
'less-loader'
]
}
]
}
}
- 兼容写法
module.exports = {
// ...
module: {
rules: [
// 相当于 use: [{loader: 'babel-loader'}]
{
test: /\.js$/,
loader: 'babel-loader'
}
{
test: /\.less$/,
loader: 'style-loader!css-loader?module!less-loader'
}
/// loaders 等于 use
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
}
]
}
}
本地开发一个loader
- 创建最基本的loader,在根目录创建loaders文件夹,创建a-loader.js.
// source 为处理文件的内容 默认是字符串格式
const loader = function(source){
// 什么也不处理直接返回
return source
}
module.exports = loader
- 加载本地loader
module.exports = {
// 添加loaders 目录作为查找loader的默认目录
resolveLoader: {
modules: ['node_modules', 'loaders']
},
module: {
rules: [
{
test: /\.js$/,
use: [{loader: 'a-loader'}]
}
]
}
}
loader 的执行顺序
- loader 是链式的处理原则,每个loader 处理一种单一功能,上一个loader的返回值将会作为下一个loader的入参。
- loader 默认顺序: 从右往左, 从下到上。
a-loader.js
const loader = function(source){
console.log('a-loader')
return source
}
module.exports = loader
b-loader.js
const loader = function(source){
console.log('b-loader')
return source
}
module.exports = loader
c-loader.js
const loader = function(source){
console.log('c-loader')
return source
}
module.exports = loader
webpack.connfig.js
use多个loader 将会从右往左执行
module.exports = {
// ...
module: {
rules: [{
test: /\.js$/,
// 控制台 输出: c-loader b-loader a-loader
use: ['a-loader', 'b-loader', 'c-loader']
}]
}
}
webpack.config.js
匹配多个rule 将会从下至上执行
// 控制台输出 c-loader b-loader a-loader
module.exports = {
// ...
module: {
rules: [{
test: /\.js$/,
use: ['a-loader']
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader']
}]
}
}
- loader 类型顺序:
- loader的类型有4种: 普通loader、前置loader、后置loader、行内loader,默认类型为普通loader。
- 在rule 中设置enforce: ''pre" (前置loader)、“post”(后置loader)
- 行内loader是在代码中引入模块的时候的一种写法如:import ‘inline-loader!./test.js’
- 执行顺序为 pre -> normal -> inline -> post
inline-loader
const loader = function(source){
console.log('inline-loader')
return source
}
module.exports = loader
// 控制台输出:
// a-loader
// b-loader
// inline-loader
// c-loader
module.exports = {
entry: 'inline-loader!./src/app.js',
module: {
rules: [{
test: /\.js$/,
use: ['a-loader'],
enforce: 'pre'
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader'],
enforce: 'post'
}]
}
}
```js
- inline-loader 添加前缀可以不走某些loader
! 不走normal
-! 不走 pre 和 normal
!! 不走其他所有
不走 normal
// 控制台输出:
// a-loader
// inline-loader
// c-loader
module.exports = {
entry: '!inline-loader!./src/app.js',
module: {
rules: [{
test: /\.js$/,
use: ['a-loader'],
enforce: 'pre'
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader'],
enforce: 'post'
}]
}
}
不走 pre 和 normal
// 控制台输出:
// inline-loader
// c-loader
module.exports = {
entry: '-!inline-loader!./src/app.js',
module: {
rules: [{
test: /\.js$/,
use: ['a-loader'],
enforce: 'pre'
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader'],
enforce: 'post'
}]
}
}
不走其他所有
// 控制台输出:
// inline-loader
module.exports = {
entry: '!!inline-loader!./src/app.js',
module: {
rules: [{
test: /\.js$/,
use: ['a-loader'],
enforce: 'pre'
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader'],
enforce: 'post'
}]
}
}
- loader.pitch 顺序
- loader还可以附带一个pitch函数
- 在执行loader 之前会默认先执行pitch 函数
- pitch 函数的执行顺序是和 loader 相反的。
a-loader.js
let loader = function(source){
console.log(source)
return source
}
loader.pitch = function(){
console.log('a-pitch')
}
module.exports = loader
b-loader.js
let loader = function(source){
console.log(source)
return source
}
loader.pitch = function(){
console.log('b-pitch')
}
module.exports = loader
c-loader.js
let loader = function(source){
console.log(source)
return source
}
loader.pitch = function(){
console.log('c-pitch')
}
module.exports = loader
webpack.config.js
// 控制台输出
// a-pitch
// b-pitch
// c-pitch
// c-loader
// b-loader
// a-loader
module.exports = {
// ...
modules: {
rules: [{
test: /\.js$/,
use: ['a-loader'],
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader'],
}]
}
}
- 如果pitch 有返回值, 那么后面的pitch和本身对应的loader将不会执行,从下一个loader开始执行
b-loader.js
let loader = function(source){
console.log(source)
return source
}
loader.pitch = function(){
console.log('b-pitch')
return ''
}
module.exports = loader
webpack.config.js
// 控制台输出
// a-pitch
// b-pitch
// a-loader
module.exports = {
// ...
modules: {
rules: [{
test: /\.js$/,
use: ['a-loader'],
},{
test: /\.js$/,
use: ['b-loader']
}{
test: /\.js$/,
use: ['c-loader'],
}]
}
}
loader 执行图
实现简单的babel-loader
- 调用babel/core 模块对代码进行转化
2)配置source-map
3)为source-map 设置name
实现简单的file-loader url-loader
- file-loader 打包图片导出路径
2)url-loader 实现图片base64 编码格式
实现简单的less-loader css-loader style-loader
- less-loader 调用less 库转化代码为css代码
- css-loader 对css 中对图片路基进行处理
- style-loader 创建style标签 将css 插入到head标签中
实现简单的banner-loader
1)在js 代码中添加头部注释
2)监听依赖文件变化进行打包
常用写法
- 常用工具库 loader-utils、schema-utils
- 异步返回 this.async
- 处理文件 loader.raw = true
- this.resourcePath 文件绝对路径
- 更多用法参考 https://webpack.js.org/api/loaders/