在大型项目中,我们往往会遇到需要将一个项目拆分为多个子项目的情况,如PC端、移动端等。为了实现代码复用和高效的依赖管理,本文将介绍如何利用Vite搭建一个多项目工程结构,它具备以下特性:
- 公共代码提取:各个子项目的共有模块可以抽离至公用文件夹,便于统一管理和维护,例如接口定义和通用业务逻辑。
- 共享依赖库:所有子项目使用同一份
node_modules
依赖。 - 独立配置与启动:每个子项目拥有各自的
vite.config.ts
配置文件,并能单独启动开发服务和进行打包部署。
注意:虽然本方案适用于多个子项目,但它并非严格意义上的Vite多页面应用架构。
项目的文件结构如下图所示:
实现原理
-
src 文件夹中的 project 文件夹是存放子项目的,上面的 proA 和 proB 就是两个子项目,每个子项目有自己的 main.ts(启动入口)、vite.config.ts(vite配置);
-
vite配置文件通过
vite-plugin-html
插件指定启动入口文件和页面入口文件; -
在 package.json 文件中给 vite 服务启动命令加上
-c
来选用指定的 Vite 配置文件来启动服务。"scripts": { "dev:proA": "vite -c src/project/proA/vite.config.ts", "dev:proB": "vite -c src/project/proB/vite.config.ts", "build:proA": "vue-tsc && vite build -c src/project/proA/vite.config.ts", "build:proB": "vue-tsc && vite build -c src/project/proB/vite.config.ts" }
工程构建步骤
-
初始化项目
通过熟悉的脚手架(如
npm create vite
)创建工程,安装全局共享的依赖包; -
调整文件结构
调整目录结构以适应多项目需求。具体做法是,在
src
目录下创建project
文件夹存放各个子项目,如proA
和proB
,并为每个子项目提供独立的main.ts
入口文件、vite.config.ts
配置文件,具体参照上述的文件结构; -
配置
vite.config.ts
文件在每个子项目的
vite.config.ts
文件中,借助vite-plugin-html
插件来指定项目启动入口。此外,设置环境变量目录、路径别名、输出目录等关键配置项。以下是proA
项目的 Vite 配置示例:import { fileURLToPath, URL } from 'node:url'; import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { createHtmlPlugin } from 'vite-plugin-html'; // https://vitejs.dev/config/ export default defineConfig(() => { return { envDir: '/.env', //指定环境配置文件的目录,路径以工程的根路径为起点 plugins: [ vue(), createHtmlPlugin({ /* 这里的路径以工程的根路径为起点 */ entry: '/src/project/proA/main.ts' //指定启动入口 }), ], resolve: { alias: { /* 配置路径别名 */ '@proA': fileURLToPath(new URL('./', import.meta.url)), //指代 proA 目录 '@': `${process.cwd()}/src` //指代工程的 src 目录 } }, build: { outDir: 'src/project/proA/dist', //打包文件的路径 rollupOptions: { /* 修改打包后生成的资源文件的路径,如果没有这个配置,所有的js、图片等资源都在assets目录下 */ output: { chunkFileNames: 'static/js/[name]-[hash].js', //每条引用链的文件路径 entryFileNames: 'static/js/[name]-[hash].js', //入口文件的路径 assetFileNames: 'static/[ext]/name-[hash].[ext]' //资源文件的路径,ext是文件后缀名 } } } }; });
-
配置
package.json
文件在
package.json
的scripts
部分添加针对每个子项目的启动和打包命令,通过-c
参数指定不同子项目的vite.config.ts
文件。-c <file> ---- 修改启动服务时使用的 Vite 配置文件的路径
{ "scripts": { "dev:proA": "vite -c src/project/proA/vite.config.ts", "dev:proB": "vite -c src/project/proB/vite.config.ts", "build:proA": "vue-tsc && vite build -c src/project/proA/vite.config.ts", "build:proB": "vue-tsc && vite build -c src/project/proB/vite.config.ts" } }
主要的构建代码就是以上这些,但是还会有一些 Vite 插件的配置需要注意下
Vite插件配置
-
unplugin-auto-import
生成的
.d.ts
文件可以放在子项目中,这样每个子项目都会有自己的声明文件。如果放在根目录下,所有子项目如果同时开发的话,相同名称的声明会被覆盖,对于本地的自动引入的会有影响,比如生成的文件中这段声明
const request: typeof import(‘@proA/API’)[‘default’]
同时启动多个子项目,只会有一个声明文件,所以只会取其中一个子项目的路径的声明,但是放到子项目中,多个文件中定义的同名声明,使用时,typescript 会对这多个定义进行合并。
{ plugins: [ AutoImport({ imports: [ 'vue', { '@proA/API': [['default', 'request']] } ], eslintrc: { enabled: false, // Default `false`,需要更新文件的时候把他打开,更新完之后再关闭,否则每次都要生成文件会有问题 filepath: 'src/project/proA/.eslintrc-auto-import.json', globalsPropValue: true // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable') }, dts: 'src/project/proA/auto-imports.d.ts' //生成文件的路径 }) ] }
-
unplugin-vue-components
生成文件路径也放在子项目中,理由同上
{ plugins: [ Components({ dts: 'src/project/proA/components.d.ts', //生成文件的路径 dirs: ['src/project/proA/views'], //需要被自动引入的组件的目录 directoryAsNamespace: true //允许子目录作为组件的命名空间前缀。 }) ] }
对于像unplugin-auto-import
和unplugin-vue-components
这类需要生成声明文件的插件,建议将生成的.d.ts
文件放在对应子项目中,避免多个子项目同时开发时声明文件冲突或覆盖的问题。
遇到的问题及解决方案
-
index.html
文件的存放位置最初尝试将
index.html
文件放在子项目中,通过createHtmlPlugin
中的template
配置指定页面入口文件路径,但生成的代码中index.html
不在根目录下,而是在dist/src/project/paroA/index.html
,同template
配置的路径,部署的时候还需要将index.html
提取到根目录下才行。解决办法:把
index.html
文件放到根目录下,因为在根目录,createHtmlPlugin
中的template
也可以不用配置了。如果有在index.html
中添加 script 标签,或者添加自定义 script 代码等需求的话,可以直接在子项目的 Vite 配置文件中,通过createHtmlPlugin
插件进行注入。 -
打包后
index.html
文件缺失把
index.html
文件放在根目录下之后,设置了build.rollupOptions.input
这个打包配置项之后,打包后的代码没有index.html
文件了,原因未知。解决办法:去掉
build.rollupOptions.input
这个配置项。
这样,通过以上配置和调整,您可以更轻松地搭建 Vite 多项目单页面开发环境,并解决一些可能遇到的问题。
源码:https://gitee.com/relex6/multi-pro.git