開發一個webapck v3 的 loader

CodeLittlePrince發表於2018-01-23

Github地址

github.com/CodeLittleP…

前言

有時候,市面上的webpack loader並不完全符合我們的需求,所以,我們不得不自己從0開始寫一個,或者是在別人寫的loader基礎之上進行修改。

無論哪種,都需要我們對webpack載入loader的方式有所瞭解。

說點題外話,不知道為什麼webpack官網對loader的介紹那麼簡短,很難單單根據文件就寫出loader來。所以還建議看些別人寫的loader,如babel-loader等。 好了,開始吧!

實現

出招吧~

在github上建立專案

開發一個webapck v3 的 loader

建立本地專案

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。 是不是有點兒小興奮? 開發一個webapck v3 的 loader

寫點有意義的功能

雖然說是教程,但是這樣的小例子的確有點太過簡單了,我們可以做點有意義點的功能。 比如,我們想把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。 看下效果: 開發一個webapck v3 的 loader 沒問題,進入下一步~

正式修改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哦

相關文章