[TOC]

webpack工程项目中配置第三方库的CDN,并做CDN容错

好处

  1. cdn可以利用缓存, 只需连接一次, 即有长久的缓存(只要不清除)
  2. 可以提升webpack打包速度,亲测打包速度 20s -> 13s (跟项目内第三方库数量有关)

场景举例

(假设内部平台有100个, 并且全部用了vue的cdn)

用户A只要登录过100个平台内的任意一个, 就会有vue的长久缓存, 在登录100个平台中的任意一个 都可以直接读vue的缓存

具体配置

1. 配webpack.config.js(根目录下)

...
const externals = { // 根据自己项目情况选择
  vue: 'Vue',
  vuex: 'Vuex',
  'vue-router': 'VueRouter',
  axios: 'axios',
  'view-design': 'iview',
  'vue-i18n': 'VueI18n'
}
...
module.exports = (env) => {
  ...  
  externals,
  ...
}

2. 配置index.html(根目录下)

增加script标签,获取资源

  • 根据上方配置的externals情况选择
// 找到当前项目的模板 index.html, 例如
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>xxx</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>


// 这个需要改成: 如下, 增加 几个 script 标签 (根据上方配置的externals情况选择)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title></title>
    <script title="cdn" src="https://xx-cdn.com/vue/vue-2.6.11.min.js" onerror="fallback('vue-2.6.11.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/vuex/vuex-3.1.2.min.js" onerror="fallback('vuex-3.1.2.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/vue-router/vue-router-3.1.6.min.js" onerror="fallback('vue-router-3.1.6.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/axios/axios-0.19.1.min.js" onerror="fallback('axios-0.19.1.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/view-ui/4.2.0/iview.min.js" onerror="fallback('iview-4.2.0.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/vue-i18n/8.22.1/vue-i18n.min.js" onerror="fallback('vue-i18n-8.22.1.min.js')"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

这样基本可以使用了,但还没完,因为CDN有可能会挂,虽然概率很低,但还是需要做容错

CDN容错

思路:当CDN挂掉的时候,我们选择自己内部备用的静态资源服务器,暂且域名叫:my-static.cn

难点:比如vue挂掉了,后续依赖vue的cdn资源,如:vue-router,也需要在执行一遍,否则拿不到vue对象

  • 除了cdn资源要全部在执行一遍外,静态的js资源 如main.js也要重新执行一遍,因为里面也依赖vue

上代码: cdn-control.js

// 文件名:cdn-control.js
let fallbackRun = false;
const myServer = 'http://my-static.cn/cdn/' 
// 自己内部备用的静态资源服务器
function fallback(fallbackUrl, local) {
  fallbackUrl = local ? fallbackUrl : myServer + fallbackUrl;
  let fallbackScript = document.createElement("script");
  fallbackScript.src = fallbackUrl;
  document.head.appendChild(fallbackScript);
  if (!fallbackRun) {
    fallbackRun = true;
    window.onload = function (e) {
      // head内的cdn比如iview是依赖vue的,如果vue的cdn挂了,此处需在刷新一遍cdn
      for (let obj of document.head.children) {
        if (obj.title === 'cdn') fallback(obj.src, 'local')
      }
      // body内的script有缓存后, 会比"容错的js文件"执行更快, 导致找不到vue, 直接挂掉
      for (let obj of document.body.children) {
        if (obj.tagName === 'SCRIPT') fallback(obj.src, 'local')
      }
    }
  }
}

上面配置过的index.html需要引入cdn-control.js,并在之前的script标签内加上onerror属性

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title></title>
    // "./cdn/cdn-control-min.js"  cdn-control.js请自行手动加入项目,并压缩
+   <script title="cdn-control" src="./cdn/cdn-control-min.js"></script>
    // 以下每个script都增加了 onerror 属性,如:onerror="fallback('vue-2.6.11.min.js')"  (fallback函数是cdn-control.js里的)
    <script title="cdn" src="https://xx-cdn.com/vue/vue-2.6.11.min.js" onerror="fallback('vue-2.6.11.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/vuex/vuex-3.1.2.min.js" onerror="fallback('vuex-3.1.2.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/vue-router/vue-router-3.1.6.min.js" onerror="fallback('vue-router-3.1.6.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/axios/axios-0.19.1.min.js" onerror="fallback('axios-0.19.1.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/view-ui/4.2.0/iview.min.js" onerror="fallback('iview-4.2.0.min.js')"></script>
    <script title="cdn" src="https://xx-cdn.com/vue-i18n/8.22.1/vue-i18n.min.js" onerror="fallback('vue-i18n-8.22.1.min.js')"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

原创整理,如有误可留言。 如果有用,谢谢点赞~


性能优化合集快速入口: