webpack5 自定义loader 自定义plugin

83 阅读2分钟

wepack5 项目初始化

创建一个webpack项目

  1. 创建项目
mkdir webpack-demo
cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev

//执行
npx webpack
  1. 创建文件与内容
    • ·/src/index.js
import './index.css';

function component() {
  const element = document.createElement('div');
  element.className = "root";
  element.innerHTML = 'Hello webpack';

  return element;
}

document.body.appendChild(component());
  • ./src/index.css
* {
  padding: 0;
  margin: 0;
}

.root {
   position: relative;
   width: 750px;
   height: 750px;
   background-color: antiquewhite;
}
  • ./dist/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>webpackLoaderPlugin</title>
  </head>
  <body>
    <script src="main.js"></script>
  </body>
</html>
  • package.json 修改
-  "main": "index.js",
+  "private": true,

  "scripts": {
+    "build": "webpack"
   },
  • webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

webpack loader 自定义loader

loader的基本介绍

loader是对源代码进行转换,预处理源代码内容。loader本质是一个函数,参数是上一个loader的内容或者模块的源代码。

自定义loader的方式

  1. 同步loader
function loader(source, sourceMap, meta){
  return targetCode;
  // 或者
  return this.callBack(null, code, sourceMap, meta);
}
  1. 异步loader
function loader(source, sourceMap, meta){
  const callBack = this.async();
  setTimeout(()=>{
    callBack(null, targetCode, sourceMap, meta)
  }, 2000);
}
  1. raw loader

webpack默认读取资源是字符串的形式,如果需要获取Buffer内容,需要配置loader的raw属性loader.raw = true;

function loader(source, sourceMap, meta){
  return targetCode;
}
loader.raw = true;
module.exports = loader;

编写自己的pxtorem-loader

  1. 创建文件 loaders/pxtorem-loader.js 实现px转rem loade功能
const Px2rem = require('./js/px2rem');
function loader(source) {
  // 获取配置的参数remUnit, remPrecision
  let options = this.getOptions();
  const px2rem = new Px2rem(options);
  // 转换px->rem
  const targetSource = px2rem.generateRem(source);
  return targetSource;
}
module.exports = loader;
  1. 修改webpack.config.js
resolveLoader:{
  alias: {
    'pxtorem-loader': path.resolve(__dirname, '../loaders/pxtorem-loader.js')
  }
}

……………………
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: 'pxtorem-loader',
            options: {
              remUnit: 75,
              remPrecision: 6
            }
          }
        ]
      }
    ]
  }

  1. 转换px->rem ./js/px2rem
const css = require('css'); // css字符串转换ast,ast在转为css代码
const pxRegExp = /\b(\d+(\.\d+)?)px\b/; // px字符串的正则匹配

class Px2rem{
  constructor(config){
    this.options = config;
  }
  generateRem(cssText){
    let self = this;

    …………

    const targetSource = css.stringify(astObj)
    return targetSource;
  }
  // 转换type单位的值,保留小数点位数
  _getCalcValue(type, value) {
    const { remUnit = 75, remPrecision = 6 } = this.options;
    return value.replace(pxRegExp, (_, $1) => {
      let val = (parseFloat($1) / remUnit).toFixed(remPrecision);
      return val + type;
    })
  }
}

module.exports = Px2rem;
  1. 安装 loader-utils 库。用来获取loader配置的参数。 webpack5 就不用了。
npm install loader-utils -D

const loaderUtils = require('loader-utils');
let options = loaderUtils.getOptions(this);

//webpack5 直接使用 
let options = this.getOptions();

  1. 入口文件,加上修改根字号大小的功能
function setRootFontSize() {
  var screenWidth = window.innerWidth;
  // 根据屏幕宽度计算并设置根元素的字体大小
  var rootFontSize = screenWidth / 10; // 例如,每100个像素为1rem,可以根据需要进行调整
  document.documentElement.style.fontSize = rootFontSize + 'px';
}
// 在窗口大小改变时调用设置根元素字体大小的函数
window.addEventListener('resize', setRootFontSize);
// 页面加载完成后初始化设置根元素字体大小
window.addEventListener('DOMContentLoaded', setRootFontSize);

webpack plugin 自定义插件的开发

webpack 插件,必须满足的条件。1.插件必须是一个函数或者是一个包含apply方法的对象。2.插件必须包含一个apply方法,用来注册当webpack构建流程中的特定事件钩子。3.插件要调用 complier API 来影响打包结果。

自定义插件

  1. ./plugins/demo-plugin.js
class DemoPlugin {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) {
    compiler.hooks.emit.tapAsync('DemoPlugin', (compilation,cb) => {
      // 在生成文件之前执行某些操作
      console.log('DemoPlugin is working');
      cb();
    });
  }
}
module.exports = DemoPlugin;
  1. webpack.config.js
const DemoPlugin = require('./plugins/demo-plugin');
module.exports = {
  // ...其他配置项
  plugins: [
    new DemoPlugin({ options: 'demo' })
  ]
};

实现一个(.js)文件,去注释的插件

class AnnotationWebpackPlugin {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) { //处理函数
    // emit 钩子,在生成文件之前执行某些操作
    compiler.hooks.emit.tap('AnnotationWebpackPlugin', compilation => {
      for (const name in compilation.assets) {
        // .js 结尾的文件
        if(name.endsWith('.js')){
          // 读取文件内容
          const contents = compilation.assets[name].source();
          // 去除多行注释 多行 单行
          const withoutComments = contents.replace(/\/\*[^\/]*\*\/|\/\/.+\n?/g, '').replace(/\/\/.+\n?/g, '');
          
          compilation.assets[name] = {
            source: () => withoutComments,
            size: () => withoutComments.length
          }
        }
      }
    });
  }
}

module.exports = AnnotationWebpackPlugin;

源码下载:https://gitee.com/leolee18/webpack-loader-pugin