webpack-chain 速查手册之 ChainedMap

2021-04-27  本文已影响0人  AizawaSayo

webpack-chain GitHub 中文文档
webpack-chain 速查手册之 ChainedSet

Set 和 Map 数据类型

Set 是一组值的集合,值允许任何类型,但不可以重复。会记住元素原始插入顺序所以是可迭代的。如果传入重复元素,会在Set中自动被过滤,可以利用Set来去重。
初始化Set需要传入一个数组,或者直接初始化空Set:new Set()

var s = new Set([1, 2, 3, 2, 1, '哈哈'])
console.log(s) // Set(2) {1, 2, 3, '哈哈'} 自动去除重复项
s.add(4) // 添加新元素 4 
s.delete(3) // 删除元素 3
s.has(3) // 是否存在元素 3:false 
s.clear() // 移除s中所有项

Map以[键,值]的形式存储数据,并且能够记住键的原始插入顺序。键和值允许任何数据类型,键不可重复是惟一的,可以极高效地查找数据。
初始化Map需要传一个二维数组,或者直接初始化一个空Map:new Map()

var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]])
console.log(m) // Map(3) {"Michael" => 95, "Bob" => 75, "Tracy" => 85}
m.set('Adam', 67); // 添加新的key-value
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.clear() // Map {}  

获取它们的元素个数的属性是size,如:

console.log(new Set([1,2,1,2]).size) // 2 

它们都拥有遍历方法:

console.log(new Set([1,2,3,4]).values()) // SetIterator {1, 2, 3, 4}
console.log(new Set([1,2,3,4]).entries()) // SetIterator {1 => 1, 2 => 2, 3 => 3, 4 => 4}
console.log(new Map([['name','jackson'],['age',11]]).keys()) // MapIterator {"name", "age"}
new Map([['name','jackson'],['age',11]]).forEach((value, key) => { console.log(key, value)} )  
// name jackson
// age 11

ChainedMap的API和方法:

操作类似于JavaScript Map。除非另有说明,否则这些方法将返回 ChainedMap , 允许再链式调用这些方法。

// 从 Map 移除所有 配置.
clear()

// 通过键值从 Map 移除单个配置.
// key: *
delete(key)

// 获取 Map 中相应键的值
// key: *
// returns: value
get(key)

// 获取 Map 中相应键的值
// 如果键在Map中不存在,则ChainedMap中该键的值会被配置为fn的返回值.
// key: *
// fn: Function () -> value
// returns: value
getOrCompute(key, fn)

// 配置Map中 已存在的键的值
// key: *
// value: *
set(key, value)

// Map中是否存在一个配置值的特定键,返回 真或假
// key: *
// returns: Boolean
has(key)

// 返回 Map中已存储的所有值的数组
// returns: Array
values()

// 返回Map中全部配置的一个对象, 其中 键是这个对象属性,值是相应键的值,
// 如果Map是空,返回 `undefined`
// 使用 `.before() 或 .after()` 的ChainedMap, 则将按照属性名进行排序。
// returns: Object, undefined if empty
entries()

//  提供一个对象,这个对象的属性和值将 映射进 Map。
// 你也可以提供一个数组作为第二个参数以便忽略合并的属性名称。
// obj: Object
// omit: Optional Array
merge(obj, omit)

// 对当前配置上下文执行函数。
// handler: Function -> ChainedMap
  // 一个把ChainedMap实例作为单个参数的函数
batch(handler)

// 条件执行一个函数去继续配置
// condition: Boolean
// whenTruthy: Function -> ChainedMap
  // 当条件为真,调用把ChainedMap实例作为单一参数传入的函数
// whenFalsy: Optional Function -> ChainedMap
  // 当条件为假,调用把ChainedMap实例作为单一参数传入的函数
when(condition, whenTruthy, whenFalsy)

被标记为ChainedMap的属性

const path = require('path')
config.set('context', path.resolve(__dirname, '.')) // 设置 webpack 上下文目录为项目根目录

配置速记方法:可以用键名作为方法名为ChainedMap设置一个值,从而简化ChainedMap.set(键, 值)方法

// 在 ChainedMap 上设置一个值的 速记方法
config.mode('development') // 告诉 webpack 使用开发环境模式优化
// 等效于:
config.set('mode', 'development')

end()方法可以让我们回到上一级API实例
链式调用时我们会移动到API的下一级甚至更深层,这会更改当前的上下文。编写规范是到下一层遍缩进一个tab,同一层级缩进空格相等。如果想回到上一层级继续链式调用上级API的方法,调用** .end()**即可实现。因为全部的API调用都将在当前上下文中返回该API实例,关于webpack配置项层级关系请参阅 webpack文档层级结构

举例:

config.module
  .rule('vue')
    .test(/\.vue$/)
    .use('cache-loader') // use 和 test 同级,都是 rule 下级 API
      .loader(require.resolve('cache-loader'))
      .end() // 调用end() 由回到 rule API 层级
    .use('vue-loader')
      .loader(require.resolve('vue-loader'))
config.
  output
    .path(path.join(__dirname, 'dist')) // 设置打包输出的目录为根目录的 dist 
config.resolve.alias
  .set('@', path.join(__dirname,'src'))
  .set('@utils', path.join(__dirname,'src/utils'))
  .delete('@api')
  .clear()
config.performance
  .hints('error')
  .maxEntrypointSize(400000)
  .maxAssetSize(100000)
  .assetFilter(assetFilename => assetFilename.endsWith('.js'))
// Minimizer 使用插件时可以通过它们的路径指定,从而允许在不使用插件或webpack配置的情况下跳过昂贵的 require
config.optimization
  .minimizer('css')
  .use(require.resolve('optimize-css-assets-webpack-plugin'), [{ cssProcessorOptions: { safe: true }

// 修改参数
config.optimization
  .minimizer('css')
  .tap(args => [...args, { cssProcessorOptions: { safe: false } }])

// 修改实例
config.optimization
  .minimizer('css')
  .init((Plugin, args) => new Plugin(...args))

// 移除
config.optimization.minimizers.delete('css')

顺便提下 when(condition, whenTruthy, whenFalsy) 的用法:

// 在生产环境中添加缩小插件,非生产环境devtool到源映射
config
  .when(process.env.NODE_ENV === 'production',
    config => {
      const terserOptions = require('./terserOptions')
      config.optimization
        .minimizer(terser)
          .use(require.resolve('terser-webpack-plugin'), [terserOptions(options)])  
    },
    config => config.devtool('source-map')
  )
// 添加
config
  .plugin('env')
  .use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ 'VAR': false }])

// 修改参数
config
  .plugin('env')
  .tap(args => [...args, 'SECRET_KEY'])

// 修改实例
config
  .plugin('env')
  .init((Plugin, args) => new Plugin(...args))

// 移除
config.plugins.delete('env')

// 指定当前插件上下文应该在另一个指定插件之前执行
config
  .plugin('html-template')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin)
    .before('html-template')

// 指定当前插件上下文应该在另一个指定插件之后执行
config
  .plugin('html-template')
    .after('script-ext')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin)
config.node
  .set('__dirname', 'mock')
  .set('__filename', 'mock')
config.node
  .set('__dirname', 'mock')
  .set('__filename', 'mock')
// 不解析的模块
config.module
  .noParse(/^(vue|vue-router|vuex|vuex-router-sync)$/)

.tap()修改这个接口很实用,特别适合当在别处已经有做过某规则(如.rule(name))的配置时,不方便去原文件修改,直接修改loader配置的情况,也可以同时链式加其他loader。比如覆盖框架的默认webpack配置。

// 创建
config.module
  .rule('compile')
    .use('babel')
      .loader('babel-loader')
      .options({ presets: ['@babel/preset-env'] })

// 修改选项
config.module
  .rule('compile')
    .use('babel')
      .tap(options => merge(options, {
        plugins: ['@babel/plugin-proposal-class-properties']
      }))
// 速记格式解读
config.module
  .rule(name)
    .test(test)
    .pre() // 指代 .use(loader-name-pre)
    .post() // 指代另一个 .use(loader-name-post)
    .enforce(preOrPost) // 值为'pre' 则表示先执行上面的loader,即loader-name-pre;值为'post' 则先执行下方的loader,loader-name-post
// 本来必须把 image-webpack-loader 配置在后面才能先执行
// 用 enforce('pre') 手动设置先执行上面的 loader
config.module
  .rule('images')
    .use('image-webpack-loader') // 在前面表示 pre
      .loader('image-webpack-loader')
      .options({...})
      .end()  //回到use同层级
    .use('url-loader') // 在后面表示 post
      .loader(require.resolve('url-loader'))
      .options({...})
      .end()
    .enforce('pre') // 先执行上面的 image-webpack-loader
config.module
  .rule('css')
    .oneOf('inline')
      .resourceQuery(/inline/)
      .use('url')
        .loader('url-loader')
        .end()
      .end()
    .oneOf('external')
    .before('inline')
      .resourceQuery(/external/)
      .use('file')
        .loader('file-loader')
上一篇下一篇

猜你喜欢

热点阅读