首页 > 其他分享 >webpack简介及自定义插件

webpack简介及自定义插件

时间:2022-11-15 17:46:39浏览次数:85  
标签:插件 自定义 钩子 compilation loader webpack compiler

  webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。想要写一个webpack的自定义插件,需要先了解webpack的一些基础配置,详细内容可以在 webpack官网 学习。

 

  • 入口(entry)

   entry是指入口文件的配置项,当入口只有一个时,可以简写为:

 module.exports = {
   entry: './src/main.js',
 };

   webpack还支持多个入口的情况,此时需要用数组的形式或者对象的形式给entry赋值,如:

  entry: {
    app: './src/app.js',
    main: './src/main.js',
  }

   相对于简写语法,对象语法比较繁琐,但是可扩展行更高,例如用于分离应用程序和第三方库入口,或者是多页面应用程序入口配置。

 

  • 输出(output)

   输出的配置需要根据入口的配置来变换,最简单的写法是只指定output的filepath属性,这样会默认将该文件输出到项目根目录下的dist目录中,如果webpack打包后会输出文件不少于一个,还需要用占位符,例如[name],[hash]等,确保输出的文件都具有唯一名字。除此之外,还可以利用output.path指定打包后的输出路径等等。

output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].js",
  },

 

  • loader

   loader是用于对代码模块进行转换,webpack本身只支持打包js和json类型的文件,但是我们的项目中肯定不止用到这两种类型文件,例如还有css,html已经ts等等,此时就需要利用loader对这些代码进行转换。一份代码可能需要多个loader才能被转换,例如转换less样式代码:

{
    test: /\.less$/,
    /**
    * use可以使用多个loader,从下往上或者从右往左执行
    */
    use: [
      {
        loader: MiniCssExtractPlugin.loader, // creates link tag
      },
      {
        loader: "css-loader", // translates CSS into CommonJS
      },
      {
        loader: "less-loader", // compiles Less to CSS
      },
    ],
 },

  常用的一些loader:

  1. style-loader:用于将编译好后的css样式以style标签的形式插入到html文件中

  2. css-loader: 用于处理css文件,需要搭配style-loader或者MiniCssExtractPlugin使用

  3. less-loader:用于处理less样式文件,需要跟css-loader搭配使用

  4. postcss-loader:自动添加浏览器前缀,解决样式浏览器兼容问题

  5. babel-loader:使用babel处理js代码

  6. ts-loader:用于处理ts文件,需要配置tsconfig.json文件

  7. url-loader:可以将文件大小小于设置的limit值的文件转成base64编码,减少请求次数,提升页面加载速度

 

  • plugins

  接下来进入到我们的主题,插件部分,在 webpack官网插件部分 的介绍中,插件是webpack的支柱功能,插件的目的是为了解决loader解决不了的问题,由此可见,插件的功能是十分强大的,如果要使用webpack插件,需要在webpack配置中的plugins传入一个new示例,因为可以使用多个插件,对应plugins是一个数组,每添加一个插件,就需要在plugins中新增一个new示例,每个插件传递的参数由使用情况决定,例如:

plugins: [
    new MyPlugin(/Test(1|2)/, /(t|j|cs)s$/), //自定义插件
    new MiniCssExtractPlugin(), //将打包后的css文件以link标签的方式导入
    new HtmlWebpackPlugin({   //根据传入的模板,生成一个html文件
      filename: "index.html",
      template: "./src/index.html",
    }),
],

 

  当我们在webpack打包的过程中想要实现某些操作时,如果已经存在的插件不能满足我们的需求,就需要自己开发自定义插件

 

  • 自定义插件

   webpack插件可以是一个javascript命名函数或者一个javascript类,在类中需要实现一个apply方法,该方法的参数是compiler对象。compiler是webpack的主要引擎,它通过 CLI 或者 Node API 传递的所有选项创建出一个 compilation 实例。 它扩展(extends)自 Tapable 类,用来注册和调用插件。 大多数面向用户的插件会首先在 Compiler 上注册。compiler包含很多钩子函数,在调用钩子函数时,可以通过如下方式访问:

compiler.hooks.someHook.tap('MyPlugin', (params) => {
  /* ... */
});

  someHook表示自己要使用的钩子函数,除tap方法外,还可以使用tapAsync方法和tapPromise方法,当使用tapAsync方法绑定插件时,就可以在钩子的回调函数中使用异步方法,但是必须在最后调用该钩子的回调函数的参数中指定的回调函数,否则会导致webpack不能继续执行,当然也有同步的钩子不支持tapAsync。在调用tapPromise,需要返回一个Promise,在异步调用完成后resolve。compiler有很多的钩子函数,如果想要知道每个钩子的具体调用位置,需要在webpack的源码中,通过搜索 hooks.<hook name>.call,查找具体使用位置。在complier的某些钩子函数的参数中,可以获取到compilation对象,Compilation 模块会被 Compiler 用来创建新的 compilation 对象(或新的 build 对象)。 compilation 实例能够访问所有的模块和它们的依赖(大部分是循环依赖)。 它会对应用程序的依赖图中所有模块, 进行字面上的编译(literal compilation)。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore),compliation和compiler用法相同,某些钩子函数也可以使用tapAsync和tapPromise方法。

  • 插件实例

const fs = require("fs")

class MyPlugin {
  //构造函数,auchor代表锚点,type表示需要匹配的文件类型的数组
  constructor(auchor, type) {
    this.auchor = auchor
    this.type = type
  }

  apply(compiler) {
    let resultArr = []
    compiler.hooks.compilation.tap("MyPlugin", (compilation) => {
      compilation.hooks.finishModules.tap("MyPlugin", (modules) => {
        modules.forEach((module) => {
          if (
            module.resource &&
            !module.resource.includes("node_modules") &&
            module.resource.split(".")[1]?.match(this.type)
          ) {
            console.log(module.resource)
            const result = matchAnchor(module.resource, this.auchor)
            // 对数组进行拼接;
            resultArr = resultArr.concat(result)
          }
        })
      })
    })
    compiler.hooks.emit.tap("Myplugin", (compilation) => {
      //将匹配到的数据输出到webpack的输出目录中
      compilation.assets["matchResult.json"] = {
        source() {
          return JSON.stringify(resultArr)
        },
        size() {
          return resultArr.length
        },
      }
    })
  }
}
//匹配函数,返回封装好的对象数组
function matchAnchor(path, anchor) {
  //匹配出的结果数组,默认为空
  const result = []
  // 读取文件内容
  const data = fs.readFileSync(path, "utf-8").toString()
  // 分行
  const lines = data.split("\n")
  lines.forEach((line, index) => {
    //将匹配条件转化成正则
    const reg = new RegExp(anchor)
    const matchArr = reg.exec(line)
    if (matchArr) {
      result.push({
        filepath: path.replaceAll("\\", "/"), // 匹配到的文件路径
        line: index + 1, // 匹配到的行号
        match: matchArr[0], // 匹配到的字符串
      })
    }
  })
  return result
}

module.exports = MyPlugin

  该插件由一个js类和一个匹配函数组成,需求是找出指定文件类型中的某些字符串,需要在调用的时候传递两个参数,在类的构造函数中初始化。之后在apply方法中,实现我们想要的效果。这里用到了compiler的两个钩子函数,第一个是compilation钩子。compilation在编译创建之后执行,这是一个同步 SyncHook 钩子,通过回调函数中的compilation的finishModules钩子,可以访问到webpack构建的依赖树。之后通过module.resource,可以拿到每个模块的依赖文件的路径,之后通过文件读写操作就可以查找想要的字符串。第二个compiler钩子函数时emit,emit在输出 asset 到 output 目录之前执行,这个钩子 不会 被复制到子编译器。在该钩子函数中,通过compilation.assets,将查询到的结果一并输出到dist文件夹中。最后就是需要在webpack的配置中导入该插件,并在plugins中new一个该类的实例,而apply方法会在new该实例时自动被调用。

标签:插件,自定义,钩子,compilation,loader,webpack,compiler
From: https://www.cnblogs.com/zhoushaowen/p/16891808.html

相关文章

  • vue自定义事件的基本使用
    因为新项目要写114个字段,所以今天试着封装了一个dialog表单组件在优化关闭和提交按钮的时候,可以在父组件写事件,这时候自定义事件就能登场了我先是这么操作了一番父组件:......
  • Flume 自定义拦截器
    ApacheFlume是一个分布式的、可靠和易用的日志收集系统,用于将大量日志数据从许多不同的源进行收集、聚合,最终移动到一个集中的数据中心进行存储。Flume的使用不仅仅限于......
  • 项目中滑块验证插件使用
    源码地址:github文档地址:https://github.com/monoplasty/vue-monoplasty-slide-verifygitee镜像地址:https://gitee.com/monoplasty/vue-monoplasty-slide-verify效果图......
  • uniapp 实现小程序中自定义tabBar
    uniapp实现小程序中自定义tabBar的方法第一种方式:page.json中配置"tabBar":{"color":"#7A7E83","selectedColor":"#007AFF","borderStyle":"black",......
  • leaflet 加载高德地图自定义样式
    最近项目需求,需要使用leaflet封装成一个vue组件,涉及功能主要有高德自定义样式地图封装为leaflet底图图层、自定义坐标系、topjson省市区街道下钻、线面区域热力层、飞线、......
  • umi配置chainWebpack,使用自定义loader----jsx-px2rem
    前言虽然云谦大佬在github上说了,umi本身的配置已经很完善了,但是肯定满足不了所有人各种各样的奇葩需求。。。比如今天说的将jsx中的style里,将px转换为rem。 umi本身提......
  • ueditor导入word文档 ueditor word导入插件
    1.编辑器修改(可选)1.1在 ueditor/config.json 中添加代码块    /* 上传word配置 */    "wordActionName":"wordupload",/* 执行上传视频的action名称......
  • fluentd如何进行插件的安装和卸载?
    安装 通过如下的命令,安装特定版本的插件(-v指定具体要安装的版本) td-agent-geminstallelasticsearch-v6.1.0  安装之后,通过td-agent-gemlist命令进行......
  • java poi导出excel单元格设置自定义背景颜色(任意颜色)
    转自:http://t.csdn.cn/QHfUU//创建一个workbook对象Workbookworkbook=newXSSFWorkbook();//创建一个sheet对象Sheetsheet=workbook.createSheet();//创......
  • 如何查看fluentd中都安装了哪些的插件?
    通过下面的命令,轻松查看fluentd中已经安装了哪些插件及版本信息 td-agent-gemlist  示例: 括号内是插件的版本[root@centos7gems]#td-agent-gemlist|......