webpack原理分析(loader, plugin)(上)

简介: webpack原理分析(loader, plugin)

loader原理


loader 概念


帮助 webpack 将不同类型的文件转换为 webpack 可识别的模块。


loader 执行顺序


了解执行顺序之前,需要先了解loader的分类


  • pre: 前置 loader


  • normal: 普通 loader


  • inline: 内联 loader


  • post: 后置 loader 执行顺序


  • 4 类 loader 的执行优级为:pre > normal > inline > post


  • 相同优先级的 loader 执行顺序为:从右到左,从下到上


// 此时loader执行顺序:loader3 - loader2 - loader1
    module: {
      rules: [
        {
          test: /\.js$/,
          loader: "loader1",
        },
        {
          test: /\.js$/,
          loader: "loader2",
        },
        {
          test: /\.js$/,
          loader: "loader3",
        },
      ],
    }


// 此时loader执行顺序:loader1 - loader2 - loader3
    module: {
      rules: [
        {
          enforce: "pre",
          test: /.js$/,
          loader: "loader1",
        },
        {
          // 没有enforce就是normal
          test: /.js$/,
          loader: "loader2",
        },
        {
          enforce: "post",
          test: /.js$/,
          loader: "loader3",
        },
      ],
    }


使用 loader 的方式


  • 配置方式:在 webpack.config.js 文件中指定 loader。(pre、normal、post loader)


  • 内联方式:在每个 import 语句中显式指定 loader。(inline loader)


inline loader


用法:import Styles from 'style-loader!css-loader?modules!./styles.css';


含义:


  • 使用 css-loaderstyle-loader 处理 styles.css 文件


  • 通过 ! 将资源中的 loader 分开


inline loader 可以通过添加不同前缀,跳过其他类型 loader。


  • ! 跳过 normal loader。


import Styles from '!style-loader!css-loader?modules!./styles.css';


  • -! 跳过 pre 和 normal loader。


import Styles from '-!style-loader!css-loader?

modules!./styles.css';


  • !! 跳过 pre、 normal 和 post loader。


import Styles from '!!style-loader!css-loader?modules!./styles.css';


编写loader


loader其实就是一个函数,接收下面三个参数


  • content 源文件的内容


  • map SourceMap 数据


  • meta 数据,可以是任何内容 最后返回处理后的内容。


loader 分类


  • 同步 loader


module.exports = function (content, map, meta) {
      // 传递map,让source-map不中断
      // 传递meta,让下一个loader接收到其他参数
      this.callback(null, content, map, meta);
      return; // 当调用 callback() 函数时,总是返回 undefined
    };


  • 异步loader注意:异步操作只能放在异步的callback调用


module.exports = function (content, map, meta) {
      const callback = this.async();
      // 异步操作只能放在异步的callback调用
      setTimeout(() => {
        callback(null, content, map, meta);
      }, 1000);
    };


  • Raw loader此时的content是一个Buffer数据,所以处理图片,音频,视频等文件时,需要使用这个。


module.exports = function (content) {
      // content是一个Buffer数据
      return content;
    };
    module.exports.raw = true; // 开启 Raw Loader


  • Pitching loader


module.exports = function (content) {
      return content;
    };
    module.exports.pitch = function (remainingRequest, precedingRequest, data) {
      console.log("do somethings");
    };


webpack 会先从左到右执行 loader 链中的每个 loader 上的 pitch 方法(如果有),然后再从右到左执行 loader 链中的每个 loader 上的普通 loader 方法


网络异常,图片无法展示
|


在这个过程中如果任何 pitch 有返回值,则 loader 链被阻断。webpack 会跳过后面所有的的 pitch 和 loader,直接进入上一个 loader 。


网络异常,图片无法展示
|


// webpack.config.js
    const path = require('path');
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    module.exports = {
      entry: "./src/main.js",
      output: {
        path: path.resolve(__dirname, "dist"),
        filename: "js/[name].js",
        clean: true
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            use: [
              "./loaders/loader04-pitching.js",
              "./loaders/loader05-pitching.js",
            ]
          }
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "./public/index.html")
        })
      ],
      mode: "development"
    }


网络异常,图片无法展示
|


类似于koa中间件的执行顺序,洋葱模型。


loader API


方法名 含义 用法
this.async 异步回调 loader。返回 this.callback const callback = this.async()
this.callback 可以同步或者异步调用的并返回多个结果的函数 this.callback(err, content, sourceMap?, meta?)
this.getOptions(schema) 获取 loader 的 options this.getOptions(schema)
this.emitFile 产生(输出)一个文件 this.emitFile(name, content, sourceMap)
this.utils.contextify 返回一个相对路径 this.utils.contextify(context, request)
this.utils.absolutify 返回一个绝对路径 this.utils.absolutify(context, request)


更多loader api请查看webpack官网


一些loader的练习


clean-log-loader


通过正则匹配console.log()的内容,将其替换成空字符串。一些正则符号,请参考这里


module.exports = function (content) {
      // ? 表示非贪婪模式
      return content.replace(/console\.log\(.*\);?/g, "");
    }


add-message-loader


添加一些创建者的信息。


// loader.js
    module.exports = function(content) {
      const options = this.getOptions(); // 获取loader中传递的options
      const bannerText = `
        /**
         * 
         * author: ${options.author}
         * time: ${options.time}
         * */
      `
      return bannerText + content;
    }


上面的代码中,我们可以再使用loader时,传递任意值。如果想要限制,那么我们就必须给getOptions中传入一个JSON格式的约束。


{
      "type": "object",
      "properties": {
        "author": {
          "type": "string"
        }
      },
      "additionalProperties": false
    }


所以改变loader


const schema = require("./schema.json");
    module.exports = function (content) {
      // 获取loader的options,同时对options内容进行校验
      // schema是options的校验规则(符合 JSON schema 规则)
      const options = this.getOptions(schema);
      const prefix = `
        /*
        * Author: ${options.author} || "zh"
        */
      `;
      return `${prefix} \n ${content}`;
    };


上面这个loader中的options只能写author属性,并且类型只能是字符串类型,否则打包会报错。


babel-loader


编译 js 代码,将 ES6+语法编译成 ES5-语法。babel-core的工作


安装依赖


npm i @babel/core @babel/preset-env -D


编写loader


const babel = require("@babel/core");
    const schema = require("./schame.json")
    module.exports = function(content) {
      const options = this.getOptions(schema);
      const callback = this.async();
      babel.transform(content, options, function(err, result) {
        if(err) {
          callback(err)
        }else { // => { code, map, ast }
          callback(null, result.code)
        };     
      });
    }


schema.json


{
      "type": "object",
      "properties": {
        "presets": {
          "type": "array"
        }
      },
      "additionalProperties": true
    }


file-loader


作用:将文件原封不动输出出去


npm i loader-utils -D


具体请访问这里编写loader


const loaderUtils = require("loader-utils");
    module.exports = function (content) {
      // 1. 根据文件内容生成带hash值文件名
      let interpolatedName = loaderUtils.interpolateName(this, "[hash].[ext][query]", {
        content,
      });
      interpolatedName = `images/${interpolatedName}`
      // console.log(interpolatedName);
      // 2. 将文件输出出去
      this.emitFile(interpolatedName, content);
      // 3. 返回:module.exports = "文件路径(文件名)"
      return `module.exports = "${interpolatedName}"`;
    };
    // 需要处理图片、字体等文件。它们都是buffer数据
    // 需要使用raw loader才能处理
    module.exports.raw = true;


配置loader


{
    test: /\.(png|jpe?g|gif)$/,
    loader: "./loaders/file-loader/index.js",
    type: "javascript/auto", // 阻止webpack默认处理图片资源,只使用file-loader处理
  }


相关文章
|
24天前
|
测试技术 开发者
如何确保 Webpack plugin 与其他插件的兼容性?
【10月更文挑战第23天】确保 Webpack plugin 与其他插件的兼容性需要从多个方面进行考虑和努力。通过遵循规范、进行充分测试、保持沟通协作等方式,
|
24天前
|
算法 测试技术 开发者
编写 Webpack plugin 时需要注意什么?
【10月更文挑战第23天】 编写 Webpack plugin 需要综合考虑多个方面的因素。只有在充分理解和掌握这些要点的基础上,才能编写出高质量、可靠且实用的 Plugin,为 Webpack 构建过程带来更多的价值和便利。
|
24天前
|
搜索推荐 测试技术 开发者
写一个 webpack plugin
【10月更文挑战第23天】编写一个 Webpack plugin 需要对 Webpack 的工作原理和机制有深入的了解,同时需要具备良好的编程能力和逻辑思维。通过合理设计和实现,Plugin 可以为我们的 Webpack 构建过程带来更多的灵活性和个性化。
|
24天前
|
监控 前端开发 JavaScript
Webpack 中 HMR 插件的工作原理
【10月更文挑战第23天】可以进一步深入探讨 HMR 工作原理的具体细节、不同场景下的应用案例,以及与其他相关技术的结合应用等方面的内容。通过全面、系统地了解 HMR 插件的工作原理,能够更好地利用这一功能,为项目的成功开发提供有力保障。同时,要不断关注技术的发展动态,以便及时掌握最新的 HMR 技术和最佳实践。
|
24天前
|
缓存 前端开发 JavaScript
Webpack 动态加载的原理
【10月更文挑战第23天】Webpack 动态加载通过巧妙的机制和策略,实现了模块的按需加载和高效运行,提升了应用程序的性能和用户体验。同时,它也为前端开发提供了更大的灵活性和可扩展性,适应了不断变化的业务需求和技术发展。
|
24天前
|
缓存 前端开发 JavaScript
webpack 原理
【10月更文挑战第23天】Webpack 原理是一个复杂但又非常重要的体系。它通过模块解析、依赖管理、加载器和插件的协作,实现了对各种模块的高效打包和处理,为现代前端项目的开发和部署提供了强大的支持。同时,通过代码分割、按需加载、热模块替换等功能,提升了应用程序的性能和用户体验。随着前端技术的不断发展,Webpack 也在不断演进和完善,以适应不断变化的需求和挑战。
|
1月前
|
前端开发 UED
Webpack 中处理 CSS 和图片资源的多 Loader 配置
【10月更文挑战第12天】 处理 CSS 和图片资源是 Webpack 配置中的重要部分。通过合理选择和配置多个 Loader,可以实现对这些资源的精细处理和优化,提升项目的性能和用户体验。在实际应用中,需要不断探索和实践,根据项目的具体情况进行灵活调整和优化,以达到最佳的处理效果。通过对 Webpack 中多 Loader 处理 CSS 和图片资源的深入了解和掌握,你将能够更好地应对各种复杂的资源处理需求,为项目的成功构建和运行提供坚实的基础。
56 1
|
1月前
|
前端开发 JavaScript
Webpack 中多个 Loader 的配置
【10月更文挑战第12天】使用多个 Loader 进行配置是 Webpack 中常见的操作,可以实现对各种资源的精细处理和优化。在配置时,需要根据具体需求合理选择和排列 Loader,并注意它们之间的顺序和交互关系。同时,不断了解和掌握新的 Loader 以及它们的特性,有助于更好地发挥 Webpack 的强大功能,提升项目的开发效率和质量。通过深入理解和熟练运用多个 Loader 的配置方法,你将能够更加灵活地处理各种资源,满足项目的多样化需求。
49 2
|
1月前
|
前端开发 JavaScript
Webpack 常用 Loader 和 Plugin
【10月更文挑战第12天】Webpack 是一个强大的模块打包工具,能够将各种资源模块进行打包和处理。Loader 用于转换模块的源代码,如 `babel-loader` 将 ES6+ 代码转换为 ES5,`css-loader` 处理 CSS 文件等。Plugin 扩展 Webpack 功能,如 `HtmlWebpackPlugin` 自动生成 HTML 文件,`UglifyJsPlugin` 压缩 JavaScript 代码。通过合理配置和使用 Loader 和 Plugin,可以构建高效、优化的项目。
23 2
|
2月前
|
JavaScript
webpack打包TS
webpack打包TS
133 60
下一篇
无影云桌面