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

yizhihongxing

深入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日

相关文章

  • 关于varchar2的最大长度

    关于varchar2的最大长度 VARCHAR2是Oracle数据库中的一种数据类型,用于存储可变长度的字符串。在使用VARCHAR2时,注意其最大长度限制。本文将详细介绍VARCHAR2的最大长度限制及其使用方法,并提供两个示例说明。 最大长度限制 在Oracle数据库中,VARCHAR2的最大长度为4000个字节。这个限制是由数据库块大小和字符集决定的。…

    other 2023年5月7日
    00
  • Win11 KB5027305发布:Beta版本升至 22621.1835/22631.1835

    Win11 KB5027305发布:Beta版本升至 22621.1835/22631.1835攻略 Win11 KB5027305是Windows 11操作系统的一个重要更新,它将Beta版本升级至22621.1835/22631.1835。本攻略将详细介绍如何完成这个升级过程。 步骤一:检查更新 首先,确保你的计算机已连接到互联网。然后按照以下步骤检查更…

    other 2023年8月3日
    00
  • 魔兽世界3.13(WOW 3.1.3)最新网易客户端 下载

    以下是详细讲解“魔兽世界3.13(WOW 3.1.3)最新网易客户端 下载”的完整攻略: 1. 下载网易客户端 在官方网站上下载网易客户端,网址为 https://dl.w.163.com/163/dl/client/wow/1.0.0/NeteaseWoW.dmg。 打开下载完成的 dmg 文件,并将客户端程序拖放到 Applications 文件夹中。 …

    other 2023年6月25日
    00
  • Wind10如何开启纯命令行模式?

    开启Wind10纯命令行模式的步骤如下: 步骤一:打开“运行”窗口 按下Win + R键组合,打开“运行”窗口。 步骤二:输入命令 在“运行”窗口中输入“cmd”命令,然后按下回车键即可。此时,Wind10将会在命令行模式下启动。 示例一 在命令行模式下,可以使用ping命令测试互联网连接。例如,输入以下命令: ping www.baidu.com 其中,w…

    other 2023年6月26日
    00
  • DOS命令行下常见的错误信息

    以下是关于DOS命令行下常见的错误信息的完整攻略。 什么是DOS命令行下的错误信息 DOS命令行是一个命令行操作系统,在执行指令时,如果遇到错误,系统会返回相应的错误信息。这些错误信息可以帮助用户理解问题的来源,以便更好地解决问题。 常见的DOS错误信息 错误码和说明 下面是一些常见的DOS错误信息,以及它们的含义: The system cannot fi…

    other 2023年6月26日
    00
  • 讲解vue-router之什么是嵌套路由

    讲解vue-router之什么是嵌套路由 在Vue.js中,Vue Router是一个官方的路由管理器,用于实现单页面应用程序(SPA)的导航功能。嵌套路由是Vue Router提供的一种功能,它允许我们在一个路由下定义子路由,从而实现更复杂的页面结构和导航。 嵌套路由的概念 嵌套路由是指在一个父级路由下定义子级路由的一种方式。父级路由可以包含多个子级路由,…

    other 2023年7月27日
    00
  • Python二进制数据结构Struct的具体使用

    Python二进制数据结构Struct的具体使用 什么是Struct Struct是Python标准库中提供的一个二进制数据结构处理模块,可以使用它来实现二进制流数据的打包与解包。通过Struct,我们可以快速且方便地处理各种二进制数据格式,例如进行网络传输的数据包、读写二进制文件等。在Python中使用Struct可以显著提高二进制数据处理的效率。 Str…

    other 2023年6月27日
    00
  • 电脑打开文件夹后资源管理器自动关闭该怎么办?

    问题描述: 有些电脑会出现这样的问题:打开一个文件夹后,突然发现资源管理器窗口自动关闭了,这种情况下我们该怎么办呢? 解决方案: 当我们遇到资源管理器自动关闭的情况时,可以通过以下几个步骤来解决: 检查是否存在病毒或者恶意软件 首先我们需要排除系统病毒或者恶意软件的可能性。我们可以通过杀毒软件进行全盘扫描,也可以通过检查系统启动项和进程,卸载最近安装的可疑应…

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