图解Webpack——实现一个Loader

简介: 图解Webpack——实现一个Loader

loader承担的是翻译官的职责,利用其弥补了让webpack只能理解JavaScript和JSON文件的问题,从而可以处理其它类型的文件,所以loader对webpack的重要性不言而喻,所以学习构建一个loader是学习webpack的必经之路。在学习编写一个loader之前,要明确一下loader的职责:其职责是单一的,只需要完成一种转换。下面将逐步阐述选择loader开发中的几个关键点并实现一个loader。


640.jpg

一、Loader分类



loader是一个CommonJs风格的函数,接收输入的source后可通过同步或异步的方式进行处理,然后将内容进行输出。

640.png

1.1 同步Loader


同步loader指的是同步的返回转换后的内容。由于是在Node.js这样的单线程环境,所以转换过程会阻塞整个构建,构建缓慢,不适用于耗时较长的环境中。对于同步loader,主要有两种方法返回转换后的内容:return和this.callback.

  1. return
    利用return可直接返回转换后结果。


module.exports = function(source, map, meta){
    // ...
    // output为处理后结果
    return output;
}
  1. this.callback
    该方法相比于return更加灵活,其参数主要有四个:


this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);

(1)第一个参数为无法转换原内容,Webpack会返回一个Error。

(2)第二个参数即为经过转换后的内容(为输出的内容)。

(3)指与编译后代码所映射的源代码,便于调试。为了在此loader中获取该sourceMap,则需要在创建的webpack做一下配置(以js为例,babel-loader会将基础ES6语法进行转换为ES5,通过devtool可以开启source-map):

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    'test-loader',// 该loader即为自己构建的loader
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                '@babel/preset-env'
                            ]
                        }
                    }
                ]
            }
        ]
    },
    devtool: 'eval-source-map',
}

(4)可以是任何东西,输出该参数,即可在下一个loader中获取并使用,例如通过各loader之间共享通用的AST,加速编译时间。


利用this.callback可返回传递多参数的结果。


module.exports = function(source, map, meta) {
    // 处理后获得的结果output
    const output = dealOperation(source);
    this.callback(null, output, map, meta);
}


1.2 异步Loader


同步loader只适合于计算量小,速度快的场景,但是对于计量大、耗时比较长的场景(例如网络请求),使用同步loader会阻塞整个构建过程,导致构建速度变慢,采用异步loader即可避免该问题。对于异步loader,使用this.async()可以获取到callback函数,该函数参数和同步loader中this.callback参数一致。


module.exports = function(content, map, meta) {
    // 获取callback函数
    const callback = this.async();
    // 用setTimeout模拟该异步过程
    setTimeout(() => {
        // 处理后获得的结果output
    const output = dealOperation(source);
        callback(null, output, map, meta);
    }, 100)
}


二、文件转化后类型


默认情况下,资源文件经转化后都是UTF-8格式编码的字符串,但是对于图片这样的文件经过转化后是二进制格式的内容,为了让loader支持接收二进制资源,需要设置raw(以图片资源为例进行展示)


// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    'url-loader',
                    'raw-test-loader',// 自己的loader
                ]
            }
        ]
    }
}
// raw-test-loader.js
module.exports = function(source, map, meta) {
    // 处理输入的资源
    const output = dealOperation(source);
    return output;
}
// 通过该属性告诉webpack该loader是否需要二进制数据
module.exports.raw = true;


三、options选项



对于webpack配置中,loader往往有一些options参数,对于自己编写的loader中为了获取options参数,官方推荐使用loader-utils包,利用该包即可获取options中参数,然后在loader中进行处理。


const loaderUtils = require('loader-utils');
module.exports = function (source, map, meta){
    // 获取options
    const options = loaderUtils.getOptions(this);
    const output = dealOperation(source);
    return output;
}


四、是否缓存



对于转换操作需要大量的计算,非常耗时,每次重新构建会让构建过程变的非常缓慢。webpack会默认缓存所有loader的处理结果,即要处理文件和其相关依赖没发生变化就会利用其缓存(注意loader除了this.addDependency里指定的依赖外,不应该有任何外部依赖)。通过this.cacheable可控制其是否进行缓存。


module.exports = function(source, map, meta) {
    // 关闭缓存
    this.cacheable(false);
    return source;
}


五、实现一个loader



本节是loader实战,编写了一个用于字母大小写转换的loader,利用该loader能够实现将txt文件中字母的大小写转换,其loader内容及webpack.config.js相关配置如下所示(详细代码见github上代码)


// format-letters-loader.js
const loaderUtils = require('loader-utils');
const Lowercase2Uppercase = 'L2U';
const Uppercase2Lowercase = 'U2L';
module.exports = function (source, map, meta) {
    let output = '';
    // 获取options
    const options = loaderUtils.getOptions(this);
    const { formatType } = options;
    switch(formatType) {
        case Lowercase2Uppercase: {
            output = source.toUpperCase();
            break;
        }
        case Uppercase2Lowercase: {
            output = source.toLowerCase();
            break;
        }
        default: {
            output = source;
        }
    }
    this.callback(null, output, map, meta);
};
// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                exclude: /\.(css|js|html|png|jpg|gif)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'asset',
                        }
                    },
                    {
                        loader: 'format-letters-loader',
                        options: {
                            formatType: 'U2L'
                        }
                    },
                ]
            }
        ]
    },
    // 解析loader包是设置模块如何被解析
    resolveLoader: {
        modules: ['./node_modules', './loader'],// 告诉 webpack 解析loader时应该搜索的目录。
    },
}


相关文章
|
13天前
|
前端开发 UED
Webpack 中处理 CSS 和图片资源的多 Loader 配置
【10月更文挑战第12天】 处理 CSS 和图片资源是 Webpack 配置中的重要部分。通过合理选择和配置多个 Loader,可以实现对这些资源的精细处理和优化,提升项目的性能和用户体验。在实际应用中,需要不断探索和实践,根据项目的具体情况进行灵活调整和优化,以达到最佳的处理效果。通过对 Webpack 中多 Loader 处理 CSS 和图片资源的深入了解和掌握,你将能够更好地应对各种复杂的资源处理需求,为项目的成功构建和运行提供坚实的基础。
40 1
|
13天前
|
前端开发 JavaScript
Webpack 中多个 Loader 的配置
【10月更文挑战第12天】使用多个 Loader 进行配置是 Webpack 中常见的操作,可以实现对各种资源的精细处理和优化。在配置时,需要根据具体需求合理选择和排列 Loader,并注意它们之间的顺序和交互关系。同时,不断了解和掌握新的 Loader 以及它们的特性,有助于更好地发挥 Webpack 的强大功能,提升项目的开发效率和质量。通过深入理解和熟练运用多个 Loader 的配置方法,你将能够更加灵活地处理各种资源,满足项目的多样化需求。
29 2
|
13天前
|
前端开发 JavaScript
Webpack 常用 Loader 和 Plugin
【10月更文挑战第12天】Webpack 是一个强大的模块打包工具,能够将各种资源模块进行打包和处理。Loader 用于转换模块的源代码,如 `babel-loader` 将 ES6+ 代码转换为 ES5,`css-loader` 处理 CSS 文件等。Plugin 扩展 Webpack 功能,如 `HtmlWebpackPlugin` 自动生成 HTML 文件,`UglifyJsPlugin` 压缩 JavaScript 代码。通过合理配置和使用 Loader 和 Plugin,可以构建高效、优化的项目。
16 2
|
2月前
|
设计模式 前端开发 JavaScript
webpack实战之手写一个loader和plugin
该文章详细讲解了如何从零开始编写一个自定义的Webpack Loader和Plugin,包括它们的工作原理、开发步骤以及如何将自定义的Loader和Plugin集成到Webpack配置中。
webpack实战之手写一个loader和plugin
|
3月前
|
缓存 JSON JavaScript
Webpack 传递给 Loader 的原始内容是一个 UTF-8 格式编码的字符串
本文详细介绍了Webpack中Loader的概念及其重要性。Webpack仅支持处理JS和JSON文件,而对于CSS、图片等其他类型文件,则需要Loader来转换。文章列举了多种常见Loader,如css-loader、style-loader、babel-loader等,并提供了具体配置示例。此外,还介绍了如何自定义Loader,包括初始化项目、实现基本功能及处理异步操作等内容。通过本文,读者可以全面了解Loader的作用及其实现方法。
28 3
|
4月前
|
缓存 JSON JavaScript
用Webpack写一个Loader
在Webpack写一个Loader
23 1
|
3月前
webpack——You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
webpack——You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
290 0
|
6月前
|
Web App开发 JSON 前端开发
Webpack【搭建Webpack环境、Webpack增加配置文件、Webpack中使用Loader、Webpack分离CSS文件 】(一)-全面详解(学习总结---从入门到深化)
Webpack【搭建Webpack环境、Webpack增加配置文件、Webpack中使用Loader、Webpack分离CSS文件 】(一)-全面详解(学习总结---从入门到深化)
222 0
|
6月前
|
JSON 前端开发 JavaScript
Webpack【搭建Webpack环境、Webpack增加配置文件、Webpack中使用Loader、Webpack分离CSS文件 】(一)-全面详解(学习总结---从入门到深化)(上)
Webpack【搭建Webpack环境、Webpack增加配置文件、Webpack中使用Loader、Webpack分离CSS文件 】(一)-全面详解(学习总结---从入门到深化)
87 0