項目剛發(fā)布的時候.npm run build打包出來的chunk-vendor.js體積達(dá)到了2.5m跳仿,我滴媽还绘,服務(wù)器帶寬又很低窍荧,加載實在是太慢了灿椅,然后我做了以下這些事情 (像路由懶加載什么的就不提了)浸间。
1.因為項目中使用了charts太雨,做了echarts的按需加載。
本來直接在Main.js中:
import echarts from 'echarts'
Vue.prototype.$echarts = echarts
現(xiàn)在改為在echarts組件里引入
var echarts = require('echarts/lib/echarts');
require('echarts/lib/chart/line') // 按需導(dǎo)入折線組件
require('echarts/lib/component/tooltip') // 提示組件
require('echarts/lib/component/legend') // 圖例組件
2.使用uglifyOptions去除console來減小文件大小
// 安裝uglifyjs-webpack-plugin
cnpm install uglifyjs-webpack-plugin --save-dev
// 修改vue.config.js
configureWebpack: config => {
if (isProduction) {
.....
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_debugger: true,
drop_console: true,
},
},
sourceMap: false,
parallel: true,
})
)
}
}
3.服務(wù)器開啟Gzip
// 安裝插件
cnpm i --save-dev compression-webpack-plugin
// 在vue-config.js 中加入
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const productionGzipExtensions = ['js', 'css'];
const isProduction = process.env.NODE_ENV === 'production';
.....
module.exports = {
....
configureWebpack: config => {
if (isProduction) {
config.plugins.push(new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
}))
}
}
}
需要注意的是魁蒜,這種優(yōu)化方法非常有效囊扳,大改能減少2/3的體積吩翻,但是需要服務(wù)器端也支持,因為它會在打包過程中生成.gz結(jié)尾的壓縮包锥咸,請求資源的時候就直接加載這個壓縮包里的文件了狭瞎。這里實力nginx的配置方法:
添加以下代碼:
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml
text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
nginx.conf最終內(nèi)容如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream njsolar {
server localhost:9000; #Apache
}
server {
listen 8083;
server_name localhost;
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/local/deploy/njsolar-ui/dist;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
}
}
4.使用CDN托管
大型Web應(yīng)用對速度的追求并沒有止步于僅僅利用瀏覽器緩存,因為瀏覽器緩存始終只是為了提升二次訪問的速度搏予,對于首次訪問的加速熊锭,我們需要從網(wǎng)絡(luò)層面進(jìn)行優(yōu)化,最常見的手段就是CDN(Content Delivery Network雪侥,內(nèi)容分發(fā)網(wǎng)絡(luò))加速碗殷。通過將靜態(tài)資源緩存到離用戶很近的相同網(wǎng)絡(luò)運(yùn)營商的CDN節(jié)點上,不但能提升用戶的訪問速度速缨,還能節(jié)省服務(wù)器的帶寬消耗锌妻,降低負(fù)載。不同地區(qū)的用戶會訪問到離自己最近的相同網(wǎng)絡(luò)線路上的CDN節(jié)點旬牲,當(dāng)請求達(dá)到CDN節(jié)點后从祝,節(jié)點會判斷自己的內(nèi)容緩存是否有效,如果有效引谜,則立即響應(yīng)緩存內(nèi)容給用戶,從而加快響應(yīng)速度擎浴。如果CDN節(jié)點的緩存失效员咽,它會根據(jù)服務(wù)配置去我們的內(nèi)容源服務(wù)器獲取最新的資源響應(yīng)給用戶,并將內(nèi)容緩存下來以便響應(yīng)給后續(xù)訪問的用戶贮预。因此贝室,一個地區(qū)內(nèi)只要有一個用戶先加載資源,在CDN中建立了緩存仿吞,該地區(qū)的其他后續(xù)用戶都能因此而受益滑频。
//vue.config.js頭部插入
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// 是否為生產(chǎn)環(huán)境
const isProduction = process.env.NODE_ENV !== 'development'
// 本地環(huán)境是否需要使用cdn
const devNeedCdn = true
// cdn鏈接
const cdn = {
// cdn:模塊名稱和模塊作用域命名(對應(yīng)window里面掛載的變量名稱)
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
'element-ui':'ELEMENT'
},
// cdn的css鏈接
css: [],
// cdn的js鏈接
js: [
'https://cdn.staticfile.org/vue/2.6.10/vue.min.js',
'https://cdn.staticfile.org/vuex/3.0.1/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js',
'https://cdn.bootcss.com/element-ui/2.13.2/index.js'
]
}
//module.exports 內(nèi)插入
chainWebpack:config =>{
// ============注入cdn start============
config.plugin('html').tap(args => {
// 生產(chǎn)環(huán)境或本地需要cdn時,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
// ============注入cdn start============
},
vue.config.js的最終代碼內(nèi)容如下:
// 代碼壓縮
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// 是否為生產(chǎn)環(huán)境
const isProduction = process.env.NODE_ENV !== 'development'
// 本地環(huán)境是否需要使用cdn
const devNeedCdn = true
// cdn鏈接
const cdn = {
// cdn:模塊名稱和模塊作用域命名(對應(yīng)window里面掛載的變量名稱)
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
'element-ui':'ELEMENT'
},
// cdn的css鏈接
css: [],
// cdn的js鏈接
js: [
'https://cdn.staticfile.org/vue/2.6.10/vue.min.js',
'https://cdn.staticfile.org/vuex/3.0.1/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js',
'https://cdn.bootcss.com/element-ui/2.13.2/index.js'
]
}
let path = require('path')
module.exports = {
productionSourceMap: false, //優(yōu)化打包體積
publicPath: './',
lintOnSave: false,
pluginOptions: {
'style-resources-loader': {
preProcessor: 'stylus',
patterns: [
path.resolve(__dirname, 'src/assets/stylus/*.styl')
// 打開之后common.styl的加載順序有問題
]
}
},
pwa: {
iconPaths: { // 修改favicon favicon.ico這個路徑不對唤冈,所以不顯示favicon.ico的峡迷,需要改成正確的才會顯示
favicon32: 'favicon.ico',
favicon16: 'favicon.ico',
appleTouchIcon: 'favicon.ico',
maskIcon: 'favicon.ico',
msTileImage: 'favicon.ico'
}
},
chainWebpack:config =>{
// ============注入cdn start============
config.plugin('html').tap(args => {
// 生產(chǎn)環(huán)境或本地需要cdn時,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
// ============注入cdn start============
},
configureWebpack: config => {
// 用cdn方式引入你虹,則構(gòu)建時要忽略相關(guān)資源
if (isProduction || devNeedCdn) config.externals = cdn.externals
// 生產(chǎn)環(huán)境相關(guān)配置
if (isProduction) {
// 代碼壓縮
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
//生產(chǎn)環(huán)境自動刪除console
compress: {
// warnings: false, // 若打包錯誤绘搞,則注釋這行
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
})
)
// 代碼壓縮
// ..................
// gzip壓縮
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, // 只有大小大于該值的資源會被處理 10240
minRatio: 0.8, // 只有壓縮率小于這個值的資源才會被處理
deleteOriginalAssets: false // 刪除原文件
})
)
}
// 生產(chǎn)環(huán)境相關(guān)配置
}
}
還有個小技巧:使用webpack-bundle-analyzer能幫助你分析哪個模塊占用了你多大的空間
再來打個包看看現(xiàn)在多大:
可以看到現(xiàn)在2.5m到了1126kb,對應(yīng)的Gzip達(dá)到了405kb傅物,讓我們看看放到服務(wù)器上的效果:
可以看到主要的chunk-vendors只有414kb夯辖,雖然加載了6s,那是因為服務(wù)器只有1M的帶寬董饰,下面的放在cdn上的文件幾乎都是秒加載的蒿褂,很棒圆米,實現(xiàn)了2.5m到400kb的突破。