深入webpack打包原理及loader和plugin的实现

深入webpack打包原理及loader和plugin的实现

一、Webpack的打包原理

Webpack 是一个现代化的 JavaScript 应用程序打包器。Webpack 会读取你的应用程序并构建一个依赖关系图,然后根据这个图创建一个打包文件。在打包的过程中,Webpack 的核心功能包括模块解析器、依赖关系解析器、代码生成器和打包器等。Webpack 的打包流程大体可以分为如下几个阶段:

  1. 初始化阶段:读取配置文件,创建Compiler对象,加载所有的插件,等等;

  2. 编译阶段:通过调用 Compiler 对象提供的 run 方法来进行编译,主要是如下几个过程:

  3. 根据 entry 和其依赖的模块,构建成 AST 树,然后经过转换器进行语法转换、附加前置、后置、中间模块等操作转换器;

  4. 根据不同类型的模块,对模块进行相应的处理(姑且称之为 load),例如: 解析模块依赖(package.json, CommonJS, ES6 等),处理样式文件、图片等文件引用等;

  5. 对模块进行封装,生成完成的 Chunk 对象;

  6. 输出阶段:对 Chunk 进行优化、压缩、最终的输出文件等操作。

下面我们重点关注在编译阶段中,webpack是如何对模块进行处理的。

二、Loader的实现

在Webpack中,Loader是一个文件转换器,它专门用于处理资源文件,将入口文件和依赖文件都作为参数传入。Webpack 会通过读取配置文件的module.rules属性,来决定用哪个Loader进行处理。其实现基本流程可以简述为:

  1. 读取配置文件,解析出module.rules下的所有正则表达式对象,并通过正则对象来匹配module下的模块文件;

  2. 根据匹配的Loader对文件进行相应的转换处理等操作;

  3. 返回转换好的内容。

有关 Loader 实现的两个示例:

1. 常用的文件转换

常用 Loader 中的一种是处理样式文件的 style-loader 和 css-loader,它们的作用是将 css 样式文件打包到 JavaScript 文件中,目的是为了提高浏览器的加载速度。

例如 css-loader 可以解析 CSS 文件,并将 CSS 文件转换成一个字符串,然后交给 style-loader 处理,style-loader 可以在 HTML 文件中插入一段 style 标签,然后将 CSS 字符串放入 style 标签中。

// css-loader.js
module.exports = function(source) {
  return JSON.stringify(source); // 将 css 转为字符串
}

// style-loader.js
module.exports = function(cssString) {
  const style = document.createElement('style');
  style.innerText = cssString; // 内联CSS
  document.head.appendChild(style); // 将style标签插入HTML
}

2. Babel转换器

常见的一个Loader是 Bable-loader,用于将 ES6 或更高的语法或其他语言转成浏览器支持的语法。

例如,将 ES6 代码转换成 ES5 代码:

// babel-loader.js
const babelCore = require('@babel/core');

module.exports = function(source) {
  const { code } = babelCore.transform(source, {
    presets: [
      ['@babel/preset-env', { targets: 'last 2 versions, >1%, not dead' }]
    ]
  });
  return code;
}

三、Plugin的实现

Plugin是可以影响Webpack的构建流程,并将在整个构建流程中“挂载”在Webpack的钩子上。Webpack的运行过程被定义为一个生命周期,而 Plugin 就是在 Webpack 生命周期中,将要被执行的代码。

常见的Plugin有:html-webpack-plugin插件可以在打包完成后,将打包生成的 js 自动引入到 html 页面中;clean-webpack-plugin插件可以在打包前自动清理输出目录;copy-webpack-plugin插件可以将需要转换成 ES5 代码的 js 文件从 dist 目录中COPY 到 dist/es5 目录中等等。

Plugin的实现基本流程可以简述为:

  1. 在Webpack生命周期中通过生命周期钩子来获得Webpack中要处理的‘资源’。

  2. 通过‘资源’创建新的‘资源’,并将这些‘资源’添加到Webpack构建流程中。

  3. 完成插件(Plugin)的生命周期

有关 Plugin 实现的两个示例:

1. html-webpack-plugin插件

样式通常会以 link 标签或者 style 标签的形式插入到 HTML 中。针对这点,我们可以实现一个插件,自动向 HTML 文件中添加 link 或 style 标签,这样在浏览器中访问时,就可以自动加载样式。

const HtmlWebpackPlugin = require('html-webpack-plugin');

class AutoInsertStylePlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('AutoInsertStylePlugin', (compliation, callback) => {
      const htmlFileName = 'index.html'; // 设置需要插入 link 或 style 标签的HTML 文件名
      let htmlFileContent = null;

      for (const asset of compliation.assets) {
        const [fileName, fileContent] = Object.entries(asset)[0];
        if (fileName === htmlFileName) {
          htmlFileContent = fileContent.source(); // 读取 HTML 的文件内容
          break;
        }
      }

      if (!htmlFileContent) {
        callback();
        return;
      }

      const styleContent = ''; // 通过某种方式获得样式内容

      const styles = `<style>${styleContent}</style>`;
      const updatedFileContent = htmlFileContent.replace(/<\/head>/, + styles + '</head>'); // 通过正则将新的样式内容添加到 HTML 中

      compliation.assets[htmlFileName] = {
        source: () => updatedFileContent,
        size: () => updatedFileContent.length
      }

      callback();
    });
  }
}

// 使用
module.exports = {
  plugins: [
    new HtmlWebpackPlugin(),
    new AutoInsertStylePlugin()
  ]
};

2. clean-webpack-plugin插件

const fs = require('fs');

class CleanWebpackPlugin {
  apply(compiler) {
    compiler.hooks.beforeRun.tapAsync('clean-webpack-plugin', (compiler, callback) => {
      try {
        fs.rmdirSync('./dist', { recursive: true }); // 递归删除 dist 目录以及其下的所有文件
      } catch (e) {
        console.error(`Error while deleting dist directory : ${e}`);
      }
      callback();
    });
  }
}

// 使用
module.exports = {
  plugins: [
    new CleanWebpackPlugin()
  ]
};

这个插件会在 Webpack 打包开始之前,将 dist 目录删除,防止不必要的文件增量构建,并在下一次构建开始时清空整个 dist 目录。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入webpack打包原理及loader和plugin的实现 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • vuejs中监听窗口关闭和窗口刷新事件的方法

    在Vuejs中监听窗口关闭和窗口刷新事件,需要用到window对象的“beforeunload”事件和Vue实例的生命周期钩子函数。下面是完整攻略: 1.使用window.onbeforeunload事件 我们可以在Vue实例的created生命周期钩子函数中监听window的beforeunload事件。beforeunload事件是在窗口即将关闭或刷新时…

    other 2023年6月27日
    00
  • 详解androidbitmap的常用压缩方式

    以下是“详解Android Bitmap的常用压缩方式”的完整攻略: 1. Android Bitmap的压缩概述 在Android开发中,Bitmap是一种常用的图像处理工具。由于图像通常比较大,因此在Android应用中使用Bitmap时,需要对其进行压缩,以减小内存占用和提高性能。Android提供了多种Bitmap压缩方式,本文将对其进行详细介绍。 …

    other 2023年5月8日
    00
  • PowerShell入门教程之函数、脚本、作用域介绍

    PowerShell入门教程之函数、脚本、作用域介绍 函数(Function) 函数是一段可重复使用的代码块,用于执行特定的任务。在PowerShell中,函数可以接受参数并返回值。以下是创建和使用函数的示例: # 定义一个函数 function SayHello { param( [string]$name ) Write-Host \"Hell…

    other 2023年8月19日
    00
  • readystatechange事件

    readyStateChange事件 什么是readyStateChange事件? 在使用 Ajax 技术进行网络通信时,我们经常需要使用XMLHttpRequest对象。在这个对象中,readyState表示 XMLHttpRequest 对象的状态。而readystatechange事件则是在这个状态发生变化时被触发。 具体来说,当readyState属…

    其他 2023年3月29日
    00
  • Ext2 文件系统的硬盘布局

    Ext2 文件系统的硬盘布局 Ext2(第二扩展文件系统)是一种用于Linux操作系统的文件系统。它定义了硬盘上数据的组织方式和存储结构。下面是Ext2文件系统的硬盘布局的详细说明: 引导扇区(Boot Sector) 硬盘的第一个扇区被称为引导扇区,它包含了引导加载程序(boot loader)的代码。引导加载程序负责加载操作系统并将控制权转交给它。在Ex…

    other 2023年9月5日
    00
  • 强大的Perl正则表达式实例详解

    强大的Perl正则表达式实例详解 正则表达式是一种强大的文本匹配工具,Perl语言中的正则表达式尤为强大。本攻略将详细讲解Perl正则表达式的使用方法,并提供两个示例说明。 1. 正则表达式基础 在Perl中,正则表达式通常用斜杠(/)包围,例如:/pattern/。正则表达式由模式和修饰符组成,模式用于描述要匹配的文本规则,修饰符用于指定匹配方式。 下面是…

    other 2023年8月3日
    00
  • Qt样式表的使用

    Qt样式表的使用 在Qt中,使用样式表可以自定义应用程序的外观,以此来展现自己的理念和风格。使用样式表可以非常方便地修改Qt应用程序的外观,实现更好的用户体验。 样式表语法 Qt的样式表采用了类似Css的语法,样式表主要分为三个部分: 选择器:选择需要修改样式的控件; 属性:需要修改控件的属性; 值:控件属性需要修改的目标值。 下面是一个简单的样式表示例: …

    其他 2023年3月28日
    00
  • java中hashmap容量的初始化实现

    Java中,HashMap是一种常见的哈希表数据结构,它可以在常数时间内完成元素的插入、查找和删除操作,因此在Java编程中被广泛使用。HashMap的内部实现是通过链表+数组实现的,每个元素被放到数组的某个位置上,如果当前位置的元素数量过多则会形成一个链表。 HashMap的初始化需要两个参数:初始容量(initialCapacity)和负载因子(load…

    other 2023年6月20日
    00
合作推广
合作推广
分享本页
返回顶部