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

相关文章

  • 苹果正式发布iOS 12.4.5 正式版 固件版本号为16G161(附更新方法)

    以下是关于“苹果正式发布 iOS 12.4.5 正式版,固件版本号为 16G161”的完整攻略,包含了两个示例说明。 更新方法 要更新到 iOS 12.4.5 正式版,可以按照以下步骤进行: 确保你的设备已连接到互联网。 打开设备的设置应用程序。 滚动并点击“通用”。 点击“软件更新”。 如果有可用的更新,点击“下载并安装”。 输入设备的密码(如果需要)。 …

    other 2023年8月2日
    00
  • Bootstrap每天必学之下拉菜单

    Bootstrap每天必学之下拉菜单攻略 1. 简介 下拉菜单是网页开发中常用的交互组件之一,Bootstrap提供了简单而强大的下拉菜单功能,可以轻松实现各种样式和布局需求。本攻略将详细介绍如何使用Bootstrap创建下拉菜单。 2. 准备工作 在使用Bootstrap之前,确保你已经引入了Bootstrap的CSS和JavaScript文件。你可以使用…

    other 2023年6月28日
    00
  • pgpool复制和负载均衡操作

    以下是对pgpool复制和负载均衡操作的完整攻略: 安装和配置pgpool 首先,安装pgpool软件包。具体的安装方法可以根据您的操作系统和包管理器进行调整。 在pgpool的配置文件中,设置数据库连接信息和复制模式。例如,您可以指定主数据库和从数据库的连接信息,并选择复制模式为stream模式。 配置pgpool的负载均衡策略。您可以设置负载均衡器如何将…

    other 2023年10月18日
    00
  • python中print()函数不换行的方法

    Python中print()函数不换行的方法 在Python中,print()函数是一个常用的输出函数。默认情况下,每次调用print()函数都会自动在输出内容的最后加上一个换行符,使得不同的输出内容分隔开来,排版更加美观。但有时候,我们需要输出一些不同行的内容,这时就需要禁止print()函数自动换行。那么,Python中如何实现不换行输出呢? 方法一:使…

    其他 2023年3月28日
    00
  • ubuntu上安装mono

    以下是在Ubuntu上安装Mono的完整攻略,包括以下步骤: 添加Mono的软件源 更新软件包列表 安装Mono 示例说明 步骤一:添加Mono的软件源 要在Ubuntu上安装Mono,需要先添加Mono的软件源。以下是添加Mono的软件源的步骤: 打开终端 运行以下命令,以添加Mono的软件源: sudo apt-key adv –keyserver h…

    other 2023年5月9日
    00
  • PHP编码规范的深入探讨

    PHP编码规范的深入探讨 1. 为什么需要编码规范? 编码规范是一组约定俗成的规则,用于统一团队成员的编码风格和代码结构。它的存在有以下几个重要原因: 可读性和可维护性:编码规范可以提高代码的可读性,使代码更易于理解和维护。统一的代码风格可以减少团队成员之间的理解障碍,提高协作效率。 代码质量:编码规范可以规范代码的结构和命名,减少潜在的bug和错误。良好的…

    other 2023年8月8日
    00
  • linux如何部署nginx

    Linux如何部署nginx 在Linux服务器上部署nginx可以快速搭建一个高性能的web服务器,本文将介绍如何在Linux上安装和配置nginx。 步骤一:安装nginx 使用命令行工具登录到Linux服务器; 安装nginx,命令如下: sudo apt update sudo apt install nginx 等待安装完成,安装成功后启动ngin…

    其他 2023年3月28日
    00
  • 3D渲染管线

    3D渲染管线的完整攻略 本文将为您提供3D渲染管线的完整攻略,包括渲染管线的概念、渲染管线的阶段、渲染管线的优化和两个示例说明。 渲染管线的概念 3D渲染管线是指将3D场景中的几何图形转换为2D图像的过程。渲染管线通常由多个阶段组成,每个阶段都有特定的功能。渲染管线的目的是将3D场景中的几何图形转换为2D图像,以便在屏幕上显示。 渲染管线的阶段 以下是渲染管…

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