vue-cli3 之vue.config.js配置

1弟蚀、 cdn蚤霞、全局cdn(所有的js、css都使用cdn)
2义钉、Gzip壓縮(壓縮js咙好、css)
3服鹅、去掉注釋、去掉console.log
4、壓縮圖片
5限匣、本地代理
6、環(huán)境變量和模式

基本配置

const path = require('path')
function resolve (dir) {
  return path.join(__dirname, './', dir)
}
module.exports = {
  publicPath:  '/', // 默認'/'骂因,部署應用包時的基本 URL
  outputDir: 'dist',
  assetsDir: '', // 相對于outputDir的靜態(tài)資源(js徘键、css、img央碟、fonts)目錄
  runtimeCompiler: true, // 是否使用包含運行時編譯器的 Vue 構建版本
  productionSourceMap: false, // 生產環(huán)境的 source map
  configureWebpack: config => {},
  chainWebpack: config => {}
}

一税灌、cdn、全局cdn(所有的js、css都使用cdn)

vue.config

// cdn預加載使用
const externals = {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'vuex': 'Vuex',
  'axios': 'axios',
  'element-ui': 'ELEMENT',
  'js-cookie': 'Cookies',
  'nprogress': 'NProgress'
}
const cdn = {
  // 開發(fā)環(huán)境
  dev: {
    css: [
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
    ],
    js: []
  },
  // 生產環(huán)境
  build: {
    css: [
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
    ],
    js: [
      'https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js',
      'https://cdn.jsdelivr.net/npm/vue-router@3.0.1/dist/vue-router.min.js',
      'https://cdn.jsdelivr.net/npm/vuex@3.0.1/dist/vuex.min.js',
      'https://cdn.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js',
      'https://unpkg.com/element-ui/lib/index.js',
      'https://cdn.bootcss.com/js-cookie/2.2.0/js.cookie.min.js',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js'
    ]
  }
}
configureWebpack: config => {
   const myConfig = {}
    //本地環(huán)境 線上環(huán)境
    if(process.env.NODE_ENV === 'production'){
      myConfig.externals  = externals
    }
    if(process.env.NODE_ENV === 'development'){
      myConfig.devServer = {
        disableHostCheck: true
      }
    }
    return myConfig
}


chainWebpack: config => {
        // 使用cdn
      config.plugin('html').tap(args => {
        if (process.env.NODE_ENV === 'production') {
          args[0].cdn = cdn.build
        }
        if (process.env.NODE_ENV === 'development') {
          args[0].cdn = cdn.dev
        }
        return args
      })
}

public/index.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="utf-8">
  <meta name="renderer" content="webkit">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">

  <!-- 使用CDN加速的CSS文件菱涤,配置在vue.config.js下 -->
  <% 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文件苞也,配置在vue.config.js下 -->
  <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
  <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="preload" as="script">
  <% } %>

  <!-- 測試 -->
  <title>vue-cli3</title>
</head>

<body>

  <noscript>
    <strong>We're sorry but vue-project-demo doesn't work properly without JavaScript enabled. Please enable it
      tocontinue.</strong>
  </noscript>
  <div id="app"></div>

  <!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
  <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
  <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>

</body>
</html>

npm run build 一下粘秆, 使用本地預覽如迟,
serve -s dist打開控制臺,如下圖

cdn

全局cdn
使用七牛云融合 CDN

1翻擒、安裝Node.js SDK

$ npm install qiniu

2氓涣、獲取密鑰(Access/Secret Key)


Access/Secret Key

3、新建upcdn.js

const qiniu = require('qiniu')
const glob = require('glob')
const mime = require('mime')
const path = require('path')

const isWindow = /^win/.test(process.platform)

let pre = path.resolve(__dirname, './dist/') + (isWindow ? '\\' : '')

const files = glob.sync(
  `${path.join(
    __dirname,
    './dist/**/*.?(js|css|map|png|jpg|svg|woff|woff2|ttf|eot)'
  )}`
)
pre = pre.replace(/\\/g, '/')

const options = {
  scope: 'test2' // 空間對象名稱 
}
var config = {
  qiniu: {
    accessKey: '你的AccessKey',  // 個人中心 秘鑰管理里的 AccessKey
    secretKey: '你的SecretKey',  // 個人中心 秘鑰管理里的 SecretKey
    bucket: options.scope,
    domain: 'http://ppqqg4jtj.bkt.clouddn.com' //你的域名
  }
}
var accessKey = config.qiniu.accessKey
var secretKey = config.qiniu.secretKey

var mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
var putPolicy = new qiniu.rs.PutPolicy(options)
var uploadToken = putPolicy.uploadToken(mac)
var cf = new qiniu.conf.Config({
  zone: qiniu.zone.Zone_z2
})
var formUploader = new qiniu.form_up.FormUploader(cf)
async function uploadFileCDN (files) {
  files.map(async file => {
    const key = getFileKey(pre, file)
    try {
      await uploadFIle(key, file)
      console.log(`上傳成功 key: ${key}`)
    } catch (err) {
      console.log('error', err)
    }
  })
}
async function uploadFIle (key, localFile) {
  const extname = path.extname(localFile)
  const mimeName = mime.getType(extname)
  const putExtra = new qiniu.form_up.PutExtra({ mimeType: mimeName })
  return new Promise((resolve, reject) => {
    formUploader.putFile(uploadToken, key, localFile, putExtra, function ( respErr, respBody, respInfo) {
      if (respErr) {
        reject(respErr)
      }
      resolve({ respBody, respInfo })
    })
  })
}
function getFileKey (pre, file) {
  console.log(pre, file);
  
  if (file.indexOf(pre) > -1) {
    const key = file.split(pre)[1]
    return key.startsWith('/') ? key.substring(1) : key
  }
  return file
}

(async () => {
  console.time('上傳文件到cdn')
  await uploadFileCDN(files)
  console.timeEnd('上傳文件到cdn')
})()


4陋气、vue.config.js

const cdnDomian = 'http://ppqqg4jtj.bkt.clouddn.com' //靜態(tài)文件cdn
module.exports = {
  publicPath:  cdnDomian, // 默認'/'劳吠,部署應用包時的基本 URL
}

5、package.json

  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "analyz": "vue-cli-service build --mode analyz",
    "lint": "vue-cli-service lint",
    "upcdn": "node ./upcdn.js",
    "globalcdn": "rm -rf dist && echo --- 正在打包... --- && npm run build && echo --- 打包完成 --- && echo --- 正在上傳到服務器... --- && npm run upcdn &&  echo -- 上傳完成9谩痒玩!"
  },

執(zhí)行npm run globalcdn 效果如下圖

效果1

效果2

二、Gzip壓縮(壓縮js议慰、css)

1蠢古、安裝compression-webpack-plugin

npm i compression-webpack-plugin

2、vue.config.js

// gzip --start
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzip = true // 是否使用gzip
const productionGzipExtensions = ['js', 'css'] // 需要gzip壓縮的文件后綴
// gzip --end

module.exports = {
    configureWebpack: config => {
         if (process.env.NODE_ENV === 'production') {
      // gzip
      //  構建時開啟gzip别凹,降低服務器壓縮對CPU資源的占用草讶,服務器也要相應開啟gzip
      productionGzip && myConfig.plugins.push(
        new CompressionWebpackPlugin({
          test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
          threshold: 8192,
          minRatio: 0.8
        })
      )
  }


    }

}

3、后臺Nginx配置

gzip on;
gzip_static on;
gzip_min_length 1024;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";

本地預覽效果

帶有.gz后綴說明壓縮成功了

線上在 response headers 里會有一個Content-Encoding:gzip

三炉菲、去掉注釋堕战、去掉console.log

1、安裝uglifyjs-webpack-plugin

npm i uglifyjs-webpack-plugin

2拍霜、vue.config.js

const UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 去掉注釋
module.exports = {
    configureWebpack: config => {
          const myConfig = {}
          if (process.env.NODE_ENV === 'production') {
          myConfig.plugins = []
          // 去掉注釋
          // 去掉注釋
          myConfig.plugins.push(
            new UglifyJsPlugin({
              uglifyOptions: {
                output: {
                  comments: false, // 去掉注釋
                },
                compress: {
                  warnings: false,
                  drop_console: true,
                  drop_debugger: false,
                  pure_funcs: ['console.log']//移除console
              }
              }
            })
          )

      }
  }
}

四嘱丢、壓縮圖片

1、安裝image-webpack-loader

npm i -D image-webpack-loader

2祠饺、vue.congin.js

module.exports = {
  chainWebpack: config => {
      // 壓縮圖片
    config.module
      .rule('images')
      .use('image-webpack-loader')
      .loader('image-webpack-loader')
      .options({
        mozjpeg: { progressive: true, quality: 65 },
        optipng: { enabled: false },
        pngquant: { quality: '65-90', speed: 4 },
        gifsicle: { interlaced: false },
        webp: { quality: 75 }
      })
  }
}

五越驻、環(huán)境變量和模式、本地代理

.env.production文件 (線上)

NODE_ENV = 'production'

VUE_APP_SRC='https://www.google.com'
VUE_APP_V='https://www.google.com'

.env.development文件

//開發(fā)環(huán)境
NODE_ENV='development'

VUE_APP_SRC=''http://192.168.1.174:8003'
VUE_APP_V='http://192.168.1.173:8003'
module.exports = {
  devServer: {
    open: true, // 自動啟動瀏覽器
    host: '0.0.0.0', // localhost
    port: 8080, // 端口號
    https: false,
    hotOnly: false, // 熱更新
    proxy: {
      // 本地代理包含user的接口 如: /user/getUser 
      '^/user': {
        target: process.env.VUE_APP_SRC,
        ws: true,   //開啟WebSocket
        changeOrigin: true
      },
      '^/v1': {  //匹配包含 /v1的接口  如:v1/xxx/xx
        target: process.env.VUE_APP_V,
        ws: true,
        changeOrigin: true
      }
    }
  },
}

完整代碼

const path = require('path')
const IS_PROD = ['production'].includes(process.env.NODE_ENV)
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin // 打包分析

const mockIndexData = require('./src/mock/index.json') // mock.js (傳說的假數據)

// gzip --start
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzip = true // 是否使用gzip
const productionGzipExtensions = ['js', 'css'] // 需要gzip壓縮的文件后綴
// gzip --end

const UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 去掉注釋

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

// cdn預加載使用
const externals = {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'vuex': 'Vuex',
  'axios': 'axios',
  'element-ui': 'ELEMENT',
  'js-cookie': 'Cookies',
  'nprogress': 'NProgress'
}

const cdn = {
  // 開發(fā)環(huán)境
  dev: {
    css: [
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
    ],
    js: []
  },
  // 生產環(huán)境
  build: {
    css: [
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
    ],
    js: [
      'https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js',
      'https://cdn.jsdelivr.net/npm/vue-router@3.0.1/dist/vue-router.min.js',
      'https://cdn.jsdelivr.net/npm/vuex@3.0.1/dist/vuex.min.js',
      'https://cdn.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js',
      'https://unpkg.com/element-ui/lib/index.js',
      'https://cdn.bootcss.com/js-cookie/2.2.0/js.cookie.min.js',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js'
    ]
  }
}
const cdnDomian = 'http://ppqqg4jtj.bkt.clouddn.com' //靜態(tài)文件cdn

module.exports = {
  // baseUrl: IS_PROD ? process.env.VUE_APP_SRC || '/' : './', // 默認'/'道偷,部署應用包時的基本 URL
  publicPath: IS_PROD ? cdnDomian: '/', // 默認'/'缀旁,部署應用包時的基本 URL
  outputDir: 'dist',
  assetsDir: '', // 相對于outputDir的靜態(tài)資源(js、css试疙、img诵棵、fonts)目錄
  runtimeCompiler: true, // 是否使用包含運行時編譯器的 Vue 構建版本
  productionSourceMap: false, // 生產環(huán)境的 source map

  
  configureWebpack: config => {
  

    const myConfig = {}
    if (process.env.NODE_ENV === 'production') {
      // 1. 生產環(huán)境npm包轉CDN
      myConfig.externals = externals

      myConfig.plugins = []
      // gzip
      // 2. 構建時開啟gzip,降低服務器壓縮對CPU資源的占用祝旷,服務器也要相應開啟gzip
      productionGzip && myConfig.plugins.push(
        new CompressionWebpackPlugin({
          test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
          threshold: 8192,
          minRatio: 0.8
        })
      )
          // 去掉注釋
          myConfig.plugins.push(
            new UglifyJsPlugin({
              uglifyOptions: {
                output: {
                  comments: false, // 去掉注釋
                },
                compress: {
                  warnings: false,
                  drop_console: true,
                  drop_debugger: false,
                  pure_funcs: ['console.log']//移除console
              }
              }
            })
          )
      
    }

    if (process.env.NODE_ENV === 'development') {
      /**
       * 關閉host check履澳,方便使用ngrok之類的內網轉發(fā)工具
       */
      myConfig.devServer = {
        disableHostCheck: true
      }
    }

    return myConfig
  },

  chainWebpack: config => {
    // 壓縮圖片
    config.module
      .rule('images')
      .use('image-webpack-loader')
      .loader('image-webpack-loader')
      .options({
        mozjpeg: { progressive: true, quality: 65 },
        optipng: { enabled: false },
        pngquant: { quality: '65-90', speed: 4 },
        gifsicle: { interlaced: false },
        webp: { quality: 75 }
      })

    // 使用cdn
      config.plugin('html').tap(args => {
        if (process.env.NODE_ENV === 'production') {
          args[0].cdn = cdn.build
        }
        if (process.env.NODE_ENV === 'development') {
          args[0].cdn = cdn.dev
        }
        return args
      })

    // 打包分析
    if (process.env.IS_ANALYZ) {
      config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
        {
          analyzerMode: 'static'
        }
      ])
    }
    // svg loader
    const svgRule = config.module.rule('svg') // 找到svg-loader
    svgRule.uses.clear() // 清除已有的loader, 如果不這樣做會添加在此loader之后
    svgRule.exclude.add(/node_modules/) // 正則匹配排除node_modules目錄
    svgRule // 添加svg新的loader處理
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })

    // 修改images loader 添加svg處理
    const imagesRule = config.module.rule('images')
    imagesRule.exclude.add(resolve('src/icons'))
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
  },
  devServer: {
    open: true, // 自動啟動瀏覽器
    host: '0.0.0.0', // localhost
    port: 6060, // 端口號
    https: false,
    hotOnly: false, // 熱更新
    proxy: {
      // 本地代理包含user的接口 如: /user/getUser 
      '^/user': {
        target: process.env.VUE_APP_SRC,
        ws: true,   //開啟WebSocket
        changeOrigin: true
      },
      '^/v1': {  //匹配包含 /v1的接口  如:v1/xxx/xx
        target: process.env.VUE_APP_V,
        ws: true,
        changeOrigin: true
      }

    }
  },

// devServer: {
//   port: 8080,
//   before(app) {
//     app.get('/api/index', (req, res) => {
//       res.json(mockIndexData)
//     })
//   }
// }
}

完K徽!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末距贷,一起剝皮案震驚了整個濱河市柄冲,隨后出現的幾起案子,更是在濱河造成了極大的恐慌忠蝗,老刑警劉巖现横,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異阁最,居然都是意外死亡戒祠,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門速种,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姜盈,“玉大人,你說我怎么就攤上這事配阵×笏蹋” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵棋傍,是天一觀的道長救拉。 經常有香客問我,道長瘫拣,這世上最難降的妖魔是什么亿絮? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮麸拄,結果婚禮上壹无,老公的妹妹穿的比我還像新娘。我一直安慰自己感帅,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布地淀。 她就那樣靜靜地躺著失球,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帮毁。 梳的紋絲不亂的頭發(fā)上实苞,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音烈疚,去河邊找鬼黔牵。 笑死,一個胖子當著我的面吹牛爷肝,可吹牛的內容都是我干的猾浦。 我是一名探鬼主播陆错,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼金赦!你這毒婦竟也來了音瓷?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤夹抗,失蹤者是張志新(化名)和其女友劉穎绳慎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體漠烧,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡杏愤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了已脓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片珊楼。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖摆舟,靈堂內的尸體忽然破棺而出亥曹,到底是詐尸還是另有隱情,我是刑警寧澤恨诱,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布媳瞪,位于F島的核電站,受9級特大地震影響照宝,放射性物質發(fā)生泄漏蛇受。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一厕鹃、第九天 我趴在偏房一處隱蔽的房頂上張望兢仰。 院中可真熱鬧,春花似錦剂碴、人聲如沸把将。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽察蹲。三九已至,卻和暖如春催训,著一層夾襖步出監(jiān)牢的瞬間洽议,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工漫拭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留亚兄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓采驻,卻偏偏與公主長得像审胚,于是被迫代替她去往敵國和親匈勋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容