vue3多个项目共享开发和单个项目独立打包的解决方案
Posted 左直拳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3多个项目共享开发和单个项目独立打包的解决方案相关的知识,希望对你有一定的参考价值。
由于实际项目的特点产生了多系统共享开发和独立打包的需求,主要原理在于应用vue的多页面支持和npm的打包定制。本方案中,vue项目由一个主程序和若干个子系统构成。主程序代码放置于外层,提供共享组件和功能;而子系统各自独立,仅包含私有代码。运行时,可整个项目集成运行,也可以单个子系统运行;打包类似,可整体打包,也可单个子系统独立打包。
一、项目简介
近期参与的一个项目,业主是同一个单位,辖下多个部门,每个部门对应一个子系统,因此该项目由多个相对独立的子系统组成。公司组建了项目团队,分为若干个小组,负责开发不同的子系统。技术方案定为前后端分离,后端采取微服务框架,前端采用VUE进行构建。
前端这里,虽然各个子系统各自独立,但必须风格统一,且为了效率和成本,总有一些资源可以复用,比如一些组件。而实际部署时,既可以整体部署,也应该可以每个子系统独立部署,独立配置,以降低风险和耦合,提升性能和资源利用率,等等。
这种情况有2种方案。一种是公共资源与各子系统并行,独立开发,并发布为node module的形式,供各子系统调用;另一种方案是前端代码是一个大的工程,公共资源和所有子系统包含于其中。
目前采取第2种方式。由于所有子系统的代码位于同一个工程(项目),共享公用的组件和资源相对容易,但编译、运行、打包,要有所区分才好。否则编译耗时,更新部署也不合理:一个子系统修改,其他子系统也被迫发布和更新,可能会带来意想不到的问题。就算是每个子系统独立部署,但部署的其实都是完整的项目,可能又有同步的问题。
解决这个问题,可以应用vue的多页面支持和webpack的打包定制。介绍如下。
二、项目整体结构
总的来说,是公共部分放在外围,而各个子系统集中于一个子文件夹下。在结构上,每个子系统都几乎是一个完整的项目,特别是都提供入口(即main.js)。
由上图可知,子系统代码在src/apps/下集中存放;每个子系统都有 main.js、router.js、index.html等文件。而公共资源部分,又可称为框架、容器或主程序,代码存放在外层,即项目根目录下和src/根目录下。其中projects.js是我新加的,内容为多入口配置。它仅仅是数据,供vue.config.js调用。vue.config.js在vue3里,默认是没有的,也要手动添加。与vue2相比,可能vue3觉得约定重于配置,各种webpack的繁琐配置就不用设置了,于是默认不提供。但如果文件存在的话,它就会去读取,并以这里的内容为准。
图里还漏了突出package.json,里面有书写分情况运行、打包的脚本。
三、代码介绍
1、生成项目
vue的版本为vue3。网上有相关问题的文章,可惜很多都是vue2,写于2018或2019年,有点旧了,上来就说了一大堆webpack的配置文件,还有build文件夹,帮不上什么忙。当然了,我这篇文章过2年也很有可能不合时宜。或者现在说的就根本不对亦未可知。
生成项目方法如下,在命令行方式下运行
vue create 项目名称
这时系统会询问创建方式,选手动
Vue CLI v4.5.13
? Please pick a preset:
Default ([Vue 2] babel, eslint)
Default (Vue 3) ([Vue 3] babel, eslint)
❯ Manually select features
进入第二步,选中路由支持(注意系统的说明,使用空格键进行选中)
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project:
◉ Choose Vue version
◉ Babel
◯ TypeScript
◯ Progressive Web App (PWA) Support
❯◉ Router
◯ Vuex
◯ CSS Pre-processors
◉ Linter / Formatter
◯ Unit Testing
◯ E2E Testing
第三步,选vue3
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with
2.x
❯ 3.x
后面的按回车默认进行即可,有2个询问,我选了no,不过应该无关大雅。完成后生成一个干净而就绪的项目。
2、添加和修改文件
1)创建文件夹 /src/apps,用于集中存放子系统代码
2)依次创建 /src/apps/projectA、B、C、D,每个子系统都摆放这样一些文件:
这些文件可以直接从根目录中复制过来,内容无关紧要,只为一个示意。其中index.html与projectA.html文件是一样的。index.html用于仅运行和打包projectA,而projectA.html则用于多个项目集成运行和打包,看到下面的入口脚本设置就会明白为何会这样。router.js可以完全不需要修改,原原本本复制自根目录即可。
3)/projects.js
添加/projects.js,内容如下:
let path = require('path')
let glob = require('glob')
//配置pages多页面获取当前文件夹下的html和js
function getEntry(globPath) {
let entries = {},
basename, tmp, pathname;
glob.sync(globPath).forEach(function(entry) {
basename = path.basename(entry, path.extname(entry));
tmp = entry.split('/').splice(-3);
pathname = basename; // 正确输出js和html的路径
entries[pathname] = {
entry: 'src/' + tmp[0] + '/' + tmp[1] + '/main.js',
template: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[2],
title: tmp[2],
filename: tmp[2] //如projectA.html
};
});
return entries;
}
let pages = getEntry('./src/apps/**?/*.html');
pages['index'] = {
// page 的入口
entry: 'src/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: '公共首页',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
// chunks: ['chunk-vendors', 'chunk-common', 'index']
};
const config = {
all: {
pages: pages
},
projectA: {
pages: {
index: {
entry: "src/apps/projectA/main.js",
template: "src/apps/projectA/index.html",
filename: "index.html"
}
},
outputDir: "dist/projectA/"
},
projectB: {},//偷懒不写了
projectC: {},
projectD: {}
};
module.exports = config;
从上面的脚本可知,为什么子系统里需要提供一个index.html和一个projectA.html这样的文件。
4)/vue.config.js
主要是读取/projects.js的数据
const config = require("./projects.js");
/*
npm run serve 就是all,否则是后接子系统名称
*/
let projectName = (!process.env.PROJECT_NAME || process.env.PROJECT_NAME.length === 0)
? 'all' : process.env.PROJECT_NAME;
module.exports = {
...config[projectName],
}
5)/package.json
节选手动加入的代码:
{
"name": "v",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"serve:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service serve --open",
"build:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service build",
"lint": "vue-cli-service lint"
},
。。。
需要安装 cross-env。全局安装吧,以后用得上。
npm install -g cross-env
sudo ln -s /home/chenqu/apps/node-v14.17.0-linux-x64/bin/cross-env /usr/local/bin/cross-env
安装好后再加上链接。
到此系统架构其实已经完成。但为了演示效果更明显,突出单独打包和资源共享的思想,我加了一个导航条组件:
6)/src/components/Navi.vue
<template>
<div id="nav">
<!-- 注意指向子系统的是 <a> 链接,而不是vue的 router-link!!! -->
<a href="/" :class="{active:!moduleName || moduleName === 'HOME'}">公共首页</a> |
<a href="/projectA" :class="{active:moduleName === 'A'}">projectA</a> |
<a href="/projectB" :class="{active:moduleName === 'B'}">projectB</a> |
<a href="/projectC" :class="{active:moduleName === 'C'}">projectC</a> |
<a href="/projectD" :class="{active:moduleName === 'D'}">projectD</a> |
</div>
</template>
<script>
export default {
props:{
moduleName: String
},
data(){
return {
}
},
mounted() {
},
}
</script>
<style lang="less">
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
a.active {color:#00f;text-decoration:none;}
a:hover {color:red;text-decoration:underline;}
}
</style>
注意指向子系统的是 a 链接,而不是vue的 router-link!!!
注意指向子系统的是 a 链接,而不是vue的 router-link!!!
注意指向子系统的是 a 链接,而不是vue的 router-link!!!
然后在主程序和各子系统的首页(Home.vue)里调用:
主程序/src/views/Home.vue
<template>
<div>
<Navi />
<div>
<router-link to="/">home</router-link> |
<router-link to="/about">about</router-link> |
</div>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
import Navi from '@/components/Navi.vue'
export default {
name: 'Home',
components: {
HelloWorld,
Navi
}
}
</script>
子系统首页/src/apps/projectA/views/Home.vue
<template>
<div class="home">
<Navi moduleName="A" />
<div>
<router-link to="/">home</router-link> |
<router-link to="/about">about</router-link> |
</div>
<div><h1>项目A首页</h1></div>
</div>
</template>
<script>
import Navi from '@/components/Navi.vue'
export default {
name: 'Home',
components: {
Navi
}
}
</script>
四、运行与打包
1、集成运行
npm run serve
2、子系统单独运行
npm run serve:projectA
打包与运行类似。
参考文章
vue cli3超详细创建多页面配置
以上是关于vue3多个项目共享开发和单个项目独立打包的解决方案的主要内容,如果未能解决你的问题,请参考以下文章
tauri+vite+vue3开发环境下创建启动运行和打包发布