最近着手重构优化一个Vue的项目,最明显的问题就是首屏加载缓慢。我们都知道请求一个资源快慢无非两个要素:带宽(网速)+ 文件大小,作为一个开发我们只能从文件体积方面进行深入优化:压缩代码,压缩图片,小图片转base64,开启Tree-sharking优化去除无用代码,资源分割打包拆分如Vue,JQuery等分离出来单独打包成一个文件,有条件可放在CDN上。
1.安装node.js,在官网下载相应版本进行安装。安装完成后在命令行模式下输入node -v查看是否安装成功。
2.安装淘宝npm(cnpm):npm install -g cnpm --registry=https://registry.npm.taobao.org npm是国外服务下载,下载速度较慢。
3.安装全局webpack(-g代表全局安装): cnpm install webpack@5 webpack-cli@4 webpack-dev-server@3 -g
(@5表示安装5的版本)这里我把安装webpack-dev-server也一并安装了,我选用了webpack-dev-server3的版本,因为有些版本与webpack5不兼容。
4.切换到项目目录,安装本地webpack:cnpm install webpack@5 webpack-cli@4 webpack-dev-server@3 --save-dev
在项目目录中安装webpack,其中,--save-dev会在 devDependencies 里记录,只是开发和打包时会用到的,但实际上线并不需要;--save会在 dependencies 里记录,除了开发需要,实际上线的时候也需要的
5.初始化package.json文件:npm init -y
这里我就不过多介绍什么了,所使用的配置基本上我都标明了注释,这里所展示的仅是我个人所需的一些loader和plugin的配置,有些我没有用到的比如:cache-loader、thread-loader之类的需要的可以自己补充。直接上代码:
/**
* @author zhangshuo
* @date 2021/9/26 13:09
*
* webpack5 优化打包处理配置
**/
const MiniCssExtractPlugin=require("mini-css-extract-plugin");//css提取插件
const CssMinimizerWebpackPlugin=require("css-minimizer-webpack-plugin");//css压缩插件
const HtmlWebpackPlugin=require("html-webpack-plugin");//html处理
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const path = require('path');
module.exports={
//production or development
//webpack4之后,指定使用 production mode 时,默认会启用各种性能优化的功能,包括构建结果优化以及 webpack 运行性能优化
//包括代码压缩,tree-sharking:Tree-shaking的本质是消除无用的js代码(包括第三方库例如jquery、vue等,只打包用到的方法,只支持函数式编程)
mode: "development",
//入口
entry: {
app:"./src/main.js",//app为name
},
//出口
output: {
path: __dirname+"/out/",//path:输出路径,__dirname:node.js内置变量,代表当前项目绝对路径
filename: "js/[name].[chunkhash].js",//[name]取入口name值,[hash]用来解决浏览器缓存文件问题,chunkhash是根据具体模块文件的内容计算所得的hash值,所以某个文件的改动只会影响本模块的hash值
//clean: true,//清除输出目录,dev模式下开启会影响热更新,prd模式下可开启使用
environment: {
arrowFunction: false //不使用箭头函数
}
},
devtool: 'source-map', //调试工具
//在webpack5版本中使用默认或者'web'参数时,hot热部署是有效的。但是编译的runtime代码IE浏览器不识别,语法不支持
//使用target: ['web','es5'],可以使编译的代码使用es5的特性,能正常在IE中使用。但是热更新失效
//webpack5热更新失效问题只能等待官方新版本中会得到优化解决,暂时建议在开发模式中使用target: 'web',在生产模式中使用target: ['web','es5']
target: 'web',//热启动生效,IE无法识别runtime代码
/*target: ['web','es5'],*/ //热启动失效,IE可以正常使用
//vue有两种形式的代码 compiler(模板)模式和runtime模式(运行时),vue模块的package.json的main字段默认为runtime模式, 指向了"dist/vue.runtime.common.js"位置。
//也就是说,import Vue from ‘vue’ 这行代码被解析为 import Vue from ‘vue/dist/vue.esm.js’,直接指定了文件的位置,没有使用main字段默认的文件位置
resolve: {
alias: {//别名
'vue$': 'vue/dist/vue.esm.js',
'@': '/src',
},
extensions: ['.js', '.vue','.json']//指定后缀
},
//把第三方库单独提取打包,例如:vue jquery等
//多页面应用:主要业务代码->页面公用模块+第三方库vender
//单页面应用: 主要业务代码->异步加载js+第三方库vender
optimization: {
splitChunks: {
// 模块加载的方式:异步的还是同步的 all, initial, async
chunks: 'all',
// 需要打包的最小尺寸,如果模块的大小小于这个值,就不单独打包
minSize: 1024*1000,
// 需要单独打包的模块需要按照这个尺寸再次拆包, 0不拆包
maxSize: 1024*1024*10,
// 单个模块被引用的次数,超过这个值的时候才会单独打包
minChunks: 1,
// 表示index.html页面上可以引入的.js文件最大个数
maxInitialRequests: 6,
name:"chunk",
cacheGroups: {
vendors: {
// 模块载入路径的匹配
test: /[\\/]node_modules[\\/]/,
// 同时满足多个test匹配的时候,priority值越大,越优先
priority: -10,
name: "vendor"
},
jquery: {
test: /jquery/,
priority: 10,
name: "jquery"
},
}
}
},
//开发模式->打包->打包内容给到webpack-dev-server->dev-server拿到打包内容,开启node服务->node服务加载打包内容->呈现页面
//安装webpack-dev-server,需要全局和本地都安装:cnpm install webpack-dev-server@3 -g/cnpm install webpack-dev-server@3 --save
//开发模式提供:热更新和自动替换 代理转发(自动替换作用于js)
devServer: {
contentBase: path.join(__dirname, "out"),//指定运行的根路径
hot: true,//热更新,只作用于css
hotOnly:false,// 页面构建失败不刷新页面
port: 3000, //端口号
host: "localhost",
compress: true,//采用gzip压缩
inline:true,//内联方式打开
progress:true,//开启进度条
open:true, //启动后直接打开浏览器
proxy:{//代理转发,匹配到/api/test——>http://localhost:8000/test/
"/api":"http://localhost:8000/"
},
},
//loader:处理某种资源文件
module: {
//test:匹配一个正则,定义这个loader处理哪种类型的文件
rules: [
//处理css:1,引入style-loader和css-loader 2,定义style-loader和css-loader来处理css类型 3,mini-css-extract-plugin提取出来
//cnpm install style-loader css-loader --save
//cnpm install mini-css-extract-plugin --save
{
test:/\.css$/,
use: [//定义多个loader,从后往前执行
{
loader: MiniCssExtractPlugin.loader
},
{
loader:"css-loader"
},
]
},
//es6-->es5 使用bable 将es6语法编译成es5语法
//cnpm install babel-loader @babel/core --save
//cnpm install @babel/preset-env --save
{
test: /\.js$/,
use: [
{
loader: "babel-loader",
options: {
presets:[
[
"@babel/preset-env",{
targets:{
browsers:[">1%","ie>=7"]//市场使用率大于1%的浏览器,大于等于ie7的浏览器
}
}
]
],
cacheDirectory: true // 自动babel缓存
}
}
]
},
//处理图片 url-loader:cnpm intsall file-loader url-loader --save
//压缩大图片 使用安装 image-webpack-loader 依赖:image-loader imagemin imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant
{
test:/\.(jpg|png|jpeg|gif)$/,
use: [
{
loader: "url-loader",
options: {
limit:5000,//5kb以下小图片转成Base64
name: '[name].[ext]',//图片名称及后缀
outputPath: './img',//负责输出目录
publicPath: '/img',//对页面引入资源的补充
esModule: false //esModule默认为true会导致打包图片文件时路径错误输出为[object-module]
}
},
{
loader: "image-webpack-loader",//使用就默认压缩
//可根据参数调整压缩程度
options: {
mozjpeg:{//jpeg图片压缩
quality:65 //1-100 压缩程度,值越小压缩越多
},
pngquant:{//png图片压缩
speed:4 //1-11
},
gifsicle:{//gif图片压缩
level:3 //1-3
}
}
}
]
},
//让webpack识别vue模板,cnpm install vue vue-loader --save,cnpm install vue-template-compiler --save
{
test:/.vue$/,
loader:'vue-loader'
}
]
},
//plugins:插件,提供一些webpack没有的功能
plugins: [
new CssMinimizerWebpackPlugin(),//压缩css: cnpm install css-minimizer-webpack-plugin --save
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash].css"//contenthash是针对文件内容级别的,只有你自己的内容变了,那么hash值才改变
}),
//处理html,安装插件cnpm install html-webpack-plugin --save
new HtmlWebpackPlugin({
template:"./index.html",//指定模板文件
filename: "index.html",//文件名
minify:{
removeComments:true,//清理html中的注释
collapseWhitespace:true,//清理html中的空格、换行符
}
}),
new VueLoaderPlugin(),
]
}
1.在package.json文件中配置scripts 运行和打包命令
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"bulid": "webpack --config webpack.config.js",
"dev": "webpack serve --config webpack.config.js"
},
webpack是打包命令,webpack5的运行命令是webpack serve,--config 指定配置文件的位置,与package.josn同级目录可以默认不写。
2.本文中用到的一些loader和plugin汇总
cnpm install html-webpack-plugin --save-dev
cnpm install css-minimizer-webpack-plugin --save-dev
cnpm install style-loader css-loader --save-dev
cnpm install mini-css-extract-plugin --save-dev
cnpm install babel-loader @babel/core --save-dev
cnpm install @babel/preset-env --save-dev
cnpm intsall file-loader url-loader --save-dev
cnpm install image-webpack-loader --save-dev
cnpm insatll image-loader imagemin imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant --save-dev
cnpm install vue-loader --save-dev
cnpm install vue-template-compiler --save-dev
cnpm install babel-plugin-component --save-dev
cnpm install vue --save
cnpm install element-ui --save
cnpm install vue-router --save
3.路由组件懒加载和element-ui组件按需加载
路由懒加载:像vue这种单页面应用,如果没有懒加载,当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
import Vue from 'vue'
import Router from 'vue-router'
/*import HelloWorld from '/src/components/HelloWorld.vue'*/
const HelloWorld = () => import('/src/components/HelloWorld.vue') //路由懒加载
Vue.use(Router)
const router=new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
//导航守卫
router.beforeEach((to, from, next) => {
console.log(to.path)
next()
})
export default router
element-ui组件按需加载:项目中使用的element-ui组件只要不是特别多或者是全部都用到都可以只引入我们所需要的组件,这样可以减少项目体积。
/**
* @author zhangshuo
* @date 2021/9/29 16:27
* 导入自己需要的element-UI组件,按需加载
**/
import {Input, Dialog, Button} from 'element-ui'
const element = {
install: function (Vue) {
Vue.use(Input)
Vue.use(Dialog)
Vue.use(Button)
}
}
export default element
在main.js中引入:
import element from './util/element.js' Vue.use(element)
想要使用element-ui按需加载就需要安装babel-plugin-component,安装命令在上面汇总中。然后要在根目录下创建babel.config.js文件,写上以下配置:
module.exports = {
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
]
]
}
4.最后截一张项目下目录结构图给大家,以上内容仅供参考,如果只是做vue项目,还是建议大家使用vue-cli的方式更方便,我这里用的webpack5,所以自己手写的配置。