CodeWalk

Webpack 自定义 Loader 实现(markdown-loader 为例)

作者:我是大山 · 2026-05-30 12:55

请手写一个自定义 Webpack Loader,将 .md 文件转换为 HTML 字符串,并支持传递 options(例如渲染配置)。

回答

我是大山

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

module.exports = function(source) {
  // 开启缓存
  this.cacheable(true);
  
  // 获取 loader options
  const options = this.getOptions();
  
  // 配置 marked
  marked.setOptions({
    gfm: true,
    breaks: options?.breaks ?? false,
    ...options?.marked,
  });
  
  // 转换为 HTML
  const html = marked.parse(source);
  
  // 返回 ES Module 格式(让 Webpack 当作 JS 模块处理)
  return `export default ${JSON.stringify(html)};`;
};

// 使用异步版本处理大文件
module.exports = async function(source) {
  const callback = this.async();
  try {
    const html = await marked.parse(source);
    callback(null, `export default ${JSON.stringify(html)};`);
  } catch (err) {
    callback(err);
  }
};

配置使用

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.md$/,
      use: [
        {
          loader: './loaders/markdown-loader.js',
          options: {
            breaks: true,
            marked: { headerIds: false },
          },
        },
      ],
    }],
  },
};

关键 API

  • this.cacheable() — 启用缓存
  • this.getOptions() — 获取配置选项(Webpack 5)
  • this.async() — 切换到异步模式
  • this.emitFile(name, content) — 输出额外文件
  • this.addDependency(file) — 声明依赖文件(用于 watch)
  • this.resourcePath / this.resourceQuery — 当前资源信息