最近在用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);
});
}
}
複製代碼