build: add remote-only mode lang package stub and replacement logic
add empty-lang-stub.js to stub lang package files in remote-only mode, add webpack plugin logic to replace lang files with stub to reduce bundle size
This commit is contained in:
15
common/js/empty-lang-stub.js
Normal file
15
common/js/empty-lang-stub.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// ============================================================
|
||||
// 空 lang 包占位
|
||||
//
|
||||
// 在 source === 'remote-only' 模式下, lang/ 目录下的所有 .js 会被
|
||||
// webpack.NormalModuleReplacementPlugin 替换为这个 stub.
|
||||
//
|
||||
// 设计要点:
|
||||
// - 导出 default 对象, 结构与真实 lang 包一致: { lang: {...} }
|
||||
// - lang 字段是空对象, 让 lang() 函数 fallback 路径不报错
|
||||
// - 不导出 named export, 避免 tree-shaking 把整个 stub 干掉
|
||||
// ============================================================
|
||||
|
||||
export default {
|
||||
lang: {}
|
||||
};
|
||||
@@ -90,6 +90,66 @@ function _readManifestBase(manifestPath) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 langConfig.source, 用于构建期判断是否启用 lang/ 排除策略
|
||||
* 用 fs 静态解析, 避免 webpack 把整个 config-external.js 链入 vue.config 编译路径
|
||||
*/
|
||||
function _readLangSource() {
|
||||
try {
|
||||
const content = fs.readFileSync(path.join(__dirname, 'common/js/config-external.js'), 'utf-8');
|
||||
const match = content.match(/source:\s*['"]([\w-]+)['"]/);
|
||||
return match ? match[1] : null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用Webpack的资源替换插件
|
||||
*/
|
||||
class NormalModuleReplacementPlugin {
|
||||
constructor(resourceRegExp, newResource) {
|
||||
this.resourceRegExp = resourceRegExp;
|
||||
this.newResource = newResource;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
const resourceRegExp = this.resourceRegExp;
|
||||
const newResource = this.newResource;
|
||||
|
||||
compiler.hooks.normalModuleFactory.tap(
|
||||
"NormalModuleReplacementPlugin",
|
||||
nmf => {
|
||||
nmf.hooks.beforeResolve.tap("NormalModuleReplacementPlugin", result => {
|
||||
if (!result) return;
|
||||
if (resourceRegExp.test(result.request)) {
|
||||
if (typeof newResource === "function") {
|
||||
newResource(result);
|
||||
} else {
|
||||
result.request = newResource;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
nmf.hooks.afterResolve.tap("NormalModuleReplacementPlugin", result => {
|
||||
if (!result) return;
|
||||
if (resourceRegExp.test(result.resource)) {
|
||||
if (typeof newResource === "function") {
|
||||
newResource(result);
|
||||
} else {
|
||||
result.resource = path.resolve(
|
||||
path.dirname(result.resource),
|
||||
newResource
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 webpack 插件:在通用产物(vendor.js)中内联注入版本数据
|
||||
* 利用 emit 钩子在资源写入磁盘前处理,支持 HMR(每次重编译都会自动注入)
|
||||
@@ -352,9 +412,36 @@ class VersionInjectPlugin {
|
||||
|
||||
// 导出配置
|
||||
module.exports = {
|
||||
productionSourceMap: false,
|
||||
configureWebpack: config => {
|
||||
console.log('config.mode = ', config.mode);
|
||||
productionSourceMap: false,
|
||||
configureWebpack: config => {
|
||||
console.log('config.mode = ', config.mode);
|
||||
|
||||
// lang/ 目录排除: 仅在 remote-only 模式下生效
|
||||
// 原理: webpack 把 require(`@/lang/${lang}/${path}.js`) 解析为 ContextModule,
|
||||
// 会扫描并打包 lang/ 下所有 .js. 替换为 stub 后, 真正的 lang 文件不进 bundle.
|
||||
// 条件: source === 'remote-only' (由 common/js/config-external.js 配置)
|
||||
const langSource = _readLangSource();
|
||||
if (langSource === 'remote-only') {
|
||||
try {
|
||||
const webpack = require('webpack');
|
||||
const stubPath = path.resolve(__dirname, 'common/js/empty-lang-stub.js');
|
||||
console.log(`[vue.config] config.plugins.length = ${config.plugins.length}`);
|
||||
if (webpack?.NormalModuleReplacementPlugin){
|
||||
config.plugins.push(
|
||||
new NormalModuleReplacementPlugin(
|
||||
// 匹配解析后的绝对路径: .../lang/xxx/yyy.js
|
||||
/[\\/]lang[\\/].+\.js$/,
|
||||
stubPath
|
||||
)
|
||||
);
|
||||
console.log(`[vue.config] ✅ lang/ 目录已替换为 stub (source=remote-only) — 节省 lang 包体积`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[vue.config] 配置 lang/ 排除失败:', e.message);
|
||||
}
|
||||
} else {
|
||||
console.log(`[vue.config] lang/ 目录保留 (source=${langSource || 'unknown'})`);
|
||||
}
|
||||
|
||||
if (config.mode === 'production') {
|
||||
console.log('开始尝试配置极限压缩');
|
||||
|
||||
Reference in New Issue
Block a user