各位知友,关于Vue框架的前端项目脚手架,优秀的代码仓库/博客文章已经很多,为什么我还要做这么一件事呢?我是想打算做一个前端工程化的体系分享,其中主要有:
- Vue脚手架的基础搭建和优化
- 基于vue-cli的 企业级脚手架
- Jenkins持续集成
期待各位知友一起学习分享,共同进步!
废话不多说,先上仓库地址
背景
有序、开箱即用、开关式配置、脚手架打包、加载优化
技术栈
Vue3.2、Webpack5、Vant、Typescript、Pretter、Eslint、Vuex、Axios、Sass
分支管理
| 环境 | 分支 | 全局环境变量标识 | npm脚本命令 |
|---|---|---|---|
| 开发 | development | development | npm run dev |
| 测试 | development-fix | development-fix | npm run build-dev-fix |
| 预发布 | release | release | npm run build-release |
| 生产 | production | production | npm run build |
打包优化方案
在脚手架代码/打包优化方面,主要做了下面的优化措施,针对每一点,接下来会详细和各位知友,通过代码块分享。
禁用js和css的预加载 Gzip打包压缩 全局环境变量+打包配置 跨域proxy代理 修复 HMR(热更新)失效 添加请求别名Alias px转rem移动端适配 svg图标组件 图片压缩 cdn加载包文件 去除console.log sass全局样式 prerender-spa-plugin 预渲染开启(更好的SEO,比SSR开发成本低,代码侵入性低) 骨架屏 添加打包分析report
- 禁用js和css的预加载
通过降低浏览器带宽请求,提高页面的加载速度
config.plugins.delete('preload')
config.plugins.delete('prefetch')
- Gzip打包压缩
项目打包上线时,发现build后的包体积很大,导致首屏加载速度慢,Gzip就能明显有效的解决这个问题,其实原理就是把原js、css进行压缩,从而减少打包文件体积,提高首屏的访问速度。
首先,需要引入Webpack插件 compression-webpack-plugin
yarn add compression-webpack-plugin --dev
const CompressionPlugin = require('compression-webpack-plugin')
其次,vue.config.js增加plugins的关键配置即可
// VUE_APP_GLOBAL_ENV 是全局环境变量
const isProduction = process.env.VUE_APP_GLOBAL_ENV !== 'development'
const productionGzipExtensions = ['js', 'css']
module.exports = {
configureWebpack: (config) => {
// 打包环境
if (isProduction) {
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip', // 压缩算法、函数
test: new RegExp('\.(' + productionGzipExtensions.join('|') + ')$'), //需要压缩的文件
threshold: 10240, // 处理大于10240字节的文件
minRatio: 0.8, // 压缩率
deleteOriginalAssets: false // 是否删除原文件
})
)
}
}
}
在Nginx配置方面,需要在nginx.conf开启Gzip
#gzip on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
#gzip_http_version 1.0;
gzip_comp_level 2;
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 off;
gzip_disable "MSIE [1-6].";
- 全局环境变量+打包配置
在实际开发过程中,有时需要区分不同的开发、打包环境,比如最常见的接口域名:本地开发、测试、预发布、生产;为了统一配置,减少代码频繁更改。
首先关于环境变量文件名,必须以如下方式命名,也不需要专门手动控制加载那个文件。
.env 全局默认配置文件,不论什么环境都会加载合并
.env.development 开发环境下的配置文件
.env.development-fix 测试环境下的配置文件
.env.release 预发布环境下的配置文件
.env.production 生产环境下的配置文件
根据vue的启动命令vue会自动加载对应的环境,所以上面说,明明要规范且对应;配置package.json文件可以具体设置启动具体加载哪个.env.xxx文件。
"dev": "vue-cli-service serve",
"build-fix": "vue-cli-service build --mode development-fix --report",
"build-release": "vue-cli-service build --mode release --report",
"build": "vue-cli-service build --mode production --report",
其次就是配置文件中的内容,自定义属性配置必须以 VUE_APP开头,比如:VUE_APP_API_URL
- 跨域proxy代理
vue-cli中的proxy主要为了解决本地开发环境下,资源请求跨域的问题;
首先,在vue.config.js文件下,配置devServer,在本地运行的时候,会自动加载
module.exports = {
devServer: {
port: '8088', // 端口号,可以不指定
hot: true,
open: true,
https: true,
proxy: {
'/coudMusicApi': {
target: process.env.VUE_APP_API_URL, // 这里就用到了全局配置文件下的公共变量
changeOrigin: true,
secure: false,
pathRewrite: {
'/coudMusicApi': '/'
}
}
}
}
}
其次,比如在发送接口请求时,直接配置上标识即可
export const getApi = () => {
return request.request({
method: RequestTypeEnum.GET,
url: 'coudMusicApi/countries/code/list'
})
}
编辑切换为居中
添加图片注释,不超过 140 字(可选)
虽然我们再浏览器F12看到的虽然是本地域名,实际上已经代理到了真实的接口地址。
- 修复 HMR(热更新)失效
本地运行时,浏览器会以下报错
编辑切换为居中
添加图片注释,不超过 140 字(可选)
就需要通过以下配置解决
module.exports = {
chainWebpack: (config) => {
// 解决热更失效问题
config.resolve.symlinks(true)
}
}
- 添加请求别名Alias
添加请求别名,减少冗余代码,具体配置如下:
const { resolve } = require('path')
module.exports = {
config.resolve.alias
.set('@', resolve('src'))
.set('@assets', resolve('src/assets'))
.set('@styles', resolve('src/styles'))
}
- px转rem移动端适配
px 转rem解决移动端适配方案,是兼容性相对较好,上手较为简单的一种方案。方案的落地方式有很多,我选择了 postcss-pxtorem 结合 amfe-flexible,具体配置如下:
安装插件包
yarn add amfe-flexible
yarn add postcss-pxtorem
在vue.config.js中配置postcss插件
module.exports = {
css: {
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 37.5,
propList: ['*']
})
]
}
}
}
main.ts中,引入amfe-flexible
import 'amfe-flexible/index.js'
最终效果如下:
编辑
添加图片注释,不超过 140 字(可选)
编辑
添加图片注释,不超过 140 字(可选)
- svg图标组件
为了解决引入svg图标,现在又两个比较好用的loader:
sass-loader、svg-sprite-loader
原理就不讲了,我们就直接看如何使用的吧
引入loader
yarn add svg-sprite-loader --dev
yarn add svg-loader --dev
接下来配置vue.config.js 的loader
module.exports = {
chainWebpack: (config) => {
// 配置svg: 添加svg-sprite-loader插件,加载svg图标
config.module
.rule('svg-icon')
.include.add(resolve('src/assets/icon/svg'))
.end()
.test(/.svg$/)
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
// 删除自带的svg解析规则
config.module.rule('svg').exclude.add(resolve('src/assets/icon/svg'))
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
}
}
前提,需要把svg的图标文件,放在 src/assets/icon/svg 下。
如何封装公共svg的组件,在项目中的 components文件夹下的 v-svg-icon 中的文件,已经提供给大家,这里我就不详细展开了。
- 图片压缩
webpack中一般使用 image-webpack-loader 处理PNG、JPG图片压缩,接下来就重点说下如何使用插件进行图片压缩
安装插件
yarn add image-webpack-loader --dev
在vue.config.js中配置loader
module.exports = {
chainWebpack: (config) => {
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
}
}
- cdn加载包文件
首先,我们要了解,为什么要使用cdn加载包文件?
默认情况下,通过import语法导入的第三方依赖包,最终会被打包到同一个文件中,从而导致打包成功后,单文件体积过大的问题。为了解决上述问题,可以通过webpack的externals节点,配置并加载依赖包的cdn资源。
const isProduction = process.env.VUE_APP_GLOBAL_ENV !== 'development'
module.exports = {
configureWebpack: (config) => {
if (isProduction) {
config.externals = { vant: 'vant' }
}
}
}
如果只是这样,那么怎么加载cdn的依赖包呢?
为了方便统一配置,我们统一管理js、css文件,并使用webpack的链式调用;
const cdn = {
css: ['//cdn.jsdelivr.net/npm/vant@2.12/lib/index.css'],
js: [
'//cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js'
]
}
const isProduction = process.env.VUE_APP_GLOBAL_ENV !== 'development'
module.exports = {
chainWebpack: (config) => {
if (isProduction) {
config.plugin('html').tap((args) => {
args[0].title = 'piece'
// html中添加cdn
args[0].cdn = cdn
return args
})
}
}
}
承载文件index.html中引入;
<html>
<head>
<!-- 使用CDN的CSS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
<% } %>
</head>
<body>
...
</body>
<!-- 使用CDN的JS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
</html>
- 去除console.log
这个其实没什么好说的,直接上配置代码;关于uglifyjs-webpack-plugin插件的配置字段,大家看下看下webpack的中文文档 uglifyjs-webpack-plugin
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const isProduction = process.env.VUE_APP_GLOBAL_ENV !== 'development'
module.exports = {
configureWebpack: (config) => {
if (isProduction) {
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
output: {
comments: false // 去掉注释
},
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: [
'console.log',
'console.warn',
'console.info',
'console.error',
'console.debug'
] // 移除console信息打印
},
warnings: false
},
sourceMap: false,
parallel: true
})
)
}
}
}
- sass全局样式
在vue-cli中全局使用scss的全局变量或者全局样式,需要安装插件,然后再vue.conf.js中配置;一般使用的插件是 style-resources-loader;但是需要制定sass-loader和style-resources-loader的版本,否则vue-cli会出现一些问题,本次我们先从简单的角度切入,在main.ts中直接引入全局样式文件;
import '../src/styles/_module.scss'
这里@各位知友,有谁可以通过webpack的方式,实现全局样式文件的加载,不妨留个言呀。
- prerender-spa-plugin 预渲染开启
众所周知,使用vue-cli打包项目一般为SPA项目,不利于SEO,目前有服务端渲染SSR和预渲染两种处理方案;这里我们只讨论预渲染的方案;
首先,安装插件
yarn add prerender-spa-plugin --dev
其次,配置插件
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const isProduction = process.env.VUE_APP_GLOBAL_ENV !== 'development'
module.exports = {
if (isProduction) {
config.plugins.push(
new PrerenderSPAPlugin({
staticDir: join(__dirname, 'dist'),
// 对应自己的路由文件
routes: ['/home'],
// 忽略重定向redirects
postProcess(renderedRoute) {
renderedRoute.route = renderedRoute.originalRoute
return renderedRoute
},
renderer: new PrerenderSPAPlugin.PuppeteerRenderer({
inject: {
foo: 'bar'
},
headless: false,
// 在 main.js 中,或者需要预处理的路由文件中, document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
renderAfterDocumentEvent: 'render-event'
})
})
)
}
}
这样,成功执行build之后,就可以看到dist文件夹下,多了home这个文件夹,并且在此文件夹下有.html文件。
- 骨架屏
目前基于Vue3版本的骨架屏方案还未有相关插件支撑,应用较广的vue-skeleton-webpack-plugin插件目前也未支持,所以,暂时还是考虑自己实现,功能简单,开发工作量较大,这个问题智能等到后面优化了。
首先,我们引入一个组件:vue-skeletor,实现骨架屏元素的基本功能
yarn add vue-skeletor --dev
然后在对应的页面下,添加骨架屏组件
编辑切换为居中
添加图片注释,不超过 140 字(可选)
在当前组件中,引入骨架屏元素
import 'vue-skeletor/dist/vue-skeletor.css'
import { Skeletor } from 'vue-skeletor'
具体代码,参照组件内编写,我们看最终实现的效果,这样就完成啦~,是不是非常简单
编辑
添加图片注释,不超过 140 字(可选)
\
- 添加打包分析report
配合webpack和插件webpack-bundle-analyzer使用,生成基于vue-cli的代码分析报告,帮助提升代码质量和网站性能。
使用方案也比较简单,安装插件后,在vue.config.js中配置。
安装插件
yarn add webpack-bundle-analyzer --dev
在vue.config.js中配置
module.exports = {
chainWebpack: (config) => {
if (isProduction) {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
}
}
}
配置按成后,执行build命令,浏览器会默认打开以下页面,可以清晰的分析打包后的文件体积及组成,方便进行加载速度优化。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
设计到多个配置文件,完成的vue.config.js文件我就不把代码贴出来了,感兴趣的知友可以到项目 中查看。还有哪些优化的措施或者方案,可以在评论区讨论或者私信留言哦~
结束语
欢迎大家多提意见,赠人玫瑰,手有余香!
\