自己实现一个webpack loader

124 阅读2分钟

最近在学习webapck的知识,webpack loader是必须学习。今天就来简单的手撸一个webpack loader吧。

前置知识:

loader 定义

  • 官方定义:用于对模块的源代码进行转换
  • 自己理解:就是用于解决各种不同资源问题

规则

  • 最后的loader最早调用,传入调用资源;
  • 第一个loader最后调用;期望值传出Javascript和source map
  • 中间的loader执行时,会传入前一个loader的传出结果

使用注意

loader 的类型以及一些常用的 api ,更详细的指引请参阅官方文档

几种类型:

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

开发loader时常用的 API 如下:

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

例子

loader执行顺序

  • 例子1: loader执行先执行scss-loader,最后执行style-loader

css-loader:处理css 文件的依赖以及资源的加载(因为 webpack 默认只支持JS的导入以及一些资源文件的导入,所以我们需要实现对css文件的导入)

style-loader:将css-loader处理后的结果输出到文档中

module: {
rules: [
          { 
             test: /\.css$/,
             use: [
                { loader: "style-loader" },
                { loader: "css-loader" },
                { loader: "scss-loader" },
             ]
            }
         ] 
     }

例子2:

实现一个转换markdown为html的loader

分三步:

  1. 在webpack.config.js 配置loader,传入option参数
  2. 编写loader,每一个loader都是一个函数,source为传入资源。这个函数的返回结果要么是二进制数据要么是字符串,字符串就是文件的具体内容(为Javascript),二进制数据就是资源文件比如图片的内容。
// webpack.config.js 配置loadertest/\.md$/,
  use: [
          { loader'./markdown-loader'options: { headerIdsfalse }}
      ]
 }
 
 
 // 编写loader
 // markdown-loader.js
 const marked = require("marked");
 function markdownLoader(source) {
    const options = this.query; // 获取loader参数 { headerIds: false }
    
    另一种options获取方法:
    const schema = {
        type'object'//options是一个对象
        properties: {
            headerIds: {
                type'boolean'
            },
        }
    }
    const options = this.getOptions(schema) || {}
    
    // 处理
    const html = marked.marked(source, options); // 使用marked插件转换为html
    const code = `module.exports = ${JSON.stringify(html)}` 
    return code; // 传出Javascript
  }
  module.exports = markdownLoader;
  
  
 // html引用
 import html from './markdown.md';
 document.getElementById("root").innerHTML = html;