最近在用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);
});
}
}
复制代码