Bulk-Replacing Domains in a Frontend Codebase
We ship both CN and international sites from one codebase. Historically we hardcoded CN links and let a 302 redirect to the international domain. That redirect was disabled, so we needed to replace scattered hardcoded domains with a dynamic variable, e.g.,
https://1991421.cn/...
→https://${window.basicHost}/...
. How to do this cleanly?
Plain regex search/replace?
首先,想到的是直接的正则替换,但是尝试了下发现并不行,原因是ES6加下的代码写法种类太多,且这个问题根本上来说是将常量改成了变量拼接,因此直接文本替换是不行的。
Examples: link strings appear in various contexts
href="https://1991421.cn/2021/09/21/844e39cc/"
href="//1991421.cn/2021/09/21/844e39cc/"
href={`//1991421.cn/2021/09/21/${postId}`}
getUrl(`//1991421.cn/2021/09/21/${postId}`)
AST + regex replacement
直接正则替换无法解决的直接原因是写法的不同,但是如果在代码编译到ES5后,写法即固定了,一定是单独的字符串,比如"//1991421.cn/2021/09/21/"+ postId。而这个时间点可以在webpack中很容易找到找到,比如compilation.hooks.optimizeChunkAssets
。
At this stage regex can replace strings, but you also need to handle surrounding quotes and build concatenations with variables. Pure regex gets messy; AST makes it straightforward by analyzing JS syntax and locating string literals properly. This leads to writing a webpack plugin.
Implementation
Webpack plugin
因为最终是将JS代码进行解析转为AST,从而正则替换部分字符串,因此webpack插件来做最为合适。
具体插件可以在这里下载使用
- webpack插件部分,根据webpack暴露的hook选择chunk生成后的hook即可。
- 获取chunk源码,做AST解析从而实现替换即可。
Core replacement logic:
function replaceDomainLoader(source) {
const tokenization = esprima.tokenize(source);
tokenization.forEach((item) => {
if (item.type !== 'String') return;
const mark = item.value.charAt(0); // 获取字符串的标签
const {value} = item;
let res = value;
replaceQueue.forEach((obj) => {
res = res.replace(obj.reg, `${mark} + ${obj.value} + ${mark}`);
});
if (value === res) return;
source = source.replace(value, res);
});
return source;
}
HMR caveat
当前如果是开发模式- HMR下会出现替换错误,因此建议插件增加环境判定,比如
...
process.env.NODE_ENV === 'production' && new DomainReplacePlugin()
...
For local production builds, set env vars reliably, e.g., with cross‑env:
npx cross-env NODE_ENV=production npm run build:dev
Final Thoughts
This approach keeps business code clean while making domain handling flexible across CN/intl sites.