原文
https://github.com/CodeLittlePrince/blog/issues/9
前言
有时候,市面上的webpack loader并不完全符合我们的需求,所以,我们不得不自己从0开始写一个,或者是在别人写的loader基础之上进行修改。
无论哪种,都需要我们对webpack加载loader的方式有所了解。
实现
出招吧~
在github上创建项目
创建本地项目
1、git clone项目到本地
2、初始化npm
npm init
填写完npm init的一路提示下来以后,我们看下文件结构:
.
├── README.md
└── package.json
3、安装webpack
npm i -D webpack
4、设置一下package.json里的scripts命令:
"scripts": {
"dev": "webpack"
},
这样的话,基本的工具就准备完毕了。
编写webpack.config.js
1、创建webpack.config.js
.
├── README.md
├── node_modules
├── package-lock.json
├── package.json
└── webpack.config.js
2、编辑webpack.config.js
const path = require('path')
module.exports = {
entry: {
app: path.resolve('demo/index.js')
},
output: {
path: path.resolve('dist'),
filename: 'index.js'
},
module: {
rules: [
{
test: /\.js$/,
loader: path.resolve('src/loader-test.js'),
options: {
speak: 'wang~',
}
}
]
}
}
因为我们是从0开始编写的,所以不得不先从简单到复杂。
所以,如上,我们通过path引用的方式来使用loader。并且,我们配置了option,作为参数。
index则是需要处理的文件。
编写index.js
const cat = 'kitty'
console.log(cat)
编写loader-test.js
// loader-utils作为工具类引入(作为webpack依赖,所以在安装webpack时候就带上了)
const loaderUtils = require('loader-utils')
// loader调用的时候,会将源数据和sourcemap作为参数传入函数
module.exports = function(source, inputSourceMap) {
const code = source
const map = inputSourceMap
// loaderUtils.getOptions 可以获取到设置loader时候设置的options
// 当然loaderUtils还有很多其他有用的方法,详情可以看 https://github.com/webpack/loader-utils
const loaderOptions = loaderUtils.getOptions(this) || {};
console.log(source)
console.log(loaderOptions)
// loader需要将自己的值传给下一个loader,并且,loader不免会有异步操作
// 因此需要回调来证明自己已经处理结束了
this.callback(null, code, map)
}
先看下目录结构,为了不影响视觉,我忽略了node_module文件:
.
├── README.md
├── demo
│ └── index.js
├── package-lock.json
├── package.json
├── src
│ └── loader-test.js
└── webpack.config.js
好,让我们运行一下webpack,看一下效果:npm run dev
...
const cat = 'kitty'
console.log(cat)
{ speak: 'wang~' }
...
正如我们写的loader,打印出了index.js的源码,以及,webpack.config.js配置loader时候的options。
是不是有点儿小兴奋?
写点有意义的功能
虽然说是教程,但是这样的小例子的确有点太过简单了,我们可以做点有意义点的功能。
比如,我们想把js中px全部替换成vw,比例就按照1vw = 10px
吧。
(我相信很多朋友会觉得为啥替换js,而不是css或者scss。因为,会涉及更多的webapck配置,比较无聊和对本章内容没什么作用,所以,我觉得还是越简单越好,就拿js举例子吧)
好,计划有了,开始行动吧!
重新编辑index.js
const parentStyle = `
background: #fdc;
width: 1200px;
height: 600px;
box-sizing: border-box;
padding: 150px 300px;
`
const childStyle = `
background: #cdf;
width: 600px;
height: 300px;
`
const parent = document.getElementById('parent')
const child = document.getElementById('child')
parent.style.cssText = parentStyle
child.style.cssText = childStyle
为了更好展示,我们再写个html吧
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {padding: 0; margin: 0;}
</style>
</head>
<body>
<div id="parent">
<div id="child"></div>
</div>
</body>
</html>
让启动demo更顺畅
一不做二不休,为了更顺畅的看效果,我们加个webpack-dev-server自动启动吧。同时,顺带着,将html-webpack-plugin和clean-webpack-plugin也都加上。
关于写demo,我觉得,是写npm modules必须要有的东西,如果没有demo,没有顺畅的启动demo操作。别说别人懒得看,自己都懒得启动了。
好,我们再看下现在的webpack配置:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
entry: {
app: path.resolve('demo/index.js')
},
output: {
path: path.resolve('dist'),
filename: 'index.js'
},
module: {
rules: [
{
test: /\.js$/,
loader: path.resolve('src/loader-test.js')
}
]
},
plugins: [
// 清理dist
new CleanWebpackPlugin('dist'),
// 将js打入html
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve('demo/index.html'),
chunks: ['app'] // 因为只有一个页面,这行不写也可以
})
]
}
修改下package.json里的scripts命令:
"scripts": {
"dev": "webpack-dev-server --open"
},
然后,启动实验一下,npm run dev
。
看下效果:
没问题,进入下一步~
正式修改loader
让我们重新编辑loader-test.js吧:
...
// 替换px
const regex = /(\d+?)px/g
code = code.replace(regex, function(match, p1) {
return p1/10 + 'vw'
})
...
}
然后,再重新启动一下,我们会发现,px都被替换成了vw了,而且比例为1vw = 10px,成功!
当然,有同学肯定会想到,要是这个比例可以自己设置那就更好了。实现方式当然也很简单啊,还记得我们之前是怎么获取loader中options配置的speak吗?我相信同学完全可以独立完成了。
怎么把包做成npm module,然后发到npm 上,以后都能用呢?
这个的话,其实是我之前已经写过这样的文章了,同学们可以转到npm-从0开始写一个npm module
本文项目地址
最后,希望喜欢的同学能给star哦
说点题外话,不知道为什么webpack官网对loader的介绍那么简短,很难单单根据文档就写出loader来。所以还建议看些别人写的loader,如babel-loader等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。