有些配置项,我们希望在 webpack 打包后也能方便修改,比如接口地址、第三方链接等。
最近做的一个项目遇到了这样的需求,其实思路很简单,在 HTML 文件的 head 中引入一个 JS 文件,JS 文件往 window 添加全局对象,里面就是各种配置字段,开发的时候直接通过 window 使用这些配置即可。
然后在打包的时候通过 copy-webpack-plugin 复制这个 JS 文件到正确的位置即可。
可是在开发过程中也遇到了一点小问题:
<script src="./gConfig.js"></script>
一开始就很简单的在 head 中通过 script 标签引入,但是却有一个问题——缓存。当我们修改了 gConfig.js 里的配置后,浏览器有缓存,需要强刷才能更新。
为了解决这个缓存问题,可以通过添加版本号,如:
<script src="./gConfig.js?v=1"></script>
不过如果是给运维等人员修改,修改了 js 的配置后还得改 html 的版本号,有点麻烦。
之后理所当然的就是想到添加随机数,可是该怎么添加呢?
在内联 JS 中使用 document.createElement('script') 然后生成随机数,最后 append 到 head 中吗?
<script>
const scr = document.createElement('script')
scr.src = `./gConfig.js?${Math.random()}`
document.head.append(scr)
</script>
<script>
console.log(123, window.gConfig)
</script>
然而通过这种方式得到的是 undefined,因为 DOM 操作是跨线程的,不会阻塞运行。
那么就没办法了吗?这时就需要 document.write 出场了:
<script>
document.write("<script src='./gConfig.js?"+Math.random()+"'></script>")
</script>
<script>
console.log(123, window.gConfig)
</script>
当我们使用 document.write 写入 script 标签,下面的 console 就能得到正确的输出结果。因为浏览器执行到 document.write 的时候,就会立即往文档流中写入内容,写入完成后浏览器才会继续解析。这里继续解析就解析到我们写入的 script 标签了,然后解析我们的 gConfig.js 再继续,流程就正确了。