webpack4.29.x成神之路(二十) 編寫一個loader

目錄css

上節: css代碼分割html

目錄:node

clipboard.png

先改一下src/index.js:webpack

import _ from 'lodash';
const root = document.getElementById('root');
root.innerText = _.join(['hello', 'webpack'], '-');

如今寫一個簡單的loader,將全部的webpack替換成其它內容,內容可經過options配置。
在根目錄新建loaders/replace-loader.js。web

loaders/replace-loader.js:npm

const { getOptions } = require('loader-utils');
module.exports = function(source) {
  /* 
    this指向webpack
    source:打包後的文件內容
    this.query options參數
  */
 const options = getOptions(this) || {};

 // 返回處理後的結果,至關因而打包攔截器
 return source.replace('webpack', options.name || 'Madao');
}

source是打包後生成的文件,options能夠拿到配置參數,這個loader會將全部webpack替換成options.name的內容,若是沒指定options.name, 就替換成Madao.segmentfault

而後引用這個loader, 修改webpack/webpack.base.js:api

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { resolve } = require('path');
module.exports = {
  entry: './src/index.js',
  output: {
    path: resolve(__dirname, '../bundles')
  },

  // 註冊loader
  resolveLoader: {
    // loader查找順序,從左到右
    modules: ['node_modules', './loaders/']
  },

  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      
      // 先不傳options
      use: ['replace-loader', 'babel-loader']
    }, {
      test: /\.(gif|jpg|jpeg|png|svg)$/,
      use: ['url-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html'
    })
  ]
};

安裝loader工具庫:npm i loader-utils -D
而後npm run build, 打開bundles下的main.[contenthash].js文件,應該能夠搜索到Madao:babel

clipboard.png

而後咱們本身傳一個配置參數,修改webpack/webpack.base.js:異步

// 省略
module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      use: [{
        loader: 'replace-loader',
        options: {
          name: '史珍香'
        }
      }, 'babel-loader']
    }, {
      test: /\.(gif|jpg|jpeg|png|svg)$/,
      use: ['url-loader']
    }]
  },
// 省略

再次npm run build,能夠看到webpack就換成了'史珍香':

clipboard.png

一個簡單的loader就實現了。如今這個replace-loader只返回了替換後的內容,若是還想返回點其它內容,就得再改寫下。
loaders/replace-loader.js:

const { getOptions } = require('loader-utils');
module.exports = function(source) {
  /* 
    this指向webpack
    source:打包後的文件內容
    this.query options參數
  */
 const options = getOptions(this) || {};

 // 返回處理後的結果,至關因而打包攔截器
//  return source.replace('webpack', options.name || 'Madao');
 const result = source.replace('webpack', options.name || 'Madao');

 /* 
 this.callback(
  err: Error | null,  // error信息
  content: string | Buffer,   // 要返回的內容
  sourceMap?: SourceMap,    // source-map
  meta?: any  // 會被 webpack 忽略,能夠是任何東西(例如一些元數據)。
);
 */
// 若是隻傳這兩個參數,效果同上
  this.callback(null, result);
}

若是轉換過程當中有什麼異步操做,還能夠返回異步loader,這裏用定時器模擬下異步
loaders/replace-loader.js:

module.exports = function(source) {
  const callback = this.async();
  setTimeout(() => {  // 直接影響打包時間
    const options = getOptions(this);
    const result = source.replace('webpack', options.name || 'Madao');
    callback(null, result); // 這裏實際仍是調用了this.callback()
  }, 3000);
}

this對象上還掛了不少屬性,具體參考:https://webpack.js.org/api/lo...

下節:編寫一個plugin

相關文章
相關標籤/搜索