vue-cli 3.0 使用CDN區(qū)分開發(fā)、生產(chǎn)、預(yù)發(fā)布環(huán)境

hi~我叫內(nèi)孤,一名web前端開發(fā)者/:B-),今天我又要來(lái)說(shuō)說(shuō)我的'故事'了。

前言:上一篇記錄文vue-cli 3.0 build包太大導(dǎo)致首屏過(guò)長(zhǎng)的解決方案中提到了CDN優(yōu)化,之前是直接在html中手動(dòng)注入JS,也沒有對(duì)開發(fā)和生產(chǎn)模式進(jìn)行區(qū)分,因?yàn)槭鞘褂檬召M(fèi)的CDN,所以在開發(fā)模式會(huì)遇到無(wú)權(quán)使用CDN的問(wèn)題。要是使用CDN寫死在html中,不同環(huán)境需要手動(dòng)的切換CDN,那么早晚有一天會(huì)搞亂,下面就說(shuō)說(shuō)怎么在vue-cli 3.0 中根據(jù)不同環(huán)境動(dòng)態(tài)注入CDN。

1. 修改public/index.html

通過(guò)htmlwebpackplugin動(dòng)態(tài)注入腳本和樣式,index.html如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>杭州納舍科技</title>
    <!-- 使用CDN的CSS文件 -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style">
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
    <% } %>
    <!-- 使用CDN的JS文件 -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
      <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="preload" as="script">
    <% } %>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div class="global-loading">
      <div class="spinner"></div>
    </div>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
      <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>
  </body>
</html>

2. 修改vue.config.js配置

首先我們會(huì)考慮哪些東西要進(jìn)行CDN優(yōu)化,例如我們需要把vue、vue-router、moment在構(gòu)建的時(shí)候排除在外使用CDN加載這三個(gè)庫(kù),那么需要把添加externals

const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
  configureWebpack: config => {
    if (isProduction) {
      config.externals = {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'moment': 'moment'
      }
    }
  }
}

現(xiàn)在我們運(yùn)行npm run build 打包出來(lái)的文件就沒有Vue、VueRouter、moment,現(xiàn)在我們使用html-webpack-plugin插件進(jìn)行動(dòng)態(tài)注入CDN,在vue-cli 3.0 中我們要這樣配置:

const isProduction = process.env.NODE_ENV === 'production';
const cdn = {
  css: ['xxx.css', 'sss.js'],
  js: ['xxxx.js', 'sss.js']
}
module.exports = {
  configureWebpack: config => {
    if (isProduction) {
      config.externals = {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'moment': 'moment'
      }
    }
  }
  chainWebpack: config => {
    if (isProduction) {
      config.plugin('html')
      .tap(args => {
          args[0].cdn = cdn;
        return args;
      })
    }
  }
}

到目前為止已經(jīng)解決了開發(fā)模式不使用CDN,生產(chǎn)模式使用CDN的問(wèn)題和動(dòng)態(tài)在html中注入CDN的問(wèn)題。

可能你會(huì)遇到和我一樣的問(wèn)題

預(yù)發(fā)布build測(cè)試,但無(wú)權(quán)使用生產(chǎn)上的CDN問(wèn)題,那么我們必須再添加一個(gè)環(huán)境變量來(lái)區(qū)分預(yù)發(fā)布build的模式。(vue-cli 3.0 環(huán)境變量文檔)這里我添加一個(gè)IS_LOCAL_BUILD,首先我們?cè)趘ue.cofnig.js同路徑下創(chuàng)建一個(gè).en.production.local :

// .en.production.local` 內(nèi)容:
IS_LOCAL_BUILD = 'isLocalBuild'

修改vue.config.js如下:

const isProduction = process.env.NODE_ENV === 'production';
const isLocalBuild = process.env.IS_LOCAL_BUILD === 'isLocalBuild';
const JS_CDN = isLocalBuild ? [
  預(yù)發(fā)布CDN(例如那些免費(fèi)的CDN)
] : [
  生產(chǎn)環(huán)CDN
];
const CSS_CDN = isLocalBuild ? [預(yù)發(fā)布CDN]: [生產(chǎn)CDN]
const cdn = {
  css: CSS_CDN,
  js: JS_CDN
}
module.exports = {
  configureWebpack: config => {
    if (isProduction) {
      config.externals = {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'moment': 'moment'
      }
    }
  }
  chainWebpack: config => {
    if (isProduction) {
      config.plugin('html')
      .tap(args => {
          args[0].cdn = cdn;
        return args;
      })
    }
  }
}

ok,上面區(qū)分了生產(chǎn)、預(yù)發(fā)布和開發(fā)環(huán)境使用CDN的問(wèn)題,這樣就不用根據(jù)不同環(huán)境手動(dòng)去修改CDN了。不過(guò)又一點(diǎn)要注意:??預(yù)發(fā)布版本的構(gòu)建才需要添加.en.production.local。

完整的vue.config.js(供參考)

const path = require('path');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const productionGzipExtensions = ['js', 'css'];
const isProduction = process.env.NODE_ENV === 'production';

function resolve(dir) {
  return path.join(__dirname, dir);
}

// 預(yù)發(fā)布環(huán)境
const isLocalBuild = process.env.IS_LOCAL_BUILD === 'isLocalBuild';
console.log('前端文件預(yù)發(fā)布打包- isLocalBuild:', isLocalBuild);

// 非externals CND前綴設(shè)置
const CDN_URL = isLocalBuild ? '/' : '//s.zypj.nasetech.com/';

// 區(qū)分生產(chǎn)環(huán)境打包和預(yù)發(fā)布打包,使用不同的CDN
const JS_CDN = isLocalBuild ? [
  // 預(yù)發(fā)布CDN
] : [
  // 生產(chǎn)CDN
];

const cdn = {
  // css: [],
  js: JS_CDN
}

module.exports = {
  lintOnSave: true,
  baseUrl: isProduction ? CDN_URL : '/',
  chainWebpack: (config) => {
    // build打包才使用CDN
    if (isProduction) {
      config.plugin('html')
      .tap(args => {
          args[0].cdn = cdn;
        return args;
      })
    }

    config.resolve.alias
      .set('assets', resolve('src/assets'))
      .set('pages', resolve('src/pages'))
      .set('components', resolve('src/components'))
      .set('utils', resolve('src/utils'))
  },
  devServer: {
    host: '0.0.0.0',
    port: 8080,
    https: false,
    hotOnly: false,
    disableHostCheck: false,
    proxy: {
      '/api/v0/': {
        // 目標(biāo) API 地址
        target: 'http://127.0.0.1:4545',
        // 將主機(jī)標(biāo)頭的原點(diǎn)更改為目標(biāo)URL
        changeOrigin: true,
      },
    },
  },
  configureWebpack: config => {
    // 生產(chǎn)模式
    if (isProduction) {
      config.externals = {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'moment': 'moment'
      }
      // 打包生產(chǎn).gz包
      config.plugins.push(new CompressionWebpackPlugin({
        algorithm: 'gzip',
        test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
        threshold: 10240,
        minRatio: 0.8
      }))
      // 添加自定義代碼壓縮配置
      config.plugins.push(
        new UglifyJsPlugin({
          uglifyOptions: {
            compress: {
              warnings: false,
              drop_debugger: true,
              drop_console: true,
            },
          },
          sourceMap: false,
          parallel: true,
        })
      )
    }
  }
}

* 使用CDN一些有意思的坑:

使用CDN還會(huì)遇到一些有意思的事,例如使用beta版的vue導(dǎo)致element UI庫(kù)有些組件無(wú)法正常工作; 使用免費(fèi)的CDN上線沒有多久就GG不能用等悲慘故事!?。?/p>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容