Github地址
前言
有時候,市面上的webpack loader並不完全符合我們的需求,所以,我們不得不自己從0開始寫一個,或者是在別人寫的loader基礎之上進行修改。
無論哪種,都需要我們對webpack載入loader的方式有所瞭解。
說點題外話,不知道為什麼webpack官網對loader的介紹那麼簡短,很難單單根據文件就寫出loader來。所以還建議看些別人寫的loader,如babel-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哦