# Vue typescript 如何极限压缩编译后静态资源 {#vue-typescript-如何极限压缩编译后静态资源}
# 前言 {#前言}
近期开发项目,由于资源有限,云服务器只有1m带宽。
vue初始 打包的静态资源,通过浏览器加载需要近1分钟的时间。
所以需要将静态资源进行压缩及相应处理 ,最终浏览器访问时间为5秒钟。
# 一、安装依赖 {#一、安装依赖}
首先安装依赖
compression-webpack-plugin
image-webpack-loader
-
yarn
yarn add compression-webpack-plugin -D yarn add image-webpack-loader -D
-
npm
npm install compression-webpack-plugin --save-dev npm install image-webpack-loader --save-dev
注意
记住,依赖一定要安装在 devDependencies
下,否则会增大你的打包体积
# 二、压缩图片 {#二、压缩图片}
提示
图片处理其实有很多种方式,例如引入cdn服务器等。
此处介绍的方式为,需要将图片和静态资源打包在一起时的解决方案。
# 1. 处理图片 {#_1-处理图片}
- 首先需要对图片进行处理,处理方式自行选择,例如使用ps将图片质量减小等。
- 此处推荐在线压缩图片,处理图片的网站https://imagecompressor.com/zh/
提示
此处再推荐一个其他的在线处理图片的网站https://www.websiteplanet.com/zh-hans/webtools/imagecompressor/
Thanks for Katherine Miller suggestion.
注意
不保证网站是否会收集图片数据,如果数据较为敏感,请不要上传,自行进行处理。
此步骤主要是为了将原始图片进一步压缩。
# 2. 打开vue.config.js
文件 {#_2-打开vue-config-js-文件}
打开vue的配置文件
# 3. 编写压缩图片配置 {#_3-编写压缩图片配置}
需要在文件中编写相应的压缩,可以对图片进行二次压缩。请根据需求自行配置。
详细使用说明可参考 https://www.npmjs.com/package/image-webpack-loader
module.exports = {
// 省略部分配置项
....
,
chainWebpack: config => {
// 省略部分配置项
...
// 判断环境不为开发环境
config
.when(process.env.NODE_ENV !== 'development',
config => {
// 压缩图片配置
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
mozjpeg: { progressive: true, quality: 65 }, // Compress JPEG images
optipng: { enabled: false }, // Compress PNG images
pngquant: { quality: [0.65, 0.9], speed: 4 }, // Compress PNG images
gifsicle: { interlaced: false } // Compress SVG images
})
.end()
}
)
}
}
# 三、压缩资源 {#三、压缩资源}
# 1. 打开vue.config.js
文件 {#_1-打开vue-config-js-文件}
打开vue的配置文件
# 2. 编写压缩配置 {#_2-编写压缩配置}
配置压缩资源,具体配置项可参考https://www.npmjs.com/package/compression-webpack-plugin
// 引入压缩依赖
const CompressionPlugin = require('compression-webpack-plugin')
// 需要压缩的文件的正则
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i
module.exports = {
// 省略部分配置项
....
,
chainWebpack: config => {
// 省略部分配置项
...
// 判断环境不为开发环境
config
.when(process.env.NODE_ENV !== 'development',
config => {
// 打包成gzip压缩文件
config.plugin('compressionPlugin')
.use(new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true
}))
}
)
}
}
# 四、抽取公共代码打包 {#四、抽取公共代码打包}
# 1. 打开vue.config.js
文件 {#_1-打开vue-config-js-文件-2}
打开vue的配置文件
# 2. 编写抽取公共代码配置 {#_2-编写抽取公共代码配置}
此处为将代码中的公共部分抽取出来,统一打包,可减小打包后的代码体积。
module.exports = {
// 省略部分配置项
....
,
chainWebpack: config => {
// 省略部分配置项
...
// 判断环境不为开发环境
config
.when(process.env.NODE_ENV !== 'development',
config
.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: path.resolve(__dirname, 'src/components'),
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single')
}
)
}
}
# 五、引用CDN {#五、引用cdn}
注意
此处引用的js和css的公共cdn代码库。
引入cdn后可有效减少从服务获取的资源数量。
但是有风险,一旦cdn服务出问题,你的网站也将无法访问。
此步骤请谨慎选择或使用自己的cdn服务器。
# 1. 打开vue.config.js
文件 {#_1-打开vue-config-js-文件-3}
打开vue的配置文件
# 2. 配置CDN {#_2-配置cdn}
const cdn = {
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.min.css',
'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css'
],
js: [
// vue必须在第一个
'https://cdn.bootcss.com/vue/2.6.11/vue.min.js',
'https://cdn.bootcss.com/vuex/3.2.0/vuex.min.js',
'https://cdn.bootcss.com/vue-router/3.4.3/vue-router.min.js',
'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',
'https://cdn.bootcss.com/qs/6.5.1/qs.min.js',
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js',
'https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts-en.min.js',
'https://cdn.bootcdn.net/ajax/libs/dexie/3.0.3/dexie.min.js',
'https://cdn.bootcdn.net/ajax/libs/js-cookie/2.2.1/js.cookie.min.js',
'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js'
]
}
module.exports = {
// 省略部分配置项
....
,
chainWebpack: config => {
config
.when(process.env.NODE_ENV !== 'development',
config => {
// 设置不打包的依赖,请根据自己需求进行修改
const externals = {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
axios: 'axios',
qs: 'Qs',
'element-ui': 'ELEMENT',
echarts: 'echarts',
dexie: 'Dexie',
'js-cookie': 'Cookies',
nprogress: 'NProgress'
}
config.externals(externals)
// 引入cdn
config.plugin('html').tap(args => {
args[0].cdn = cdn
return args
})
}
)
}
}
# 六、配置Nginx {#六、配置nginx}
提示
如果你使用的ngxin服务器当做静态资源服务,则可以开启gzip配置。
开启后访问速度会获得极大的提升
http {
# 省略部分配置
...
# 开启gzip
gzip on;
gzip_static on;
# 设置缓冲区大小
gzip_buffers 4 16k;
#压缩级别官网建议是6
gzip_comp_level 6;
#压缩的类型
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php;
# 省略部分配置
...
}
# 七、完整的配置文件 {#七、完整的配置文件}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const CompressionPlugin = require('compression-webpack-plugin')
const name = 'xxxx系统'
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i
const cdn = {
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.min.css',
'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css'
],
js: [
// vue必须在第一个
'https://cdn.bootcss.com/vue/2.6.11/vue.min.js',
'https://cdn.bootcss.com/vuex/3.2.0/vuex.min.js',
'https://cdn.bootcss.com/vue-router/3.4.3/vue-router.min.js',
'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',
'https://cdn.bootcss.com/qs/6.5.1/qs.min.js',
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js',
'https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts-en.min.js',
'https://cdn.bootcdn.net/ajax/libs/dexie/3.0.3/dexie.min.js',
'https://cdn.bootcdn.net/ajax/libs/js-cookie/2.2.1/js.cookie.min.js',
'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js'
]
}
module.exports = {
publicPath: './',
outputDir: 'dist',
// 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。 资源放的目录
assetsDir: './static',
// 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径 index的路劲和名字
indexPath: './index.html',
// publicPath: process.env.NODE_ENV === 'production' ? '/vue-typescript-admin-template/' : '/',
lintOnSave: process.env.NODE_ENV === 'development',
transpileDependencies: ['fuse.js', 'vuex-module-decorators', 'clipboard', 'markdown-it-vue'],
productionSourceMap: false,
devServer: {
port: devServerPort,
open: true,
overlay: {
warnings: false,
errors: true
},
progress: false,
proxy: {
'/': {
target: 'http://localhost:8082/',
withCredentials: true,
changeOrigin: true, // needed for virtual hosted sites
ws: true, // proxy websockets
}
}
},
pwa: {
name: name,
workboxPluginMode: 'InjectManifest',
workboxOptions: {
swSrc: path.resolve(__dirname, 'src/pwa/service-worker.js')
}
},
pluginOptions: {
'style-resources-loader': {
preProcessor: 'scss',
patterns: [
path.resolve(__dirname, 'src/styles/_variables.scss'),
path.resolve(__dirname, 'src/styles/_mixins.scss')
]
}
},
chainWebpack: config => {
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
config.set('name', name)
config
.when(process.env.NODE_ENV !== 'development',
config => {
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
// { bypassOnDebug: true }
mozjpeg: { progressive: true, quality: 65 }, // ∂Compress JPEG images
optipng: { enabled: false }, // Compress PNG images
pngquant: { quality: [0.65, 0.9], speed: 4 }, // Compress PNG images
gifsicle: { interlaced: false } // Compress SVG images
// webp: { quality: 75 }
})
.end()
const externals = {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
axios: 'axios',
qs: 'Qs',
'element-ui': 'ELEMENT',
echarts: 'echarts',
dexie: 'Dexie',
'js-cookie': 'Cookies',
nprogress: 'NProgress'
}
config.externals(externals)
// 引入cdn
config.plugin('html').tap(args => {
args[0].cdn = cdn
return args
})
// 打包成gzip压缩文件
config.plugin('compressionPlugin')
.use(new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true
}))
config
.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: path.resolve(__dirname, 'src/components'),
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single')
}
)
}
}