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徽!