教你手写webpack常用loader

本文详细介绍了如何手写webpack的常用loader,包括同步和异步loader的实现,如hello-loader、eslint-loader、babel-loader和uglify-loader。文章通过实例展示了loader的工作原理和配置方法,帮助读者深入理解webpack生态。
摘要由CSDN通过智能技术生成

前言

webpack 作为目前主流的前端构建工具,我们几乎每天都需要与它打交道。个人认为一个好的开源产品壮大的原因应该包括核心开发者的稳定输出以及对应生态的繁荣。对于生态来说, webpack 是一个足够开放的类库,提供了可插拔的方式去自定义一些配置,包括配置 loaderplugin ,本篇我们主要讨论loader。

loader 本质上是一个函数,webpack在打包过程中会按照规则顺序调用处理某种文件的 loader ,然后将上一个 loader 产生的结果或者资源文件传入进去,当前 loader 处理完成后再交给下一个 loader

loader的类型

开始之前,还是要先大概提一下 loader 的类型以及一些常用的 api ,不感兴趣的同学可以直接跳过这一小节,更详细的指引请参阅官方文档。

loader 主要有以下几种类型:

  • 同步 loaderreturn 或调用 this.callback 都是同步返回值
  • 异步 loader :是用 this.async() 获取异步函数,是用 this.callback() 返回值
  • raw loader :默认情况下接受 utf-8 类型的字符串作为入参,若标记 raw 属性为 true ,则入参的类型为二进制数据
  • pitch loaderloader 总是从右到左被调用。有些情况下,loader 只关心 request 后面的 元数据(metadata),并且忽略前一个 loader 的结果。在实际(从右到左)执行 loader 之前,会先从左到右调用 loader 上的 pitch 方法。

开发 loader 时常用的 API 如下:

  • this.async :获取一个 callback 函数,处理异步
  • this.callback :同步 loader 中,返回的方法
  • this.emitFile :产生一个文件
  • this.getOptions :根据传入的 schema 获取对应参数
  • this.importModule :用于子编译器在构建时编译和执行请求
  • this.resourcePath :当前资源文件的路径

Hello Loader

现在假设我们有这么一个需求:在每个文件的头部打上开发者的相关信息。比如打包之前的文件内容是这样的:

const name = 'jay'

打包之后文件内容可能是这样的:

/** * @Author:jay * @Email:email@qq.com * /const name = 'jay'

那废话不多说,直接开整。首先把相关依赖安装一下:

//package.json
"webpack": "^5.0.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.10.0"

再简单的配置一下webpack:

const HtmlWebpackPlugin = require('html-webpack-plugin')
const {
    resolve } = require('path')
module.exports = {
   
    mode: 'none',
    entry: './src/main.js',
    output: {
   
        path: resolve(__dirname, './dist'),
        filename: 'js/[name].js',
        clean: true
    },
    module: {
   
        rules: [
            {
   
                test: /\.js$/,
                loader: './loaders/hello-loader',
            },
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
   
            template: './public/index.html'
        })
    ]
}
参考webpack视频讲解:进入学习

接下来就可以开始实现这个 loader 了,首先每一个 loader 都是一个函数,这个函数的返回结果要么是二进制数据要么是字符串,字符串就是文件的具体内容,二进制数据就是资源文件比如图片的内容。在上面这个需求中,显然我们只需要拿到文件的内容,做一些修改替换即可。所以可以比较容易的写出下面的代码:

module.exports = function (content) {
   
    const newContent = `        /**         * @Author:jay         * @Email:email@qq.com         * */                ${
     content}
    `

    return newContent;
}

这样就会将对应的内容添加到打包结果中,如下图所示:

在这里插入图片描述

获取参数

上面对于文件的一些描述我们是已经写死了,但这样不太灵活,大多数时候是希望能通过 loader 对应的配置去获取对应的参数,我们可以在引入 loader 的时候这样改造一下:

{
   
    test: /\.js$/,
    loader: './loaders/hello-loader',
    options: {
   
        author: 'hello loader',
        email: 'helloloader@qq.com'
    }
}

那么在具体的loader中,可以使用 this.getOptions(schema) 去获取传入的配置。这个 schema 是对 option 的格式校验,代码改造如下:

const schema = {
   
    type: 'object', //options是一个对象
    properties: {
   
        //author是一个字符串
        author: {
   
            type: 'string'
        },
        //email是一个字符串
        email: {
   
            type: 'string'
        }
    }
}
const options = this.getOptions(schema) || {
   }
const {
    author = 'null', email = 'null' } = options
const newContent = `    /**     * @Author:"${
     author}"     * @Email:"${
     email}"     * */    ${
     content}
`

这样就可以将用户自定义的参数传给处理的 loader ,对于一些需要提供可拓展能力的 loader 来说,获取参数这一步是必不可少的。webpack配置如下,即可使用loader获取参数的能力。

在这里插入图片描述

在这里插入图片描述

异步回调

这时候有了一个新需求,希望我们把当前处理的文件内容信息与文件名通过网络传输,以便后续做一些分析。那为了方便我们还是在上面的 loader 进行拓展,实际开发中最好不要这样做,要保证 loader 的单一职责。这时候就不能直接返回结果,而是要获取一个异步 callback 函数,使用这个函数把结果输出。代码实现如下:

const callback = this.async()
// 模拟网络请求
setTimeout(() => {
   
    callback(null, JSON.stringify(newContent), null, {
   })
    console.log('net done');
}, 1000)

这里留意一下 callback 函数的用法:callback(error,content,map,meta) ,其中有四个参数,分别的作用是:

  • error :错误信息,如果存在的话则会抛出异常,构建终止
  • content :处理后的内容
  • mapsourceMap 相关信息
  • meta :要传给下一个 loader 的额外信息参数

JS处理

上面大致举例说明了同步l loader 、异步 loader 以及如何获取 loader 的参数。在这一小结,主要实现开发过程中经常用到的三个 JS 处理相关的 loader

  • eslint-loader :使用 eslint 做代码检测
  • babel-loader :将 ES6+ 语法转换为 ES5 语法
  • uglify-loader :对代码进行压缩混淆

eslint-loader

首先先来实现 eslint-loader ,实现思路是对当前处理的文件调用 eslint 去扫描,如果无错误则继续正常调用下一个 loader 去处理。具体代码实现如下:

const childProcess = 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
常用webpack loader有babel-loader、css-loader、file-loader和url-loader常用的plugin有CommonsChunkPlugin、ProvidePlugin、UglifyJsPlugin和HtmlWebpackPlugin。Webpack 是一种现代化的前端构建工具,它可以将多个源文件(如 JavaScript、CSS、图片等)打包成单个的 JavaScript 文件,以优化网页的加载速度和性能。在 Webpack 中,Loader 和 Plugin 是两个非常重要的概念。 Loader 是用于对模块源代码进行转换的工具,它可以将各种类型的文件转换成 Webpack 能够处理的模块。常见的 Loader 有: - `babel-loader`:将 ES6+ 语法转换成 ES5 语法,以便浏览器能够兼容。 - `style-loader` 和 `css-loader`:用于处理 CSS 文件,将 CSS 文件转换成 JavaScript 模块,以便在浏览器中使用。 - `file-loader` 和 `url-loader`:用于处理图片、字体等文件,将它们复制到输出目录并修改模块代码,以便在浏览器中使用。 Plugin 则是用于增强 Webpack 功能的工具,它可以在 Webpack 构建过程的不同阶段执行一些额外的任务。常见的 Plugin 有: - `HtmlWebpackPlugin`:用于生成 HTML 文件,并自动将生成的 JavaScript 文件插入到 HTML 文件中。 - `MiniCssExtractPlugin`:用于将 CSS 文件提取成单独的文件,以便在浏览器中加载。 - `CleanWebpackPlugin`:用于在每次构建之前清除输出目录中的文件,以便确保输出的文件都是最新的。 Loader 和 Plugin 在 Webpack 中都有着非常重要的作用,通过它们,我们可以轻松地处理各种类型的文件,并增强 Webpack 的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值