webpack 手写loader流程

752 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

引言

webpack千奇百怪的loader,如果你还不懂loader的作用或loader的流程,就适合自己手动编写一个loader,这能让你快速了解loader的运行机制以及加深你对它的理解。在面试中如果面试官提到webpack loader,我想你就能镇定自若,得心应手。

本文手动写一个loader,让每一位前端开发者也能自己编写loader,需要有一定的webpack基础

loader 简介

一句话:loader是负责资源文件从输入到输出的转换
因此也可以说loader是webpack 核心

开始

手写一个markdown文件加载器为例:markdown-loader
功能:实现可以在代码中导入markdown文件,读取生成html展示到页面

第一步
搭建webpack基础结构,搭建流程省略,不会的可以私聊我写文章
WX20220605-155330@2x.png
src下放一个index.js项目入口,里面引入md文件

// index.js
import md from './readme.md'
document.write(md)

src下放一个已经写好的md文件

// readme.md
## 岭南蜀香
### 想吃攀枝花大芒果的联系我!便宜包邮!

**贵妃,金煌上市咯**

再编辑webpack.config.js文件,基本结构:

const path = require('path')

module.exports = {
  mode: 'none', // 打包模式
  entry: './src/index.js', // 入口
  output: { // 输出
    filename: 'bundle.js', // 输出文件名
    path: path.join(__dirname,'dist'), // 输出目录
  }
}

现在,如果直接执行webpack打包命令(yarn webpack),后报一个错误:
WX20220605-170444@2x.png
告诉我们需要有一个loader来处理该类型的文件

第二步
目标:新建loader文件,读取md文件,生成html字符串
在第一层目录下新建一个markdown-loader.js文件,每个webpack loader都需要导出一个函数,该函数就是对该资源的一个处理过程,

// markdown-loader.js
module.exports = source => {
  console.log(source)
  return 'begin!'
}

参数source为输入,首先打印出输入,并返回一个字符串
然后在webpack配置文件中配置上自己的loader

// webpack.config.js
module: {
  rules: [
    {
      test: /.md$/,
      use: './markdown-loader.js'
      // use写入loader的相对路径
      // use不仅可以写入名称,也可以写入路径,和node的require模式是 一样的
    }
  ]
}

现在执行yarn webpack,后也会报一个错: WX20220605-171358@2x.png
告诉我们需要一个额外的加载器来加载我们的处理结果
这是为什么呢?
因为loader的加载过程相当于一个管道
source => loader1 => laoder2 => result
也要求结果result必须是一个js代码,我们返回的字符串'begin!'不符合js语法,所以会报错,告诉我们要么返回js代码,要么继续加loader来继续处理结果

result为什么必须是一个js代码?
我们将返回结果改过:return "console.log('begin!')"
然后执行打包,我们会看到打包结果bundle.js为:
WX20220605-172914@2x.png
发现打包后的字符串直接拼接到js中了,所以必须得符合js的语法规则,否则就会报错

第三步
安装一个md解析器:marded
然后将解析结果以js规则的结果导出即可

// markdown-loader.js
const marked = require('marked')

module.exports = source => {
    const html = marked(source)
    return `module.exports = ${JSON.stringify(html)}`
}

此处该loader就算完成!

额外也可以使用多层loader处理方式(方式2):

// markdown-loader.js
const marked = require('marked')
module.exports = source => {
    const html = marked(source)
    return html // 直接返回html 字符串交给下一个loader处理
}

// webpack.config.js
rules: [
  {
    test: /.md$/,
    use: [
      'html-loader',
      './markdown-loader.js'
    ]
  }
]

同样也能达到正确的结果
最终展示的网页:

WX20220605-174626@2x.png

最后写完可以将markdown-loader发布到npm上作为一个独立的模块使用

总结

我们在手写一个loader的同时,也讲解了webpack loader的运行原理
虽然写一个loader不难,但正真实践手写后,你才会发现一些前所未知的报错,理解为什么会报错,你才会更加深层次的理解这个东西。

往期精彩文章

🌟两种方式轻松做react css样式隔离
🌟彻底理解redux的中间件原理
🌟canvas实现刮刮奖效果
🌟前端实现pdf下载
🌟web前端性能优化(全汇总)
🌟一句话概括this指向问题
🌟MutationObserver 实现微任务原理分析
🌟遇到几次的大厂笔试题:装饰数组push方法
🌟V8垃圾回收策略与GC算法
🌟浏览器缓存策略(强缓存和协商缓存)
🌟$nextTick 源码解读与原理分析
🌟手动封装适合react hook使用的状态管理工具