自定义 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 顺序从右到左。
来源整理自:我的有道云笔记



