项目配置相关的功能都完成以后,目前项目已经可以作为一个脚手架去使用了,这里先看一下打包生产环境是否有问题,在执行打包生产环境时,目前项目会有报错出现,其主要是src/router/index.ts
文件中,导入路由模块时,await
不是单独使用,需配合async
使用,这里需要修改一下:
// 自动导入modules文件夹下的所有路由模块
const modules = import.meta.globEager("./modules/*.ts");
const routes:any = [];
for(const path in modules){
modules[path].default.forEach(function(item: any){
routes.push(item);
});
}
这里换一种写法即可,此时再次打包生产环境代码,就不会再有报错问题出现了。
默认的打包分析文件report.html
是放在了根目录,这里修改一下生成到生产环境的打包目录根路径内,修改vite.config.ts
文件:
plugins: [
...
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: VITE_OUTDIR+"/report.html" })
: null
]
修改src/mockProdServer.ts
文件:
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
const modules = import.meta.globEager('../mock/*.ts')
const mockModules: any[] = []
Object.keys(modules).forEach((key) => {
modules[key].default.forEach((item) => {
mockModules.push(item)
})
})
export function setupProdMockServer() {
createProdMockServer(mockModules)
}
这里批量将mock
文件夹下得模拟数据导入,用于生产环境使用。
修改tsconfig.json
文件:
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","vite.config.ts","build/*.ts", "types/*.d.ts", "mock/*.ts"],
以上修改后,生产环境使用mock
模拟数据的配置是完成了,但如果直接本地起服务运行打包后的生产环境代码,mock
模拟数据依然无法使用。需要修改配置文件vite.config.ts
:
viteMockServe({
mockPath: './mock', // 模拟接口api文件存放的文件夹
watchFiles: true, // 将监视文件夹中的文件更改。 并实时同步到请求结果
localEnabled: command === 'serve' // ,设置是否启用本地 xxx.ts 文件,不要在生产环境中打开它.设置为 false 将禁用 mock 功能
}),
这里将之前配置的生产环境启用mock相关代码移除,配置在这里不生效,目前暂未发现为何如此,除了配置在这里外,还可以直接配置到src/main.ts
文件中:
import { setupProdMockServer } from './mockProdServer'
// production mock server
if (process.env.NODE_ENV === 'production') {
setupProdMockServer()
}
然后修改.env
相关文件,增加NODE_ENV
变量配置,各环境变量文件各自增加该变量,值为对应环境名即可。
此时再重新生成生产环境代码,启动本地服务,mock
功能就可以正常使用了。
打包后的文件有些太大,大文件需要再次拆分,拆分的原理就是项目在打包时,将很多插件都打包到了一个文件内,这里需要做的是将那些大插件单独进行打包,小插件可以合并打包到一个文件。
修改vite.config.ts
文件:
// 生产环境配置
build:{
outDir:VITE_OUTDIR,
assetsDir:"assets",
sourcemap:false,
brotliSize:false,
reportCompressedSize:false,
// 消除打包大小超过500kb警告
chunkSizeWarningLimit:1024,
minify: 'terser',
target: 'esnext',
rollupOptions:{
output:{
manualChunks(id){
if (id.includes('node_modules')) {
const currentPlugin = id.toString().split('node_modules/')[1].split('/')[0].toString();
if(currentPlugin=="element-plus"||currentPlugin=="@element-plus"||currentPlugin=="lodash-es"||currentPlugin=="@vue"||currentPlugin=="china-area-data"){
return currentPlugin;
}else if(currentPlugin=="@iconify"){
const iconType = id.toString().split('node_modules/')[1].split('/')[3].split('.')[0].toString()
return currentPlugin+'_'+iconType;
}else{
return '_vendor';
}
}
}
}
}
},
这里主要是对打包过程进行了判断,将资源比较大的插件,进行了单独打包,特别是@iconify
插件,本身项目引入了其中的5个图标集,每个图标集的json
文件都非常大,这里针对该文件也做了特定的逻辑判断,将5个图标集都分别打包成一个文件,此时再打包项目,资源除了gif
图片还是太大外,其它资源文件就只有element-plus
以及@iconify
的每个图标集文件还是太大,这个是资源本身就多,已无法再次拆分
项目在之前配置了vite-plugin-remove-console
插件用来移除console
,vite
本身是可以通过配置实现移除console
的,这里删除vite-plugin-remove-console
相关代码,修改vite.config.ts
文件:
// 生产环境配置
build:{
...
// 清除console和debugger
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
...
},
npm i vite-plugin-imagemin -D
修改vite.config.ts
文件:
import viteImagemin from 'vite-plugin-imagemin'
plugins:[
...
viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
webp: {
quality: 75,
},
mozjpeg: {
quality: 65,
},
pngquant: {
quality: [0.65, 0.9],
speed: 4,
},
svgo: {
plugins: [
{
removeViewBox: false,
},
{
removeEmptyAttrs: false,
},
],
},
})
]
该配置完成后在打包线上环境的代码,图片资源就会被自动压缩(gif压缩有可能压缩后会变更大)
需要注意该插件的安装会比较麻烦,如下载不成功可按插件官方指明的方式进行安装。
前端开启gzip压缩,后端需要做相应的配置,开启gzip压缩后,可以减少对服务端内存的使用,从而提升浏览器加载速度,提升优化用户性能体验。gzip压缩后,打包的文件中,被gizp压缩的文件会被打包为.gz
格式的文件,在将打包后的文件部署到服务器后,服务端通过配置开启gzip
功能,虽然资源格式是.gz
后缀的文件,但客户端浏览器也依然能成功读取文件内容。
gzip
压缩主要是为了将大的资源压缩成.gz
格式的压缩包,资源整体变小,减少服务端的内存占用,在浏览器下载资源时,也会更快一些,浏览器在下载.gz
格式资源后,再进行解压,解压后的文件与源文件的大小没有变化,这个过程主要是减少服务端内存占用,以及加快浏览器下载速度。
npm i vite-plugin-compression -D
修改vite.config.ts
文件:
import viteCompression from 'vite-plugin-compression'
plugins:[
...
viteCompression({
verbose: true,
disable: false, // 不禁用压缩
deleteOriginFile: false, // 压缩后是否删除原文件
threshold: 10240, // 压缩前最小文件大小
algorithm: 'gzip', // 压缩算法
ext: '.gz', // 文件类型
})
]
gzip
需要配合服务端启用,在服务端成功开启gzip
功能后,可以在chrome
的network
中查看资源的下载,在size
列中,如果一个资源有两个不一样大小的体积显示,则代表gzip
已成功开启。
浏览器是配合服务器启用gzip
,需要在资源请求的时候,在header
里面带上accept-encoding:gzip
参数,服务端接收到header
,发现里面有该配置后,则发送gzip
之后的文件,如果没有,则发送源文件。浏览器则根据response header
来处理要不要针对返回的文件进行解压,然后展示。
现在的所有资源都是统一放在assets
文件夹下,这里进行一些配置,让各类型的文件分别放在不同的文件夹内。并对文件名进行一定的修改。
修改vite.config.ts
文件:
// 生产环境配置
build:{
outDir:VITE_OUTDIR,
assetsDir:"assets/images",
sourcemap:false,
brotliSize:false,
reportCompressedSize:false,
// 消除打包大小超过500kb警告
chunkSizeWarningLimit:1024,
minify: 'terser',
target: 'esnext',
// 清除console和debugger
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
rollupOptions:{
output:{
chunkFileNames: (chunkInfo) => {
const facadeModuleId = chunkInfo.facadeModuleId ? chunkInfo.facadeModuleId.split('/') : [];
let fileName = ''
if(facadeModuleId.length>0&&facadeModuleId[facadeModuleId.length-1]==='index.vue'){
const index = facadeModuleId.indexOf('views');
const idx = facadeModuleId.indexOf('src');
if(idx>0){
if(index>0){
fileName = 'vk_'+facadeModuleId.slice(index+1,facadeModuleId.length-1).join('_');
}else{
fileName = 'vk_'+facadeModuleId.slice(idx+1,facadeModuleId.length-1).join('_');
}
}else{
fileName = 'vk_[name]';
}
}else{
fileName = 'vk_[name]';
}
return `assets/js/${fileName}-[hash].js`;
},
entryFileNames: (chunkInfo) => {
return 'assets/js/vk_[name]-[hash].js'
},
assetFileNames: (assetInfo)=>{
return 'assets/[ext]/vk_[name]-[hash].[ext]';
},
manualChunks(id){
if (id.includes('node_modules')) {
const currentPlugin = id.toString().split('node_modules/')[1].split('/')[0].toString();
if(currentPlugin=="element-plus"||currentPlugin=="@element-plus"||currentPlugin=="lodash-es"||currentPlugin=="@vue"||currentPlugin=="china-area-data"||currentPlugin=="jsencrypt"||currentPlugin=="crypto-js"){
return currentPlugin;
}else if(currentPlugin=="@iconify"){
const iconType = id.toString().split('node_modules/')[1].split('/')[3].split('.')[0].toString()
return currentPlugin+'_'+iconType;
}else{
return '_vendor';
}
}
}
}
}
},
这里修改了assetsDir
的默认值,将资源默认打包到assets/images
文件夹内,并通过修改chunkFileNames
,将拆分的js
文件,打包到assets/js
文件夹内,并通过获取拆分的js
的文件路径拼接命名;作为单页面应用的入口文件,通过修改entryFileNames
,可以修改其打包位置及文件名;assetFileNames
可以将css
文件打包到css
文件夹内,这里因为该插件assetInfo
参数并未返回css
文件的路径,无法根据路径修改文件。
以上修改后,再次打包,各类型文件就生成到了各自类型的文件夹中了。而且js文件也根据其具体拆分文件的路径进行了命名。
该插件是用来做低版本浏览器兼容性支持的,它会额外生成一套代码,因为该插件也会有自己的入口文件,如果开启了该插件的支持,会发现在assets/images
中也会生成一个legacy
后缀的.js
文件,这是由于该插件的入口文件并未走entryFileNames
;目前除了关闭该功能外,尚未找到能修改其生成路径的办法。另外该插件虽然可以做低版本浏览的兼容性支持,但需要对应的前端框架语言能支持对应浏览器的低版本才能生效,vue3
因已经放弃了对ie11
的支持,所以在vue3
项目中想通过该插件实现对ie11
的支持是办不到的。
相关配置:
plugins:[
...
// 是否为打包后的文件提供传统浏览器兼容性支持(vue3本身不支持ie11,所以vite虽然能为支持ie11的语言做兼容性支持,但不能为vue3做兼容性支持)
VITE_LEGACY
? legacy({
targets: ['defaults', 'not IE 11'], // 这里可以设置多个浏览器内核版本,使用vue3的情况下,设置ie11的兼容性也不会起作用。
// targets: ['ie >= 11','chrome >= 52'], // 这里可以设置多个浏览器内核版本,使用vue3的情况下,设置ie11的兼容性也不会起作用。
// additionalLegacyPolyfills: ["regenerator-runtime/runtime"] // 面向ie11时需要此插件
})
: null,
...
]
以上是打包过程中的一些操作修改。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。