vue项目架构-多子系统分包运行打包
Posted wangjie962311
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue项目架构-多子系统分包运行打包相关的知识,希望对你有一定的参考价值。
分析
要实现多子系统互相不干扰,并主系统能集成任意子系统,那么我们考虑就需要对每个子系统有一个独立的入口文件,同时主系统也有自己的入口文件。从而实现可拔插式结构。
实现方式
1、使用脚手架构建项目,在src下新建文件夹projects,用于存放主系统及各子系统文件,其中任何一个项目文件都相当于一个小vue,可以进行单独运行。具体如下:
2、任何小vue项目中包含入口文件main.js,以及项目需要的views页面,这里我们将路由进行拆分为index.js,和path.js,目的是便于我们主系统需要子系统路由而进行路由合并。
index.js——主要用于创建路由对象,以及合并需要的路由。
path.js——用于放置项目中需要的具体路由。
以主系统为例:
index.js 文件内容:
import Vue from "vue";
import VueRouter from "vue-router";
//引入主系统路由path.js
import mainRouter from "@/projects/mainSystem/router/path.js"//导入主系统路由文件
//引入其他子系统path.js
import projectARouter from "@/projects/projectA/router/path.js"//导入子系统路由文件
//引入其他子系统path.js
import khfwzhRouter from "@/projects/khfwzh/router/path.js"//导入子系统路由文件
Vue.use(VueRouter);
//合并路由(将需要的路由进行合并)
let routes = new Set([...mainRouter, ...projectARouter, ...khfwzhRouter ]);
const router = new VueRouter(
mode: 'hash',
base: process.env.BASE_URL,
routes
)
//解决路由导航冗余报错(路由重复)
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location)
return originalPush.call(this, location).catch(err => err)
export default router
path.js文件内容(主系统自身的路由):
/**
* 主系统路由地址
* @returns Promise<*>|*
*/
let firstPageIndex=()=>import(/* webpackChunkName: "mainSystem" */ "@/projects/mainSystem/views/index/index.vue")
let mainHome=()=>import(/* webpackChunkName: "mainSystem" */ "@/projects/mainSystem/views/Home")
let mainLayout=()=>import(/* webpackChunkName: "mainSystem" */ "@/components/base/publicLayout")
export default [
path: "/",
name: "home",
component: mainHome
,
path: '/aa',
name: 'aaa',
component: mainLayout,
children: [
path: "/aa",
name: "/aa",
component: firstPageIndex
]
]
3、在根目录下创建config文件夹及projectsConfig.js,用于存放各系统入口配置。
const config =
//主系统
mainSystem:
pages:
index:
entry: "src/projects/mainSystem/main.js",
template: "public/index.html",
filename: "index.html"
,
devServer:
port: 8081, // 端口地址
open: false, // 是否自动打开浏览器页面
host: "0.0.0.0", // 指定使用一个 host,默认是 localhost
https: false, // 使用https提供服务
disableHostCheck: true,
,
//子系统A
projectA:
pages:
index:
entry: "src/projects/projectA/main.js",
template: "public/index.html",
filename: "index.html"
,
devServer:
port: 8080, // 端口地址
open: false, // 是否自动打开浏览器页面
host: "0.0.0.0", // 指定使用一个 host,默认是 localhost
https: false, // 使用https提供服务
disableHostCheck: true,
,
;
module.exports = config;
4、将配置文件projectsConfig.js在vue.config.js引入,通过控制入口文件的路径和输出的路径实现,分模块打包。
const path = require('path')
const resolve = dir =>
return path.join(__dirname, dir)
const config = require("./config/projectsConfig.js");
let projectName = process.env.PROJECT_NAME;
module.exports =
publicPath: "/" + projectName,
outputDir: "dist/" + projectName + "/",
configureWebpack: config =>
config.resolve =
extensions: ['.js', '.vue', '.json'],
alias:
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
,
...config[projectName],
chainWebpack: config => // 是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。
config.resolve.alias.set('@', resolve('src'))
// config.entry('index').add('babel-polyfill')
,
productionSourceMap: false,
lintOnSave: false
;
5、安装cross-env,在我们执行打包命令的时候,通过cross-env找到我们的入口文件。
npm install --save-dev cross-env
6、修改package.json中脚本
"scripts":
"dev:mainSystem": "cross-env PROJECT_NAME=mainSystem vue-cli-service serve",
"dev:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service serve",
"build:mainSystem": "cross-env PROJECT_NAME=mainSystem vue-cli-service build",
"build:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service build",
...其他
,
7、现在可以使用命令分别进行运行 和 打包各系统
运行及打包主系统
npm run dev:mainSystem
npm run build:mainSystem
运行及打包子系统
npm run dev:projectA
npm run build:projectA
vite3+vue3 项目打包优化实战之-视图分析(rollup-plugin-visualizer)CDN引入依赖分包gzip压缩history404问题
文章目录
写在前面
vue项目在线下环境开发完成后,我们就需要项目的打包上线了,除了要知道打包命令npm run build
之外,我们还要知道项目整体文件依赖情况,web访问加载速度等概念,包括首屏优化方案。我通过一次实战把最基本可以优化的步骤走一下。
将分为以下几个步骤:
- build 视图分析依赖文件
- 第三方库CDN引入
- 依赖文件分包
- gzip压缩文件
- 部署前配置history路由模式的404问题
build 视图分析依赖文件
分析项目中的文件大小及引用情况,是优化前的重要一步,从而去采取文件分包,cdn引入等相关技术概念,那么在vite下我们可以利用什么工具来做项目的依赖分析呢?
答案是:
Rollup Plugin Visualizer
,这是一个依赖分析插件,它提供了多种模式的依赖分析,包括直观的视图分析,sunburst(循环层次图,像光谱)、treemap(矩形层次图,看起来比较直观,也是默认参数)、network(网格图,查看包含关系)、raw-data(原数据模式,json格式), list(列表模式),你可以选择任意一种你喜欢的观察模式,这里我们就以默认的为例;
安装方式如下:
npm install --save-dev rollup-plugin-visualizer
yarn add --dev rollup-plugin-visualizer
❗选择一种安装即可;
安装完成后,即可在vite下的插件属性中进行配置:
import visualizer from 'rollup-plugin-visualizer';
export default defineConfig(
plugins: [vue(), visualizer(
emitFile: false,
file: "stats.html", //分析图生成的文件名
open:true //如果存在本地服务端口,将在打包后自动展示
)],
)
配置的参数有很多是默认的,如果你没有特殊需求,完全可以不添加参数;下面我添加一个表格对已有参数进行诠释:
参数 | 类型 | 解释 |
---|---|---|
filename/file | string | 生成分析的文件名 |
title | string | html标签页标题 |
open | boolean | 以默认服务器代理打开文件 |
template | string | 可选择的图表类型 |
gzipSize | boolean | 搜集gzip压缩包的大小到图表 |
BrotliSize | boolearn | 搜集brotli压缩包的大小到图表 |
emitFile | boolean | 使用emitFile生成文件,简单说,这个属性为true,打包后的分析文件会出现在打包好的文件包下,否则就会在项目目录下 |
sourcemap | boolean | 使用sourcemap计算大小 |
projectRoot | string, RegExp | 文件的根目录,默认在打包好的目录下 |
看完这些参数,也有了大概的了解,根据需求配置就好
接下来,你只需要npm run build
;就可以查看这个图表了
是不是很好看,五颜六色的,这里颜色也是有说法的:
🟦蓝色表示自己写下的js文件项;
🟩绿色是表示依赖的文件项;
其他颜色我们可以根据文件名来判断
像上面这个文件,明显我们可以看出这是router相关的文件,当鼠标点击时我们可以看出这块依赖文件的大小,他的位置是是哪里;这里也看到它的大小马上到了100kb,是因为我们的主要业务也确实在这里;那我们就可以通过这样的信息采取一些优化方案,包括不限于修改代码的设计方式等,那么下面要说的CDN引入就是为了减少如element-plus及bootstrap5的打包文件大小,减少本地文件载入压力。下图很直观的可以看出element-plus的占据程度
第三方库CDN引入
🤔CDN 是构建在数据网络上的一种分布式的内容分发网。 CDN
的作用是采用流媒体服务器集群技术,克服单机系统输出带宽及并发能力不足的缺点,可极大提升系统支持的并发流数目,减少或避免单点失效带来的不良影响。
上面是百度百科的一段话,这里我要cdn引入是因为我们只有一个服务器,便称为单系统;那么引入他们各自官方的cdn链接就是在利用分布式内容分发技术,但是毕竟是人家的cdn安全上还需要考虑,如果自己公司有条件,就可以用自己公司的保证安全性;
话接上文,我们通过视图分析发现了element-plus
是最大的文件依赖,包括
bootstrap5
,那我们就尝试在vite+vue下配置这俩个库的cdn引入来减少请求压力;
cdn管理插件我们使用vite-plugin-cdn-import
安装方式
npm install vite-plugin-cdn-import --save-dev
yarn add vite-plugin-cdn-import -D
选择自己的包管理器下载
// vite.config.js 基本用法
import reactRefresh from '@vitejs/plugin-react-refresh'
import importToCDN from 'vite-plugin-cdn-import'
export default
plugins: [
importToCDN(
modules: [
name: 'react',
var: 'React',
path: `umd/react.production.min.js`,
,
name: 'react-dom',
var: 'ReactDOM',
path: `umd/react-dom.production.min.js`,
,
],
),
],
有一些model该插件还提供了自动完成,不要太爽,我们不需要配置参数了
export default
plugins: [
importToCDN(
modules: [
autoComplete('react'),
autoComplete('react-dom')
],
),
reactRefresh(),
],
写法如上,那么有那些是支持自动完成的呢,官方也写出了
自动完成支持的 module
“react” | “react-dom” | “react-router-dom” |
“antd” | “ahooks” | “@ant-design/charts” |
“vue” | “vue2” | “@vueuse/shared” |
“@vueuse/core” | “moment” |
“eventemitter3” | “file-saver” |
“browser-md5-file” | "xlsx | “crypto-js” |
“axios” | “lodash” | “localforage”
接下来我们再看完参数配置即可完成cdn的相关配置
这里的相关属性配置你们去官方看吧,很明确vite-plugin-cdn-import
然后还需要知道是常见cdn网站,我们主要介绍俩个国外的,也是常用的,
UNPKG:https://unpkg.com
jsDelivr :https://www.jsdelivr.com
这里还要学习怎么找到对应库cdn包的路径,我们好来配置参数,以UNPKG
为例实践如下:
比如我们要配置element-plus的cdn引入,
- 先进入https://unpkg.com
- 在地址后面链接你的包名
- 得到链接配置参数即可
下面我附图来展示:
package.json找到你的包信息
浏览器拼接你的包并且回车:
你会发现页面请求到了内容(这就说明该库在cdn上已经存在,我们把整个的链接拿下来配置好参数就可以了):
到这里你已经掌握了cdn库自动构建的基本知识,下面看一下我的配置片段:
import defineConfig from 'vite'
import vue from '@vitejs/plugin-vue'
import autoComplete, Plugin as importToCDN from 'vite-plugin-cdn-import';
export default defineConfig(
plugins: [vue(),
importToCDN(
prodUrl: 'https://unpkg.com/name@version/path',
modules: [
autoComplete('vue'),
autoComplete('axios'),
name: 'element-plus',
var: 'ElementPlus', //根据main.js中定义的来
version: '2.2.17',
path: 'dist/index.full.js',
css: 'dist/index.css'
,
name: 'vue-demi',
var: 'VueDemi', //根据main.js中定义的来
version: '0.13.11',
path: 'lib/index.iife.js'
,
name: '@element-plus/icons-vue',
var: 'ElementPlusIconsVue', //根据main.js中定义的来
version: '2.0.9',
path: 'dist/index.iife.min.js'
,
name: 'bootstrap',
var: 'bootStrap', //根据main.js中定义的来
version: '5.2.1',
path: 'dist/js/bootstrap.js',
css: 'dist/css/bootstrap.min.css'
,
],
)
],
)
上面的配置中有一个问题需要提及,我配置了
vue-demi
,它是pinia仓库的依赖,简单说,如果不配置它我们的cdn构建中间出现了个缺口,它是pinia-vue中间的一个依赖;vue和axios我配置了自动完成,那接下来看下我们进入实战。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./static/ico/favicon-a91524b8.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xxxxx</title>
<script type="module" crossorigin src="./static/js/index-3f77d0fe.js"></script>
<link rel="modulepreload" crossorigin href="./static/js/@vue-57a1150c.js">
<link rel="modulepreload" crossorigin href="./static/js/js-cookie-1db5286e.js">
<link rel="modulepreload" crossorigin href="./static/js/axios-08851a62.js">
<link rel="modulepreload" crossorigin href="./static/js/lodash-es-9a8f223b.js">
<link rel="modulepreload" crossorigin href="./static/js/@vueuse-d210d573.js">
<link rel="modulepreload" crossorigin href="./static/js/@element-plus-1fa478d9.js">
<link rel="modulepreload" crossorigin href="./static/js/@popperjs-892fd7f5.js">
<link rel="modulepreload" crossorigin href="./static/js/@ctrl-eb0b847c.js">
<link rel="modulepreload" crossorigin href="./static/js/dayjs-54e8cf14.js">
<link rel="modulepreload" crossorigin href="./static/js/async-validator-efc2d198.js">
<link rel="modulepreload" crossorigin href="./static/js/memoize-one-99e54574.js">
<link rel="modulepreload" crossorigin href="./static/js/escape-html-4bbaf1e1.js">
<link rel="modulepreload" crossorigin href="./static/js/normalize-wheel-es-da779ce4.js">
<link rel="modulepreload" crossorigin href="./static/js/@floating-ui-4b8fd220.js">
<link rel="modulepreload" crossorigin href="./static/js/element-plus-88e408ab.js">
<link rel="modulepreload" crossorigin href="./static/js/vue-router-5a9da933.js">
<link rel="modulepreload" crossorigin href="./static/js/vue-demi-5b9a0fa5.js">
<link rel="modulepreload" crossorigin href="./static/js/pinia-ef1d9feb.js">
<link rel="modulepreload" crossorigin href="./static/js/@fortawesome-7be7f9bf.js">
<link rel="stylesheet" href="./static/css/element-plus-c08499e6.css">
<link rel="stylesheet" href="./static/css/index-f2f66543.css">
<link rel="stylesheet" href="./static/css/bootstrap-744009a1.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
这样的入口文件,这么多的link是我提前用了分包的效果,下面我们会实战分包;回到上面,这么多的link引入对我们本地的压力可想而知;再来看分析图:
element-plus的依赖是如此庞大,那我们配置完后,build再来感受下;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./static/ico/favicon-a91524b8.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xxxxxxxxx</title>
<link href="https://unpkg.com/element-plus@2.2.17/dist/index.css" rel="stylesheet">
<link href="https://unpkg.com/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://unpkg.com/vue@3.2.36/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios@0.27.2/dist/axios.min.js"></script>
<script src="https://unpkg.com/element-plus@2.2.17/dist/index.full.js"></script>
<script src="https://unpkg.com/vue-demi@0.13.11/lib/index.iife.js"></script>
<script src="https://unpkg.com/@element-plus/icons-vue@2.0.9/dist/index.iife.min.js"></script>
<script src="https://unpkg.com/bootstrap@5.2.1/dist/js/bootstrap.js"></script>
<script type="module" crossorigin src="./static/js/index-8dbc54cb.js"></script>
<link rel="modulepreload" crossorigin href="./static/js/js-cookie-1db5286e.js">
<link rel="modulepreload" crossorigin href="./static/js/vue-router-5755d64e.js">
<link rel="modulepreload" crossorigin href="./static/js/pinia-7992cf6b.js">
<link rel="modulepreload" crossorigin href="./static/js/@fortawesome-0742f1fb.js">
<link rel="stylesheet" href="./static/css/index-f2f66543.css">
<link rel="stylesheet" href="./static/css/element-plus-c08499e6.css">
<link rel="stylesheet" href="./static/css/bootstrap-744009a1.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
cdn标签引入正确,我们也可以本地构建serve 来验证效果,这里就不扩展了,那么再看下分析图
element-plus等第三方库将不会成为我们的本地依赖,这里的tool是我自己的js工具模块,他看起来也是很大,那我们就可以找方法去优化调整,至此你学会了vite框架下的vue项目cdn引入方式;
还有一点题外话,cdn引入之前:
- 你需要知道一但依赖网站出现问题,我们的项目也就不行了,所以有依赖如上网站的cdn建议留下备用方案,以便维护。
- cdn是对整个库的引入,在你引入前,你要对一个库足够熟悉,比如我有一个
好朋友
他就在cdn引入中上出现了问题;
大致是这样:项目是vue3项目,我们知道在vue3中的reactive
响应式对象函数,
//它可以这样导入:
import reactive from "@vue/reactivity";
//也可以这样:
import onBeforeMount, ref, reactive from "vue";
那么如果你用@vue/reactivity
来导入,上线后发现reactive响应式没了,别问我怎么知道的,我朋友说的。我们cdn可没有引入该组件的相关依赖,只是在本地\\node_modules
下才有;
依赖文件分包
🤔在我们没有配置构建工具的分包功能时,构建出来的build将无比巨大且是独立的一个js and css 文件,这样就会存在本地加载文件的压力,已经成熟的方案在rollup 和 webpack中都有概念;
在vite的官方介绍中有这么一段
build.rollupOptions¶
类型: RollupOptions
自定义底层的 Rollup 打包配置。这与从 Rollup 配置文件导出的选项相同,并将与 Vite 的内部 Rollup 选项合并。查看 Rollup 选项文档 获取更多细节。
vite底层已经集成了rollup的一部分功能,也就是说我们直接配置好即可;详细关于rollup的配置可以去看官方文档rollupjs;这里我直接给出我的配置情况,也是借鉴部分大佬的文章得出;
export default defineConfig(
plugins: [vue(), viteCompression(
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
),
importToCDN(
prodUrl: 'https://unpkg.com/name@version/path',
modules: [
autoComplete('vue'),
autoComplete('axios'),
name: 'element-plus',
var: 'ElementPlus', //根据main.js中定义的来
version: '2.2.17',
path: 'dist/index.full.js',
css: 'dist/index.css'
,
以上是关于vue项目架构-多子系统分包运行打包的主要内容,如果未能解决你的问题,请参考以下文章