自定义 loader

CSS loader loader 必须返回 JS 文件,入参 source 可能是任意文件的字符串。 入参分别是:上一个 loader 处理后的源码、映射和抽象语法树 处理 css 文件: function hash() {  return Math.random().toString(36).substring(2, 8);}module.exports = function (source, map, meta) {  const options = getOptions(this);  const reg = /(?<=.)(.?)(?={)/g;  const classKeyMap =    Object.fromEntries(      source.match(reg).map(str => [str.trim(), str.trim()])    );  const cssHashMap = new Map();  source = source.replace(reg, (result) => {    const key = result.trim();    const cssHash = hash();    cssHashMap.set(key, cssHash);    return ${key}-${cssHash}  });  Object.entries(classKeyMap).forEach((item) => {    classKeyMap[item[0]] = item[1] + '-' + cssHashMap.get(item[0]);  });  return /**__CSS_MODULE__${source}*//**__CSS_classKeyMap__${JSON.stringify(classKeyMap)}**/;} 返回值处理: loader 要求只能返回一个内容 如果要返回多个内容,我们可以添加注释 /**模块名${xx}/ 来标记返回 loader.pitch loader.pitch方法中有三个参数,分别是remainingRequest、previousRequest和data remainingRequest:剩余的请求 previousRequest:前面的请求 data:数据 remainingRequest剩余的请求就是当前loader后面(不含当前)的loader和file的路径用感叹号’!'拼接,类型是字符串。 previousRequest前面的请求就是当前loder之前(不含当前)的loader的路径用感叹号’!'拼接,类型是字符串。 data数据其实是一个空对象{},给loader内部存放数据使用的。 处理样式文件的 loader 顺序:less-loader -> css-loader -> style-loader less-loader less-loader的原理):主要是借助less模块的render方法,将less语法进行转换成css语法,然后返回或者额调用this.callback()传递给下一个loader。 css-loader 其实less-loader已经转成css了,但是有些语法比如import、url还尚未处理,所以这个css-loader就是用来处理import、url等语法的,功能比较单一。 style-loader 返回 js 字符串: module.export = ${JSON.stringify())} module.exports = function (source) {  const cssSource = source.match(//**__CSS_MODULE__*//g);  const classKeyMapSource = source.match(//**__CSS_classKeyMap__*//g);  let script =     var style = document.createElement('style');    style.innerHTML = ${JSON.stringify(cssSource)};    document.head.appendChild(style);  ;  if (classKeyMap) {    // 因为是通过 import style from './color.css' 引入的, 所以 loader 需要导出一个对象    script +=       module.exports = ${classKeyMap}};    ;  }  return script;}

补充

补充:loader 规范要点:

  • module.exports = function (source, sourceMap?, meta?) { ... } 同步版本,return 处理结果。
  • 异步版本:const callback = this.async() → 处理完后 callback(err, content, map, meta)。
  • 不能使用箭头函数(丢失 this 上下文);不能在 loader 中保存模块级状态(会破坏缓存)。
  • 常用 API:this.context(资源目录)、this.resourcePath(资源绝对路径)、this.addDependency(path)(让 webpack 监听依赖文件)、this.emitFile / this.utils.absolutify。
  • 风格链:less-loader → postcss-loader → css-loader → style-loader,loader 顺序从右到左。

来源整理自:我的有道云笔记