前端

vue-cli3 之vue.config.js配置

2019-04-24  本文已影响0人  取个帅气的名字真好

1、 cdn、全局cdn(所有的js、css都使用cdn)
2、Gzip压缩(压缩js、css)
3、去掉注释、去掉console.log
4、压缩图片
5、本地代理
6、环境变量和模式

基本配置

const path = require('path')
function resolve (dir) {
  return path.join(__dirname, './', dir)
}
module.exports = {
  publicPath:  '/', // 默认'/',部署应用包时的基本 URL
  outputDir: 'dist',
  assetsDir: '', // 相对于outputDir的静态资源(js、css、img、fonts)目录
  runtimeCompiler: true, // 是否使用包含运行时编译器的 Vue 构建版本
  productionSourceMap: false, // 生产环境的 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 = {
  // 开发环境
  dev: {
    css: [
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
    ],
    js: []
  },
  // 生产环境
  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 = {}
    //本地环境 线上环境
    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' //静态文件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 -- 上传完成!!"
  },

执行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 }
      })
  }
}

五、环境变量和模式、本地代理

.env.production文件 (线上)

NODE_ENV = 'production'

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

.env.development文件

//开发环境
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 = {
  // 开发环境
  dev: {
    css: [
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
      'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
    ],
    js: []
  },
  // 生产环境
  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' //静态文件cdn

module.exports = {
  // baseUrl: IS_PROD ? process.env.VUE_APP_SRC || '/' : './', // 默认'/',部署应用包时的基本 URL
  publicPath: IS_PROD ? cdnDomian: '/', // 默认'/',部署应用包时的基本 URL
  outputDir: 'dist',
  assetsDir: '', // 相对于outputDir的静态资源(js、css、img、fonts)目录
  runtimeCompiler: true, // 是否使用包含运行时编译器的 Vue 构建版本
  productionSourceMap: false, // 生产环境的 source map

  
  configureWebpack: config => {
  

    const myConfig = {}
    if (process.env.NODE_ENV === 'production') {
      // 1. 生产环境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之类的内网转发工具
       */
      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)
//     })
//   }
// }
}

完!!

上一篇下一篇

猜你喜欢

热点阅读