webpack随笔

webpack官网

手写Loader

注意:loader 的执行是从后 ->前。从右 -> 左

// loader就是一个函数
module.exports = function (source) {
    // return source.replace('loader', 'webpack')
     return source.replace('loader', this.query.name)
     // this.query获得options 传来的数据
     
}
//loader 可以通过 options 对象配置(仍然支持使用 query 参数来设置选项,但是这种方式已被废弃)。
  • loader函数一定得是声明式函数,不能是箭头函数,因为webpack在运行loader的时候,会涉及到this指向的变更,箭头函数的话,是不满足的
  • loader 函数接受source为一个参数,意思是源代码,我们拿到原代码后,就可以对源代码做一些相应的操作了

使用自己写的loader

module.exports = {
    module: {
        rules: [
            {
                test: /\.js/,
                use: [path.resolve(__dirname, './loaders/replaceLoader.js')]
                 options: {
                        name: 'hello'
                    }
            }
        ]
    },
}
const loaderUtils = require('loader-utils')
module.exports = function (source) {
    const options = loaderUtils.getOptions(this)
    // loaderUtils.getOptions(this) 获取option 传过来的参数
    const result = source.replace('loader', options.name)
    this.callback(null, result)
    // callback,我们看上面的代码,只是返回了一个替换后的结果,想返回其他值的话,我们就需要用到callback了
}
// callback 有四个参数
this.callback(
  err: Error | null, // 错误信息
  content: string | Buffer, // 最终生成的源码
  sourceMap?: SourceMap, // 对应的sourcemap
  meta?: any // 其他额外的信息
);

在loader里面写异步

const loaderUtils = require('loader-utils')
module.exports = function (source) {
    const options = loaderUtils.getOptions(this)
    const callback = this.async()
    setTimeout(() => {
        const result = source.replace('loader', options.name)
        // this.callback(null, result)
        callback(null, result) // 实际上为this.callback
    }, 1000)
}

resolveLoader
我们现在使用自定义的loader还是采用的,很长的一段绝对路径来应用的,但实际上,我们更希望像使用第三方loader那样,只引用一个loader名字,
我们知道,webpack 默认会到 node_modules 里面找对应的loader,这样不方便我们调试,我们可以通过给webpack.config.js添加resolveLoader属性,将loader指向我们创建的loaders文件夹

resolveLoader: {
    modules: [
      path.resolve(__dirname, "node_modules"),
      path.resolve(__dirname, "./loaders"),
    ],
  }

意识是,当你去引用一个loader的时候,会优先到node_moudules里面去找,找不到才会去我们自己的loader文件下面去找,这样配置后,我们的自定义loader就可以这样配置了

module.exports = {
    module: {
        rules: [
            {
                test: /\.js/,
                use: [{
                    loader: 'loaders/replaceLoader',
                    options: {
                        name: 'hello'
                    }
                }]
            }
        ]
    }

校验配置参数是否正确 schema-utils

const fs = require("fs");
const {resolve} = require("path");
const loaderUtils = require("loader-utils");
const { validate } = require("schema-utils");

module.exports = function (source) {
    // 获取配置参数
    let options= loaderUtils.getOptions(this);
    let schema = {
      type: "object",
      properties: {
        text: {type: "string"}
     } 
    }
    // 校验参数是否正确
    validate(schema, options,"banner-loader")

    return `${options.text} ${source}`;
}

SourceMap

SourceMap是一种映射关系。当项目运行后,如果出现错误,错误信息只能定位到打包后文件中错误的位置。如果想查看在源文件中错误的位置,则需要使用映射关系,找到对应的位置

如果在开发环境下:

mode: "development"
devtool: "cheap-module-eval-source-map"
// 提示方式比较全面,同时打包速度也是比较快的
// 生产环境下一般不用配置SourceMap,但如果出了问题想要提示,如下配置
mode: "production"
devtool: "cheap-module-source-map"

oneOf

webpack原本的loader是将每个文件都过一遍,比如有一个js文件 rules中有10个loader,第一个是处理js文件的loader,当第一个loader处理完成后webpack不会自动跳出,而是会继续拿着这个js文件去尝试匹配剩下的9个loader,相当于没有break。而oneOf就相当于这个break

rules:[
            oneOf:[
                {
                    test:/\.css$/,
                    use:[...common_css_loader]
                },
                {
                    test:/\.less$/,
                    use:[...common_css_loader,'less-loader']
                },
                {
                    test:/\.html/,
                    loader:'html-loader'
               	}
           		]
        ]

enforce

loader的执行顺序是从下往上的,但是有时候我们想先执行某个loader 就要把它移到最后边这样非常的不方便。
enforce的作用是设置loader的优先级
enforce有以下几个配置项

  • pre 优先处理
  • normal 正常处理(默认)
  • inline 其次处理
  • post 最后处理

执行loader的时候会根据enforce的配置来安排顺序,如果设置了pre则会优先执行

resourceQuery

用来测试通过import/require引入的模块参数是否符合要求
在这里插入图片描述

// 使用resource方式配置,还有or、and、not属性可以配置,完整的如下
// 匹配规则
module: {
  rules: [{
    use: ['babel-loader],
    resource: {
      test: /\.js$/,
      exclude: [],
      include: [],
      not: [],
      and: [],
      or: []
    }
  }]
}

optimization

optimization.splitChunks

/**
   * webpack中实现代码分割的两种方式:
   * 1.同步代码:只需要在webpack配置文件总做optimization的配置即可
   * 2.异步代码(import):异步代码,无需做任何配置,会自动进行代码分割,放置到新的文件中
   */
  optimization: {
    splitChunks: {
      chunks: "all",    //async异步代码分割 initial同步代码分割 all同步异步分割都开启
      minSize: 30000,    //字节 引入的文件大于30kb才进行分割
      //maxSize: 50000,     //50kb,尝试将大于50kb的文件拆分成n个50kb的文件
      minChunks: 1,        //模块至少使用次数
      maxAsyncRequests: 5,    //同时加载的模块数量最多是5个,只分割出同时引入的前5个文件
      maxInitialRequests: 3,  //首页加载的时候引入的文件最多3个
      automaticNameDelimiter: '~', //缓存组和生成文件名称之间的连接符
      name: true,                  //缓存组里面的filename生效,覆盖默认命名
      cacheGroups: {    //缓存组,将所有加载模块放在缓存里面一起分割打包
        vendors: {     //自定义打包模块
          test: /[\\/]node_modules[\\/]/,
          priority: -10,    //优先级,先打包到哪个组里面,值越大,优先级越高
          filename: 'vendors.js',
        },
        default: { //默认打包模块
          priority: -20,
          reuseExistingChunk: true, //模块嵌套引入时,判断是否复用已经被打包的模块
          filename: 'common.js'
        }
      }
    }
  }

ptimization.runtimeChunk

runtimeChunk作用是为了线上更新版本时,充分利用浏览器缓存,使用户感知的影响到最低

Preload和Prefetch的区别

  • 一个预加载块(preload)开始与父块并行加载。预取的块(prefetch)在父块完成加载后启动。
  • 预加载块(preload)具有中等优先级,可以立即下载。而预取块(prefetch)在浏览器空闲时下载预取的块。
  • 一个预加载的块(preload)应该被父块立即请求。预取的块(prefetch)可以在将来的任何时候使用。
  • 浏览器的支持能力是不同的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值