上海网站建设 建站猫/网页制作的步骤
打包优化的目的
- 项目启动速度,和性能
- 必要的清理数据
- 减少打包后的体积
- 第一点是核心,第二点呢其实主要是清理console
性能优化的主要方向
- 去除.map文件
- 开启CDN加速
- 代码压缩
- 图片压缩
- 公共代码抽离,写在configureWebpack模块中
- 首屏骨架屏优化
- 开启Gzip压缩
打包优化
1.去除.map文件
在vue.config.js中添加
module.exports = {productionSourceMap: false, //不输出map文件
}
2.开启CDN加速
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development';// 本地环境是否需要使用cdn
const devNeedCdn = false// cdn链接
const cdn = {// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)externals: {vue: 'Vue',vuex: 'Vuex','vue-router': 'VueRouter','marked': 'marked','highlight.js': 'hljs','nprogress': 'NProgress','axios': 'axios'},// cdn的css链接css: [],// cdn的js链接js: ['https://cdn.bootcss.com/vue/2.6.10/vue.min.js','https://cdn.bootcss.com/vuex/3.1.2/vuex.min.js','https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js','https://cdn.bootcss.com/axios/0.19.2/axios.min.js']
}module.exports = {chainWebpack: config => {// ============注入cdn start============config.plugin('html').tap(args => {// 生产环境或本地需要cdn时,才注入cdnif (isProduction || devNeedCdn) args[0].cdn = cdnreturn args})// ============注入cdn start============},configureWebpack: config => {// 用cdn方式引入,则构建时要忽略相关资源if (isProduction || devNeedCdn) config.externals = cdn.externals}
}
<!-- 使用CDN的CSS文件 --><% for (var i in htmlWebpackPlugin.options.cdn &&htmlWebpackPlugin.options.cdn.css) { %><linkhref="<%= htmlWebpackPlugin.options.cdn.css[i] %>"rel="stylesheet"/><% } %><!-- 使用CDN的CSS文件 --><!-- 使用CDN的JS文件 --><% for (var i in htmlWebpackPlugin.options.cdn &&htmlWebpackPlugin.options.cdn.js) { %><script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script><% } %><!-- 使用CDN的JS文件 -->
3.代码压缩
安装插件 npm i -D uglifyjs-webpack-plugin
// 代码压缩
//在configureWebpack中加入
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
// 代码压缩
config.plugins.push(new UglifyJsPlugin({uglifyOptions: {//生产环境自动删除consolecompress: {drop_debugger: true,drop_console: true,pure_funcs: ['console.log']}},sourceMap: false,parallel: true})
)
4.图片压缩
安装插件 npm install image-webpack-loader --save-dev
在chainWebpack中新增以下代码// ============压缩图片 start============config.plugins.delete('prefetch')config.module.rule('images').test(/\.(png|jpe?g|gif|svg)(\?.*)?$/).use('image-webpack-loader').loader('image-webpack-loader').options({ bypassOnDebug: true })
// ============压缩图片 end============
5.公共代码抽离,写在configureWebpack模块中
// 公共代码抽离
config.optimization = {splitChunks: {cacheGroups: {vendor: {chunks: 'all',test: /node_modules/,name: 'vendor',minChunks: 1,maxInitialRequests: 5,minSize: 0,priority: 100},common: {chunks: 'all',test: /[\\/]src[\\/]js[\\/]/,name: 'common',minChunks: 2,maxInitialRequests: 5,minSize: 0,priority: 60},styles: {name: 'styles',test: /\.(sa|sc|c)ss$/,chunks: 'all',enforce: true},runtimeChunk: {name: 'manifest'}}}
}
6.骨架屏
安装插件 npm install vue-skeleton-webpack-plugin
在src下新建Skeleton文件夹,其中新建index.js以及index.vue,在其中写入以下内容,其中,骨架屏的index.vue页面样式请自行编辑
index.js
import Vue from 'vue'
import home from './index.vue'
import list from './a.vue'
export default new Vue({components: {home,list},template: `<div><home id="home" style="display:none"/><list id="list" style="display:none"/></div>`
})
骨架屏页面
<template><div class="skeleton-wrapper"><header class="skeleton-header"></header><section class="skeleton-block"><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg=="><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg=="></section></div>
</template><script>export default {name: 'skeleton'}
</script><style scoped>.skeleton-header {height: 40px;background: #1976d2;padding:0;margin: 0;width: 100%;}.skeleton-block {display: flex;flex-direction: column;padding-top: 8px;}</style>
vue.config.js
//骨架屏渲染
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')//path引入
const path = require('path')//configureWebpack模块中写入内容
// 骨架屏渲染
config.plugins.push(new SkeletonWebpackPlugin({webpackConfig: {entry: {app: path.join(__dirname, './src/Skeleton/index.js'),},},minimize: true,quiet: true,// 如果不设置那么所有的路由都会共享这个骨架屏组件router: {mode: 'hash',// 给对应的路由设置对应的骨架屏组件,skeletonId的值根据组件设置的idroutes: [{ path: '/list', skeletonId: 'home' },{ path: '/kc', skeletonId: 'list' },]}))
7.开启Gzip压缩
注意的是,服务器上nginx也必须开启gzip才能生效
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development';// gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin')module.exports = {productionSourceMap: false,configureWebpack: config => {// 生产环境相关配置if (isProduction) {//gzip压缩const productionGzipExtensions = ['html', 'js', 'css']config.plugins.push(new CompressionWebpackPlugin({filename: '[path].gz[query]',algorithm: 'gzip',test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),threshold: 10240, // 只有大小大于该值的资源会被处理 10240minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理deleteOriginalAssets: false // 删除原文件}))}}
}
nginx中
# 开启gzipgzip on;# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩gzip_min_length 1k;# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明gzip_comp_level 2;# 进行压缩的文件类型。javascript有多种形式,后面的图片压缩不需要的可以自行删除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;# 是否在http header中添加Vary: Accept-Encoding,建议开启gzip_vary on;# 设置压缩所需要的缓冲区大小 gzip_buffers 4 16k;
全部代码
// vue.config.js
//骨架屏渲染
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')//path引入
const path = require('path')
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development';
// 代码压缩
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')// 本地环境是否需要使用cdn
const devNeedCdn = false
// cdn链接
const cdn = {// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)externals: {vue: 'Vue',vuex: 'Vuex','vue-router': 'VueRouter','axios': 'axios','element-ui': 'ELEMENT','vant':'vant'},// cdn的css链接css: ['https://unpkg.com/element-ui/lib/theme-chalk/index.css','https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css',],// cdn的js链接js: ['https://cdn.bootcss.com/vue/2.6.10/vue.min.js','https://cdn.bootcss.com/vuex/3.1.2/vuex.min.js','https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js','https://cdn.bootcss.com/axios/0.19.2/axios.min.js','https://unpkg.com/element-ui/lib/index.js','https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js']
}module.exports = {lintOnSave: false,publicPath: './',css: {loaderOptions: {postcss: {plugins: [require('postcss-plugin-px2rem')({rootValue:35, //换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。// unitPrecision: 5, //允许REM单位增长到的十进制数字。//propWhiteList: [], //默认值是一个空数组,这意味着禁用白名单并启用所有属性。// propBlackList: [], //黑名单// exclude: /(page_pc)/i, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值exclude: /node_modules/i,// selectorBlackList: ['van-'], //要忽略并保留为px的选择器,我们一般不转换vantui中的大小// ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。// replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。mediaQuery: false, //(布尔值)允许在媒体查询中转换px。minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0}),]}}},productionSourceMap: false, //不输出map文件chainWebpack: config => {// ============注入cdn start============config.plugin('html').tap(args => {// 生产环境或本地需要cdn时,才注入cdnif (isProduction || devNeedCdn) args[0].cdn = cdnreturn args})// ============注入cdn start============// ============压缩图片 start============config.module.rule('images').use('image-webpack-loader').loader('image-webpack-loader').options({bypassOnDebug: true}).end()
// ============压缩图片 end============},configureWebpack: config => {if (isProduction || devNeedCdn) config.externals = cdn.externalsconfig.plugins.push(new SkeletonWebpackPlugin({webpackConfig: {entry: {app: path.join(__dirname, './src/Skeleton/entry-skeleton.js'),},},minimize: true,quiet: true,router: {mode: 'hash',// 给对应的路由设置对应的骨架屏组件,skeletonId的值根据组件设置的idroutes: [{ path: '/list', skeletonId: 'skeleton' }]}}))// 用cdn方式引入,则构建时要忽略相关资源// if (isProduction || devNeedCdn) config.externals = cdn.externals
// 公共代码抽离
config.optimization = {splitChunks: {cacheGroups: {vendor: {chunks: 'all',test: /node_modules/,name: 'vendor',minChunks: 1,maxInitialRequests: 5,minSize: 0,priority: 100},common: {chunks: 'all',test: /[\\/]src[\\/]js[\\/]/,name: 'common',minChunks: 2,maxInitialRequests: 5,minSize: 0,priority: 60},styles: {name: 'styles',test: /\.(sa|sc|c)ss$/,chunks: 'all',enforce: true},runtimeChunk: {name: 'manifest'}}}
}// 代码压缩
config.plugins.push(new UglifyJsPlugin({uglifyOptions: {//生产环境自动删除consolecompress: {drop_debugger: true,drop_console: true,pure_funcs: ['console.log']}},sourceMap: false,parallel: true})
)},}