【webpack】自定义loader

这篇具有很好参考价值的文章主要介绍了【webpack】自定义loader。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

📝个人主页:爱吃炫迈
💌系列专栏:前端工程化
🧑‍💻座右铭:道阻且长,行则将至💗


loader

一个loader就是一个Node.js模块,这个模块需要导出一个函数,这个导出函数的工作就是获得处理前的源内容,对源内容进行处理后,返回处理后的内容

实现一个替换文件中姓名的loader。例如将“小张”替换成“小李”

name.js

export const name = "小张"

index.js

import { name } from "./name.js"

function showInfo() {
    console.log("name")
}

showInfo()

运行代码输出:

小张

现在我们希望将小张替换成小李:

  1. 创建replace-loader

myLoaders/replace-loader.js

module.exports = function(source) {
    // source为compiler传递给loader的一个文件的源内容
    
    const cotent = source.replace("小张", "小李")
    // 该处理函数需要返回处理后的内容
    return cotent
}
  1. 使用loader

webpack.config.js

const path = require("path")

module.export = {
    mode: "production",
    entry: "./src/index.js",
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "[name].js",
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use:"./myLoaders/replace-loader.js"
                // 本地loader, 要填写本地的路径
            }
        ]
    },
}

打包后我们就会发现实现我们的想要的功能啦~~~

因为我们使用的是本地的loader,因此需要填写本地的路径。loader的引入主要有以下几种方式:

loader引入方式

  1. 如果是npm包安装的loader,那么直接写loader名称即可
{
    test: /\.js$/,
    use:'babel-loader'
}
  1. 如果是本地自定义的loader,那么需要写本地loader的地址
{
    test: /\.js$/,
    use: path.resolve(__dirname, "./myLoaders/replace-loader")
}

如上面的代码,我们每使用一个自定义的loader,都必须使用 path 模块来解析自定义loader的路径问题,这就会导致代码变得难以维护。那可不可以像引用第三方的loader一样,只写loader 名呢?我们可以使用 resolveLoader 来解决这个问题。

  1. 如果是本地定义的loader,然后也想直接使用loader名称,那么可以取个别名
module.exports = {
    resolveLoader: {
    // 取个别名
     alias: {
        "replace-loader": path.resolve(__dirname,"myLoaders/replace-loader")
    }
  },
  module: {
        rules: [
            {
                test: /\.js$/,
                use: 'replace-loader',
            }
        ]
    }
}
  1. 如果你不想取别名,还想直接使用loader,那么就定义一下loader的查找位置,loader会默认先从node_modules中查找。如果我们希望它也能够到本地查找,那么就定义一下查找位置。

ResolveLoader 用于配置 webpack 如何寻找 loader,默认情况下只会去 node_modules 目录下寻找,为了让 webpack 去加载自定义的 loader,我们需要修改 resolveLoader.modules

比如我们自定义的loader 放在 ./myLoaders 目录下,则需要如下配置:

module.exports = {
    resolveLoader: {
    // 去哪些目录下寻找 loader ,有先后顺序之分
    // 如下配置中,查找顺序是:先在 node_modules 目录下寻找,若找不到,再到 ./myLoaders 目录下寻找
    modules: ["node_modules", "./myLoaders"],
  },
  module: {
        rules: [
            {
                test: /\.js$/,
                use: 'replace-loader',
            }
        ]
    }
}

loader传入/接收参数

传入参数

我们上述代码的功能是将“小张”替换成“小李”,假如我们希望将“小张”替换成“小王”,换成“小周”,那么我们难道每次都在loader中修改吗?这肯定不会,因此,我们需要支持配置参数。loader支持通过options进行配置:

{
  test: /\.js$/,
  use: [
    "replace-loader",
    {
      loader: "replace-loader",
      options: {
        name: "小李",
      },
    },
  ],
}

接收参数

  1. this.query

webpack官方文档如何让编写一个loader中说明了loader只接收一个参数,这个参数是读取的文件内容(一个包含资源文件内容的字符串)。webpack会把所有的信息都放到上下文this中,我们可以通过this.queryAPI来获取webpack.config.js中配置的options对象:

module.exports = function (source) {
  // this.query 获取到的就是在webpack.config.js配置中配置的 options 对象
  // 通过 this.query API 获取在配置中配置的 name 
  return source.replace("小张", this.query.name);
};
  1. loader-utils

虽然我们可以通过this.query来进行获取,但是webpack更加推荐使用loader-utils来进行操作,它提供了许多有用的工具,最常用的一种工具是获取传递给loader的选项。

  • 安装
npm i loader-utils -D
  • 使用
const { getOptions } = require('loader-utils')
module.exports = function(source)  {
    // const options = this.getOptions();
    let { name } = getOptions(this);
    const content = source.replace("小张",name);
    return content;
}

loader返回值

loader 的原理就是将输入的源内容进行处理后返回,loader的返回值涉及到一个还是多个返回值。有些情况下比如我们需要返回sourceMap,那么就需要多个返回值。 如果需要返回一个返回值,可以直接使用return。

return source

如果只有一个返回值,可以使用return返回,这种方式返回的是源内容转换后的内容

const { getOptions } = require('loader-utils')
module.exports = function (source) {
    // 处理source
    let { name } = getOptions(this)
    const content = source.replace("小张", name)
    return content // 返回一个值
}

this.callback()

如果有多个值需要返回,需要使用loader本身提供的回调函数callback。这种方式可以返回除了处理内容之外的其他信息。

const { getOptions } = require('loader-utils')
const { SourceMap } = require('module')

module.exports = function (source) {
  // 处理 source
  let { name } = getOptions(this)
  const content = source.replace("小张", name);
  // 使用 this.callback 返回内容
  this.callback(null, content,SourceMap);
};

callback支持的参数如下:

callback({
    // 报错
    error: Error | Null,
    // 转换后的内容
    content: String | Buffer,
    // 转换后的内容得出的sourceMap
    sourceMap?: SourceMap,
    // ast
    abstractSyntaxTree?: AST 
})

注意:

在Webpack中,每个loader都可以返回一个包含多个属性的对象。

  • content是该对象的一个属性,用于指定经过loader处理后生成的代码。
  • sourceMap是另一个属性,用于指定生成的代码的源映射表。

因此,content和sourceMap的区别在于,content是经过loader处理后生成的代码本身,而sourceMap则是一个包含了生成的代码和原始代码的映射关系的JSON对象。

事实上,如果只有一个返回值,我们也可以直接使用this.callback。

this.callback(null,content)

同步/异步loader

loader有同步异步之分,上面介绍的loader都是同步loader,因为它们的转换流程都是同步的,即转换完成后再返回结果。但在某些场景下转换内容需要异步才能完成,例如需要通过网络请求才能得到结果,如果使用同步的方式,网络请求就会阻塞整个构建过程,导致构建变得十分缓慢。

使用async和await进行处理

module.exports = async function(source)  {
    let {name,age} = getOptions(this);
    // 这里其实不是异步的,只是作为示例,可以这样处理
    const content =  await source.replace("小张",name);
    return content;
}

使用loader提供的this.async进行处理

当转换内容需要异步才能完成时,我们可以使用webpack为loader提供的this.async将这个loader变成是一个异步loader:

const { getOptions } = require('loader-utils')
const { SourceMap } = require('module')

module.exports = function (source) {
  let { name } = getOptions(this);
  // 使用 setTimeout 模拟异步过程
  setTimeout(() => {
    const content = source.replace("小张", name);
    // 通过 callback 返回执行异步后的结果
    this.async(null, content,SourceMap);
  }, 3000);
};

loader单一功能原则

在webpack官网的如何编写一个loader中提到,webpack的loader编写最寻单一功能原则,也就是loader只能实现一个功能。比如less-loader用来处理less文件,css-loader用来处理css文件,style-loader用来将样式插入到style标签中,这些功能虽然可以放到一个loader中实现,但是为了确保loader的功能纯粹,能够让不同的loader各司其职,同时进行功能组合,最好每个loader只负责一个功能。

loader实战

style-loader

style-loader做的事情其实很简单,就是把序列化后的css内容放到style标签中,然后将style标签插入到HTML页面的head标签中

module.exports = function(source) {
    return `const styleTag = document.createElement('style');
        styleTag.innerHTML = ${source};
        document.head.appendChild(styleTag);
    `
}

css-loader

css-loader 做的事情也十分的简单,将 less-loader 转换后的 css 内容进行序列化

module.exports = function(source) {
    return JSON.stringify(source);
}

less-loader

less-loader 做的事情就是使用 less 模块,将 less 转换成 css

// 使用 less 模块处理 less 语法
const less = require('less');
module.exports = function(source) {
    less.render(source, (error, output) => {
    let { css } = output;
    this.callback(error, css)
  })
}

参考文章:
由浅及深实现一个自定义loader文章来源地址https://www.toymoban.com/news/detail-648728.html

到了这里,关于【webpack】自定义loader的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端面试:【前端工程化】构建工具Webpack、Parcel和Rollup

    嗨,亲爱的前端开发者!在现代Web开发中,前端工程化变得愈发重要。构建工具如Webpack、Parcel和Rollup帮助我们自动化任务、管理依赖、优化性能等。本文将深入探讨这三个前端构建工具,帮助你了解它们的优点和用途。 1. Webpack: 用途: Webpack是一个强大的模块打包工具。它

    2024年02月11日
    浏览(44)
  • 【前端工程化面试题】说一下 webpack 的构建流程

    类似问题是,说一下 vite 的构建流程,参考这篇文章。 初始化流程 从配置文件和shell 语句中读取合并参数,初始化需要使用的插件和执行环境所需要的参数 配置文件默认是 webpack.config.js 编译构建流程 解析入口模块,从入口模块开始串行调用对应的loader 去翻译文件内容,依

    2024年02月20日
    浏览(53)
  • 前端工程化第三章:webpack5基础(下)

    TypeScript 是一种静态类型的编程语言,是 JavaScript 的一个超集。它由 微软开发,提供了许多 JavaScript 不支持的功能,比如 类型检查 、 接口和类 。 ts-loader 是 Webpack 中的一个加载器,用于将 TypeScript 代码转换成 JavaScript 代码。它是基于 typescript 编译器实现的,支持所有 TypeS

    2024年02月16日
    浏览(44)
  • 前端工程化第一章:webpack5基础(上)

    Webpack 是一个现代 JavaScript 应用程序的静态模块 打包器 。它是一个用于 将代码编译成浏览器可识别的格式 的工具。 webpack 可以实现以下的功能: 代码转换 : TypeScript 编译成 JavaScript 、 SCSS 、 less 编译成 CSS 等。 文件优化 :压缩 JavaScript 、 CSS 、 HTML 代码, 压缩合并图片

    2024年02月16日
    浏览(42)
  • Vue3学习-01_前端工程化与webpack

    最近在学习Vue知识,参照的教程是黑马程序员官网提供的免费前端教程,这里记录一下自己的学习笔记以及遇到的相关问题。 前端工程化指的是:在企业级的前端项目开发中,把前端开发所需的工具、技术、流程、经验等进行规范化、标准化。最终落实到细节上,就是实现前

    2024年02月13日
    浏览(66)
  • 【前端工程化面试题】如何优化提高 webpack 的构建速度

    使用最新版本的 Webpack 和相关插件 : 每个新版本的 Webpack 都会带来性能方面的改进和优化,因此始终确保你在使用最新版本。同时,更新你的相关插件也是同样重要的。 使用DllPlugin动态链接库: 使用DllPlugin和DllReferencePlugin来将第三方库的代码进行预打包,减少构建时间。这个

    2024年02月19日
    浏览(56)
  • 前端工程化之:webpack4-1(babel的安装和使用)

    官网:https://babeljs.io/ 民间中文网:https://www.babeljs.cn/  babel一词来自于希伯来语,直译为巴别塔。 巴别塔象征的统一的国度、统一的语言 而今天的 JS 世界缺少一座巴别塔,不同版本的浏览器能识别的 ES 标准并不相同,就导致了开发者面对不同版本的浏览器要使用不同的语言

    2024年02月21日
    浏览(43)
  • 【前端工程化面试题】webpack的module、bundle、chunk分别指的是什么?

    首先从语法方面 在配置文件中有 module 这个配置项,里面有 rules 选项用来配置各种 loader,还有其他各种选项,参考官网。 bundle 和 chunk 在配置文件中是没有这个选项的,但是会出现在配置的值中。 module 模块 指单个文件,可以是 js、css、图片等, 每个文件都是一个独立的模

    2024年02月19日
    浏览(54)
  • 【前端工程化面试题】webpack proxy的工作原理,为什么能解决跨域问题

    在 webpack 的配置文件 webpack.config.js 中有一个配置项 devServer 里面有一个属性是 proxy,这里面可以配置代理服务器,解决跨域问题,请参考官网。 一般来说 webpack 的代理就是说的开发服务器 webpack-dev-server。 其实不光是 webpack 其他的打包工具比如是 vite,也有代理的功能,也是

    2024年02月21日
    浏览(55)
  • 前端工程化详解——理解与实践前端工程化

    前言: 前端工程化一直是一个老生常谈的问题,不管是面试还是我们在公司做基建都会经常提到前端工程化,那么为什么经常会说到前端工程化,并没有听过后端工程化、Java工程化或者Python工程化呢?我们理解的前端工程化是不是一直都是Webpack的性能调优,或者是一个cli工

    2024年02月02日
    浏览(76)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包