博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编写一个webpack的loader(1)
阅读量:6412 次
发布时间:2019-06-23

本文共 4104 字,大约阅读时间需要 13 分钟。

开始之前,先介绍一下loader,下面是webpack中文网loader的描述

所谓 loader 只是一个导出为函数的 JavaScript 模块。 会调用这个函数,然后把上一个 loader 产生的结果或者资源文件(resource file)传入进去。函数的 this 上下文将由 webpack 填充,并且  具有一些有用方法,可以使 loader 改变为异步调用方式,或者获取 query 参数。

loader的参数以及返回值(同样摘抄自webpack中文网)

第一个 loader 的传入参数只有一个:资源文件(resource file)的内容。compiler 需要得到最后一个 loader 产生的处理结果。这个处理结果应该是 String 或者 Buffer(被转换为一个 string) ,代表了模块的 JavaScript 源码。另外还可以传递一个可选的 SourceMap 结果(格式为 JSON 对象)。

loader的分类

loader分为同步loader异步loaderloader本质是一个函数。所以这两种loader的区别,可以理解为只是返回值不同(只是为了方便理解的类比)。实际操作并不是简单的两种返回值。

同步loader

同步loader比较简单,无论是 return 还是 调用this.callback 都可以同步地返回转换后的 content 内容。

  1. 使用return 这种比较直观,就一个普通函数,执行完成返回一个值。例如:
function loader(source) {  // do anything  return source;}复制代码
  1. 使用this.callback this.callback的函数参数类型是
// 后两个参数是非必传的this.callback(  err: Error | null,  content: string | Buffer,  sourceMap?: SourceMap,  meta?: any);复制代码

这种比return方式更灵活,可以返回多个值。例如:

function loader(source) {  // do anything   this.callback(null, source, map, meta);}复制代码

注意: 函数中调用callback后,return的返回值将被忽略。

异步loader

异步loader只有一种处理方式。对于异步 loader,使用  来获取 callback 函数。这里的callback函数,和同步loader里面的参数是一样的。

function loader (source) {    console.log('--- loader begin ----');    console.log(source);    console.log('--- loader end ----\n');    const callback = this.async();    // do anything    callback(null, source);}module.exports = loader;复制代码

注意几种特殊情况:

  1. 函数中调用this.async后,return的返回值将被忽略。
  2. 函数中调用this.async后,再调用this.callback,则会将当前loader当做同步loader来处理。
  3. 函数中调用this.async后,再调用this.callback且立即调用this.async返回的callback。程序会报错。

至此,我们就能开始着手写一个简单的loader了。下面便开始,着手写几个loader

banner-loader

这个loader的功能是给每一个文件头部,添加一行段注释,标明作者。例如:

/**** @author laibao101** @time 2019-06-04 19:57:20**/// source code复制代码

功能分析:这个loader,并没有任何的异步操作,所以我们使用同步loader即可。注释方面,暂且先写死,通过参数配置的,后续再做。

function loader (source) {    const time = new Date().toLocaleString()    return `        /**        ** @author laibao101        ** @time ${time}        **/        ${source}    `}复制代码

使用模板字符串,将注释代码写进去,返回即可。这样一个简单的loader就完成了。

异步的banner-loader

这个loader是为了写一个异步loader而写的。功能是从一个文件中读取模板,给文件添加banner

// banner-loaderconst path = require('path');const fs = require('fs');const baseUrl = process.cwd();const configTextPath = "bannerConfig.txt";// 拼接完整的配置文件路径const fullConfigPath = path.resolve(baseUrl, configTextPath);// 根据模板中的占位符,来获取数据const configItemMap = {    author: "laibao101",    time: new Date().toLocaleString()};// 匹配占位符const reg = /{(\w+)}/gi;function loader (source) {    const callback = this.async();    fs.readFile(fullConfigPath, (err, data) => {        if (err) {            // 如果读取文件失败,返回错误            callback(err);        }        // 获取文件内容        const template = data.toString();        // 根据模板,修改占位符数据,完成banner        const banner = template.replace(reg, (match, key) => {            return configItemMap[key] || key;        });        // 拼接返回值        const ret = `            ${banner}            ${source}        `        callback(null, ret);    });}module.exports = loader;// bannerConfig.txt/**** @author {author}** @time {time}**/复制代码

可配置参数的同步banner-loader

前面写到的banner-loader,参数都是loader内部定的。如果需要从webpack.config.js中获取参数,则可以使用webpack提供的this.query参数来获取loader配置中的options参数。这在loader中使用的很频繁。

例如: babel-loader

module: {  rules: [    {      test: /\.m?js$/,      exclude: /(node_modules|bower_components)/,      use: {        loader: 'babel-loader',        options: {          presets: ['@babel/preset-env']        }      }    }  ]}复制代码

url-loader

module.exports = {  module: {    rules: [      {        test: /\.(png|jpg|gif)$/i,        use: [          {            loader: 'url-loader',            options: {              limit: 8192            }          }        ]      }    ]  }}复制代码

所以,我们将上面的banner-loader,修改一下,将参数改为从loader配置中获取

// banner-loaderfunction loader (source) {    const time = new Date().toLocaleTimeString();    const { author = '' } = this.query || {}    return `        /**        ** @author ${author}        ** @time ${time}        **/        ${source}    `}module.exports = loader;// webpack.config.js{  ...  options: {    author: "laibao101"  }}复制代码

这样,我们就可以实现参数从配置文件中获取的loader了。

下一篇

介绍 raw-loaderpitch-loader。并各自编写一个demo

转载地址:http://uzura.baihongyu.com/

你可能感兴趣的文章
Dubbo/HSF在Service Mesh下的思考和方案
查看>>
Django form表单
查看>>
CTYL-9.14(tomcat端口与阿里云安全组,域名与tomcat配置,域名与反向代理)
查看>>
Java 多线程相关问题记录
查看>>
LNMP架构介绍、MySQL安装、PHP安装、 Nginx介绍
查看>>
简单的Spark+Mysql整合开发
查看>>
阿里java面试经验大汇总(附阿里职位需求)
查看>>
Python全套零基础视频教程+软件2018最新编程视频!
查看>>
内存管理之1:x86段式内存管理与保护模式
查看>>
20180925上课截图
查看>>
IO输入/输出流的简单总结
查看>>
JavaScript之DOM-9 HTML DOM(HTML DOM概述、常用HTML DOM对象、HTML表单)
查看>>
技术成长之路(一)
查看>>
中国北方国际五金城硬件选型
查看>>
php.exe启动时提示缺少MVCR110.dall 64位 window系统 解决
查看>>
判断是否为数字方法
查看>>
[翻译] EF Core in Action 关于这本书
查看>>
js Uncaught TypeError: undefined is not a function
查看>>
数据库存储引擎
查看>>
[2019.2.13]BZOJ4318 OSU!
查看>>