Webpack之多CDN域名解决方案

1,961 阅读3分钟

诉求

同一个前端项目,支持多个不同域名访问,不同访问域名需要使用不同的cdn域名。举例来说使用使用a.com、b.com、c.com访问页面,对应的cdn域名为,a.cdn.com、b.cdn.com、c.cdn.com。

方案

1. 不同页面域名对应不同 CDN 域名

页面访问域名和CDN域名做一个映射,根据页面访问域名动态获取对应的CDN域名。如果是Node直接html形式,直接注入一个全局变量,和拼装首页依赖的静态资源

2. 如何正确设置异步加载js文件的cdn域名

在 webpack中,异步加载的js都是通过 lib/web/JsonpMainTemplatePlugin.js 加载的,异步组件首要条件是拼接资源的路径: 项目代码编译的形式为: 拼接路径时会使用到一个变量 __webpack_require__.p, 如果可以动态修改这个变量,即可动态改变静态资源的加载前缀, 这个路径可以通过在代码中设置__webpack_public_path__变量以修改__webpack_require__.p,大致原理是 Webpack 内部集成了一个 APIPlugin 插件,代码可以看webpack源码中的 lib/APIPlugin.js 文件,在解析源代码时,会将__webpack_public_path__ 替换为 __webpack_require__.p

故可以在源代码中设置:

if (window.__webpack_public_path__) {
  __webpack_public_path__ = window.__webpack_public_path__
}

如果页面中动态注入了cdn的域名,则覆盖默认的。当然结合一些检测手段,也应该可以实现 cdn 的域名的降级。

3. 如何不侵入代码设置 __webpack_public_path__

设置 __webpack_public_path__ 可以理解是一个工程行为,和具体的业务逻辑没有关系,如果多个项目有通用的诉求,应该是可直接复用,而不应该每次都修改源码。

既然定义为一个工程行为,工程化大多场景都是通过脚手架落地,脚手架中包含开发、编译、部署等能力,设置__webpack_public_path__变量应该在编译源码阶段,可以封装成一个插件形式,因项目是基于webpack构建,故基于webpack实现一个插件。

通过自己看 webpack 的源码,同时调研了些现有的插件,大致思路有两个:

  1. babel插件,通过解析文件阶段,修改解析的文件;
  2. webpack的loader形式,针对命中规则的文件,添加一个自定义的loader,在loader中修改源文件。

使用babel插件形式过于复杂,毕竟只是插入几行代码到源码中,还是基于webpack可能最简单。通过看webpack插件找到个自身的盲点知识,webpack的的entry支持多个文件,其实只需要动态修改entry,添加一个文件即可,大致实现为: 然后在webpack的配置使用该插件即可。

参考插件: webpack-inject-plugin

总结

有些场景需要一个项目在不同场景使用不同域名,不同域名对应的 cdn 域名也不一致,通过动态下发 cdn 域名,并结合 webpack 的自带修改资源路径前缀方式,解决多 cdn 域名问题。