必须知道的loader基础知识

175 阅读1分钟

lodader 基础

loader 分为inline,pre,normal,post loader

  • inline 内联laoder写法 import 'style-loader!css-loader!./style.css',用!号分割

内联loader在前面加前缀,表示禁止webpack.config.js配置的loader执行

加 !  表示禁止normal loader执行  import '!style-loader!css-loader!./style.css'

加 -! 表示禁止 pre 和 normal loader 执行 import '-!style-loader!css-loader!./style.css'

加 !! 表示禁止 pre 和 normal、post loader 执行 import '!!style-loader!css-loader!./style.css'
  • loader执行顺序 inline > pre > normal > post,从右到左,从下到上

对js文件匹配到后,都会执行下面loader,不是只执行一个

下面执行顺序是 B -> babel-loader -> D -> A

{
    module:{
        rules:[
            {
                test: /\.js$/,
                use: ['D-loader']
            },
            {
                test: /\.js$/,
                use: ['babel-loader']
            },
            {
                test: /\.js$/,
                enforce: 'post',
                use: ['A-loader']
            },
            {
                test: /\.js$/,
                enforce: 'pre',
                use: ['B-loader']
            }
        ]
    }
}

loader 是一个函数,参数code,map,meta

  • code 是上一个loader返回字符串

  • map是sourcemap

  • meta是上一个传递下来的参数

module.exports = function(code,map,meta){
    return code
}

同步this.callback和异步this.async()

  • this.callback 是同步,或者直接return

  • this.async 返回函数是异步

// 同步
module.exports = function(code,map,meta){
    this.callback(null,code,map,meta)
}
// 异步
module.exports = function(code,map,meta){
    const callback = this.async()
    setTime(()=>{
        callback(null,code,map,meta)
    },2000)
}

静态属性 raw 表示获取buffer数据

// raw 设置了,那code是buffer格式
module.exports = function MyLoader(code,map,meta){
    this.callback(null,code,map,meta)
}

MyLoader.raw = true

pitch loader 从左往右执行,返回数据后熔断后续loader

vue-loader 和 style-loader 原理就是用到 pitch vue-loader原理基本实现

function MyLoader(code,map,meta){
    this.callback(null,code,map,meta)
}

MyLoader.pitch = function(){

}
module.exports = MyLoader

image.png

常用api

  • this.async 异步调用回调 用法 const callback = this.async()

  • this.callback 同步调研回调 用法 this.callback(error,content,sourceMap?,meta?)

  • this.getOptions(schema) 获取loader的options 用法 this.getOptions(schema)

  • this.emitFile 产生一个文件 用法 this.emitFile(name,content,sourceMap)

  • this.utils.contentify 返回一个相对路径 用法 this.utils.contentify(context, request),别用path

  • this.utils.absolutify 返回一个绝对路径 用法 this.utils.absolutify(context, request),别用path

小技巧:

loader返回字符串用JSON.stringify包装转移为标准字符串

module.exports = function(code){
    return `module.exports = ${JSON.stringify(code)}`
}

loader 笔记

  • mark md文件转html

  • html-loader html内容转js

style-loader 例子

/**
 1、直接使用style-loader,只能处理样式,不能处理样式中引入的其他资源
    use: ['./loaders/styleLoader.js']

 2、借助
 */
//  const schema = {
//     type: "object",
//     properties: {
//       presets: {
//         type: "array",
//       },
//     },
//     addtionProperties: true,
// };

function styleLoader(content) {
//   const options = this.getOptions(schema);
  return content;
}

styleLoader.pitch = function (remainRequest) {
  // remainRequest  c:/work/css-loader/dist/cjs.js!c/work/css/index.css
  const loaderContext = this;

  // 1、将绝对路径改为相对路径,因为后面只能使用相对路径
  const relativePath = remainRequest
    .split("!")
    .map((absolutePath) => {
      // 返回相对路径
      return loaderContext.utils.contextify(
        loaderContext.context,
        absolutePath
      );
    })
    .join("!");

  // 2、引入css-loader处理后的资源,创建style标签插入样式生效
  // 使用 !! 终止配置中css-loader执行
  const script = `
        import style from '!!${relativePath}';
        const styleEl = documeng.createElement('style');
        styleEl.innerHTML = style;
        document.body.appendChild(styleEl)
    `;

  return script;
};

module.exports = styleLoader;