【webpack构建优化】——编写enhanced-resolve插件

背景

最近在用webpack-bundle-analyzer包分析构建产物的时候发现soundmanager2的体积比较大。因而我在node_modules里面找了下soundmanager2的代码,发现默认导出的文件是带调试功能的未压缩版本。若是能够在最终构建包里面使用soundmanager2-nodebug-jsmin.js版本的话体积会小不少。node

图片

动手

基于以前的经验,我知道webpack是用enhanced-resolve来解析模块滴,在github上找到enhanced-resolve,没找到啥有用的信息,搜索了一番无果以后只好去看enhanced-resolve源码了,还好源码很少,看起来不是很累。具体怎么看代码的过程就不在这逼逼了,下面直接放解决方案。webpack

使用

// webpack.config.js
module.exports={
    resolve: {
        plugins: [
          new ReplaceModuleResolvePlugin({
            sourceModule: 'soundmanager2',
            destModule: 'soundmanager2-nodebug-jsmin.js',
          }),
        ],
      },
};
复制代码

插件源码

// utils.ts
export function cached(fn: Function) {
  const cache = Object.create(null);
  return function(str: string) {
    const hit = cache[str];
    // eslint-disable-next-line no-return-assign
    return hit || (cache[str] = fn(str));
  };
}

const extensionPattern = /\.(\w+)(?:$|\?.*)/;
export const getExtension = cached(function(path: string) {
  const result = path.match(extensionPattern);
  if (result && result[1]) {
    return result[1];
  }
  return '';
});
复制代码
// ReplaceModuleResolvePlugin.ts
import { getExtension } from '../utils';

export interface ReplaceModuleOptions {
  sourceModule: string;
  destModule: string;
}

function ensureExtension(path: string, extension: string) {
  if (getExtension(path) !== '') {
    return path;
  }
  return `${path}.${extension}`;
}

// 构建时替换module
export class ReplaceModuleResolvePlugin {
  options: ReplaceModuleOptions;

  constructor(options: ReplaceModuleOptions) {
    this.options = options;
  }

  apply(resolver) {
    const { sourceModule, destModule } = this.options;
    const sourceModuleRegExp = new RegExp(sourceModule);

    resolver.getHook('existing-file').tapAsync('ReplaceModuleResolvePlugin', (request, resolveContext, callback) => {
      const innerRequest: string = request.request || request.path;

      if (!sourceModuleRegExp.test(innerRequest)) {
        return callback();
      }

      const extension = getExtension(innerRequest);

      const obj = {};
      Object.keys(request).forEach(key => {
        const val = request[key];
        if (typeof val === 'string') {
          obj[key] = val.replace(ensureExtension(sourceModule, extension), ensureExtension(destModule, extension));
        } else {
          obj[key] = val;
        }
      });

      return resolver.doResolve('resolved', obj, `ReplaceModuleResolvePlugin 使用目标模块${destModule}`, resolveContext, callback);
    });
  }
}
复制代码
相关文章
相关标签/搜索