webpack系列之编写一个loader

写在前面

webpackloader的应用是非常广泛的,完全离不开它,我们开发的过程往往都是使用别人编写好的loader来处理文件,今天我们就来编写一个loader

基础

首先我们看看loader是怎么使用在webpack上的

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
entry: '...',
module: {
rules: [
{
test: /\.css$/,
use: 'css-loader',
},
],
},
}

使用起来很简单,如果你需要处理css文件,那么安装好css-loader包,然后正则匹配到所有.css的文件,使用css-loader进行文件得处理

编写

编写之前我们先给定个需求吧,设想我们能不能像vue那样编写,处理style/script/template,这样,我们先只处理style的内容,把他提取处理。

安装

1
2
> npm init -y
> cnpm i webpack webpack-cli webpack-dev-server clean-webpack-plugin html-webpack-plugin -D

配置

先来编写一个配置文件

新建文件 webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'bundle.js',
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({ template: 'index.html' }),
],
module: {
rules: [
{
test: /\.css/,
use: path.resolve(__dirname, 'loader/loader.js'),
},
],
},
};

项目下新建src文件夹,src项目新建main.jsa.test文件

main.js

1
2
import './a.test';
console.log('loader test');

a.test

1
2
3
4
5
<style>
body{
background: #ccc
}
</style>

我们重点是a.test文件,等会我会用loader处理他,让他显示到页面中

———–分割线———–

现在我们在项目下新建loader文件夹,文件夹下面新建loader.js,这就是我们编写的loader

loader/loader.js

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = function(sSource) {
let sStyleString = sSource
.match(/<style>([\s\S]*)<\/style>/)[1]
.replace(/\n/g, '');
return `
let head = document.querySelector('head');
let style = document.createElement('style');
style.type = 'text/css';
let cssNode = document.createTextNode('${sStyleString}');
style.appendChild(cssNode);
head.appendChild(style);`;
};

没错,就这么多,loader接收一个参数,也就是sSource,内容就是.test后缀下的文件内容,我们只需要获取内容,然后做我们想做的一切事情,比如,我提取了文件里css的部分,像.vue那样,然后去写一段js,把这段css通过<style></style>的方式放到页面上去

现在你运行一下这个项目,然后查看浏览器,浏览器的背景是否变了颜色?

api

loader的上下文通过this访问,举几个例子

this.query

  1. 如果这个 loader 配置了 options 对象的话,this.query 就指向这个 option 对象
  2. 如果 loader 中没有 options,而是以 query 字符串作为参数调用时,this.query 就是一个以 ? 开头的字符串

this.context

模块所在的目录

this.emitFile

1
emitFile(name: string, content: Buffer|string, sourceMap: {...})

可以通过用它来生成一个文件

总结

写一个loader很简单,只需要你有对文件内容处理的能力,还是很容易上手的,关键不在loader,而在于你的需求复杂程度

本文地址 webpack系列之编写一个loader

坚持原创技术分享,您的支持将鼓励我继续创作!