Vue 3 + Vite + Router + Pinia + Element Plus + Monorepo + qiankun 构建企业级中后台前端框架

news/2025/11/28 16:14:34/文章来源:https://www.cnblogs.com/ypSharing/p/19283156

 

---

# **Vue 3 + Vite + Monorepo + Qiankun 微前端搭建指南**

## **目录**
1. [环境准备](#1-环境准备)
2. [初始化 Monorepo 项目](#2-初始化-monorepo-项目)
3. [安装公共依赖](#3-安装公共依赖)
4. [配置代码规范和 TypeScript](#4-配置代码规范和-typescript)
5. [创建共享库](#5-创建共享库)
- [5.1 公共工具库 (`packages/utils`)](#51-公共工具库-packagesutils)
- [5.2 公共 Hooks 库 (`packages/hooks`)](#52-公共-hooks-库-packageshooks)
- [5.3 公共 UI 组件库 (`packages/components`)](#53-公共-ui-组件库-packagescomponents)
- [5.4 公共请求封装 (`packages/request`)](#54-公共请求封装-packagesrequest)
6. [创建主应用 (`apps/main`)](#6-创建主应用-appsmain)
7. [创建微应用 (`apps/app1`)](#7-创建微应用-appsapp1)
8. [配置主应用和微应用的路由](#8-配置主应用和微应用的路由)
9. [测试和运行](#9-测试和运行)
10. [构建和部署](#10-构建和部署)

---
### 一、技术选型考量
1. 核心技术栈确定
- Vue 3:作为核心框架,其组合式 API、更好的 TypeScript 支持以及优异的性能,为中后台项目的复杂逻辑处理和组件复用提供了强大基础。
- Vite:替代传统的 Webpack 构建工具,以其极速的冷启动、按需编译和热更新能力,显著提升开发效率,尤其适合大型项目的开发流程。
- Vue Router 4:与 Vue 3 深度适配,提供了更灵活的路由配置方式,支持动态路由、嵌套路由等功能,满足中后台系统复杂的页面跳转需求。
- Pinia:作为 Vuex 的替代方案,Pinia 具有更简洁的 API 设计、更好的 TypeScript 兼容性,同时支持多 Store 架构,便于状态的模块化管理。
- Element Plus:基于 Vue 3 的 UI 组件库,提供了丰富的中后台常用组件,如表格、表单、弹窗等,能够快速搭建美观、易用的界面。
- Monorepo:采用单一代码仓库管理多个相关项目,实现代码共享、依赖统一管理,简化团队协作流程,尤其适合多项目、多模块的中后台系统。
- qiankun:微前端框架,能够将多个独立的前端应用整合为一个整体,实现应用间的无缝切换、通信和资源共享,满足中后台系统的业务拆分和整合需求。
2. 技术栈优势互补
这些技术的组合形成了强大的优势互补。Vue 3 和 Vite 保证了项目的性能和开发体验;Router 和 Pinia 实现了页面路由和状态的高效管理;Element Plus 加速了 UI 开发;Monorepo 优化了项目的组织和协作方式;qiankun 则为系统的微前端架构提供了支持,使得各业务模块可以独立开发、部署和维护,同时又能有机地结合在一起。
### 整体架构概览

我们将创建以下目录结构:

```
vue3-monorepo-qiankun/
├── apps/ # 应用目录
│ ├── main/ # 主应用 (qiankun 容器)
│ └── app1/ # 微应用 1
├── packages/ # 共享库目录
│ ├── components/ # 共享组件库
│ ├── hooks/ # 共享 Hooks 库
│ └── utils/ # 共享工具库
├── package.json # 根项目配置
├── pnpm-workspace.yaml # pnpm 工作区配置
└── tsconfig.json # 全局 TypeScript 配置
```

---
## **第一步:环境准备**
确保你已经安装了 `pnpm` 和 `node` (推荐 v16+)。

```bash
npm install -g pnpm
```

---

## **第二步:初始化 Monorepo 项目**
1. **创建并进入项目根目录**
```bash
mkdir -p vue3-monorepo-qiankun && cd vue3-monorepo-qiankun
```

2. **初始化 `package.json`**
```bash
pnpm init -y
```

3. **创建 `pnpm-workspace.yaml` 文件**
```bash
cat > pnpm-workspace.yaml << EOF
packages:
- 'apps/*'
- 'packages/*'
EOF
```

4. **创建 `.npmrc` 文件 (推荐)**
这个文件用于配置 pnpm 的行为,让它更像传统的 `node_modules` 结构,方便某些工具识别。

```bash
cat > .npmrc << EOF
shamefully-hoist=true
EOF
```

---

## **第三步:安装公共依赖**

这是本方案的核心。我们将所有共享的运行时依赖和开发依赖都安装在根目录。

1. **安装公共运行时依赖**
这些是主应用和微应用都需要用到的库,如 `vue`, `element-plus` 等。

```bash
pnpm add -w vue vue-router pinia element-plus @element-plus/icons-vue axios qiankun
```
> **说明**: `-w` 或 `--workspace-root` 是关键,它告诉 pnpm 把依赖安装到工作区的根目录,而不是当前目录(虽然这里我们就在根目录)。

2. **安装公共开发依赖**
这些是构建、 lint、测试等工具,如 `vite`, `typescript`, `eslint` 等。

```bash
pnpm add -Dw @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite typescript vue-tsc @types/node eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue vue-eslint-parser @typescript-eslint/eslint-plugin @typescript-eslint/parser vite-plugin-qiankun
```

执行完毕后,你会发现根目录的 `package.json` 中已经包含了所有这些依赖,并且根目录下出现了一个 `node_modules` 文件夹。

---

## **第四步: 配置代码规范和 TypeScript**
1. **创建 `tsconfig.json`**
这个文件为整个工作区提供基础的 TypeScript 配置,子项目可以继承它。
```bash
cat > tsconfig.json << EOF
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["**/*.ts", "**/*.tsx", "**/*.vue"],
"exclude": ["node_modules", "**/dist"]
}
EOF
```

2. **创建 ESLint 和 Prettier 配置**
在根目录创建这些配置文件,可以让所有子项目共享同一套代码规范。
```bash
# 创建 .eslintrc.js
cat > .eslintrc.js << EOF
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
plugins: ['vue', '@typescript-eslint', 'prettier'],
rules: {
'prettier/prettier': 'error',
'vue/no-unused-vars': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
};
EOF

# 创建 .prettierrc
cat > .prettierrc << EOF
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "auto",
"vueIndentScriptAndStyle": false
}
EOF

# 创建 .eslintignore 和 .prettierignore
cat > .eslintignore << EOF
node_modules/
dist/
*.d.ts
EOF
cp .eslintignore .prettierignore
```

3. **更新根目录 `package.json` 的 `scripts`**
添加一些方便在根目录运行的脚本,比如全局 lint。
```json
{
"scripts": {
"dev": "pnpm -r dev",
"build": "pnpm -r build",
"lint": "eslint . --ext .vue,.js,.ts",
"format": "prettier --write .",
"clean": "pnpm -r --delete node_modules && rm -rf node_modules"
}
}
```

---

## **第五步:创建共享库 (packages)**
共享库将直接使用根目录的依赖,它们自己的 package.json 只需要声明依赖即可。
### **5.1 公共工具库 (`packages/utils`)**
1. **创建目录并初始化**
```bash
mkdir -p packages/utils/src && cd packages/utils
pnpm init -y
```

2. **修改 `package.json`**
关键是 dependencies 字段,我们声明需要 vue,但 pnpm 会自动从根目录查找。
```json
{
"name": "@your-org/utils",
"version": "1.0.0",
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"lint": "eslint . --ext .ts"
},
"dependencies": {
"vue": "^3.4.21"
}
}
```

3. **创建 `tsconfig.json`**
继承根目录的配置。
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts"]
}
```

4. **编写工具函数**
创建 src/format.ts 并在 src/index.ts 中导出
- `src/format.ts`
```typescript
export function formatDate(date: Date, fmt = 'YYYY-MM-DD HH:mm:ss') {
const o = {
'M+': date.getMonth() + 1,
'D+': date.getDate(),
'H+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds(),
'q+': Math.floor((date.getMonth() + 3) / 3),
S: date.getMilliseconds()
};
if (/(Y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
for (const k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k as keyof typeof o]) : (('00' + o[k as keyof typeof o]).substr(('' + o[k as keyof typeof o]).length)));
}
}
return fmt;
}
```
- `src/index.ts`
```typescript
export * from './format';
```

### **5.2 公共 Hooks 库 (`packages/hooks`)**
1. **创建目录并初始化**
```bash
cd ../../ && mkdir -p packages/hooks/src && cd packages/hooks
pnpm init -y
```

2. **修改 `package.json`**
```json
{
"name": "@your-org/hooks",
"version": "1.0.0",
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"lint": "eslint . --ext .ts,.vue"
},
"dependencies": {
"vue": "^3.4.21"
}
}
```

3. **创建 `tsconfig.json`**
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"]
}
```

4. **编写 Hooks**
- `src/useStorage.ts`
```typescript
import { ref, watch, type Ref } from 'vue';

export function useStorage<T>(key: string, defaultValue: T): Ref<T> {
const storedValue = localStorage.getItem(key);
const value = ref<T>(storedValue ? JSON.parse(storedValue) : defaultValue);

watch(value, (newVal) => {
localStorage.setItem(key, JSON.stringify(newVal));
}, { deep: true });

return value;
}
```
- `src/index.ts`
```typescript
export * from './useStorage';
```

### **5.3 公共 UI 组件库 (`packages/components`)**
1. **创建目录并初始化**
```bash
cd ../../ && mkdir -p packages/components/src && cd packages/components
pnpm init -y
```

2. **修改 `package.json`**
```json
{
"name": "@your-org/components",
"version": "1.0.0",
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"lint": "eslint . --ext .ts,.vue"
},
"dependencies": {
"vue": "^3.4.21",
"element-plus": "^2.7.2"
}
}
```

3. **创建 `tsconfig.json`**
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"]
}
```

4. **编写 UI 组件**
- `src/CommonButton/CommonButton.vue`
```vue
<template>
<el-button :type="type" :loading="loading" @click="onClick">
<slot></slot>
</el-button>
</template>

<script setup lang="ts">
import { defineProps, emit } from 'vue';

const props = defineProps<{
type?: 'primary' | 'success' | 'warning' | 'danger' | 'info';
loading?: boolean;
}>();

const emit = defineEmits<{
(e: 'click'): void;
}>();

const onClick = () => {
emit('click');
};
</script>
```
- `src/index.ts`
```typescript
export { default as CommonButton } from './CommonButton/CommonButton.vue';
```

### **5.4 公共请求封装 (`packages/request`)**
1. **创建目录并初始化**
```bash
cd ../../ && mkdir -p packages/request/src && cd packages/request
pnpm init -y
```

2. **修改 `package.json`**
```json
{
"name": "@your-org/request",
"version": "1.0.0",
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"lint": "eslint . --ext .ts"
},
"dependencies": {
"axios": "^1.6.8",
"vue": "^3.4.21"
}
}
```

3. **创建 `tsconfig.json`**
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts"]
}
```

4. **编写请求封装**
- `src/index.ts`
```typescript
import axios from 'axios';

const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 5000
});

// 请求拦截器
service.interceptors.request.use(
(config) => {
// 可以添加 token 等逻辑
return config;
},
(error) => {
return Promise.reject(error);
}
);

// 响应拦截器
service.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
return Promise.reject(error);
}
);

export default service;
```

---

## **第六步:创建主应用 (`apps/main`)**
主应用是一个标准的 Vite 应用,但它的依赖也将由根目录提供。

1. **创建目录并初始化**
我们使用 --template,但之后会修改依赖。
```bash
cd ../../ && mkdir -p apps/main && cd apps/main
pnpm create vite@latest . --template vue-ts
rm -rf node_modules pnpm-lock.yaml
```
执行后,根据提示操作,然后删除 apps/main 目录下的 node_modules 和 pnpm-lock.yaml 文件,因为我们将使用根目录的依赖。
2. **修改 `package.json`**
删除 `dependencies` 和 `devDependencies` 下的所有依赖,然后根据需要重新声明它们。pnpm 会自动从根目录链接。
```json
{
"name": "@your-org/main",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"lint": "eslint . --ext .vue,.js,.ts",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@your-org/components": "workspace:^*",
"@your-org/hooks": "workspace:^*",
"@your-org/utils": "workspace:^*",
"@your-org/request": "workspace:^*",
"element-plus": "^2.7.2",
"pinia": "^2.1.7",
"qiankun": "^2.10.16",
"vue": "^3.4.21",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"vite": "^5.2.11",
"vite-plugin-qiankun": "^1.0.11",
"vue-tsc": "^1.8.27"
}
}
```
> **注意**: `"@your-org/utils": "workspace:^*"` 是引用工作区内部包的标准方式。
3. **修改 `vite.config.ts`**
主应用作为 qiankun 容器,需要配置 vite-plugin-qiankun。
```typescript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import qiankun from 'vite-plugin-qiankun'
import path from 'path'

export default defineConfig({
plugins: [
vue(),
vueJsx(),
qiankun('main-app', { useDevMode: true })
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
preserveSymlinks: true,
modules: [
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, '../../node_modules')
]
},
server: {
port: 8080,
open: true,
cors: true
}
})
```

4. **修改 `tsconfig.json`**
继承根目录的配置
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true
"baseUrl": ".", // 基础路径
"paths": {
"@/*": ["src/*"] // 映射 @/ 到 src/
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
```

5. **编写主应用代码**
- `src/router/index.ts`
```typescript
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home/index.vue'
import MicroApp from '@/views/MicroApp/index.vue'

const routes = [
{ path: '/', component: Home },
{ path: '/app1', component: MicroApp }
]

const router = createRouter({
history: createWebHistory(),
routes
})

export default router
```
- `src/main.ts`
```typescript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { CommonButton } from '@your-org/components'

const app = createApp(App)

for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}

app.component('CommonButton', CommonButton)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)

app.mount('#app')

// 暴露全局变量给微应用
(window as any).Vue = app.config.globalProperties.constructor
(window as any).ElementPlus = ElementPlus
(window as any).Pinia = app.config.globalProperties.$pinia
(window as any).VueRouter = router
```
- `src/views/MicroApp/index.vue`
```vue
<template>
<div id="micro-app-container"></div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import { loadMicroApp, unmountMicroApp } from 'qiankun';

let microApp: any = null;

onMounted(() => {
microApp = loadMicroApp({
name: 'app1',
entry: '//localhost:8081',
container: '#micro-app-container',
props: { token: 'main-app-token' }
})
});

onUnmounted(() => {
unmountMicroApp('app1');
});
</script>
```

---

## **第七步:创建微应用 (`apps/app1`)**
微应用的配置与主应用类似,但有一个关键区别:**当它被 qiankun 加载时,需要通过 `externals` 排除已由主应用提供的依赖**。
1. **创建目录并初始化**
同样,删除自动生成的 `node_modules` 和 `pnpm-lock.yaml`。
```bash
cd ../../ && mkdir -p apps/app1 && cd apps/app1
pnpm create vite@latest . --template vue-ts
rm -rf node_modules pnpm-lock.yaml
```

2. **修改 `package.json`**
与主应用类似,声明依赖
```json
{
"name": "@your-org/app1",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"dev:qiankun": "vite --mode qiankun",
"build": "vue-tsc && vite build",
"build:qiankun": "vue-tsc && vite build --mode qiankun",
"lint": "eslint . --ext .vue,.js,.ts",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@your-org/components": "workspace:^*",
"@your-org/hooks": "workspace:^*",
"@your-org/utils": "workspace:^*",
"@your-org/request": "workspace:^*",
"element-plus": "^2.7.2",
"pinia": "^2.1.7",
"vue": "^3.4.21",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"vite": "^5.2.11",
"vite-plugin-qiankun": "^1.0.11",
"vue-tsc": "^1.8.27"
}
}
```

3. **修改 `vite.config.ts`**
这里是核心,我们需要根据运行模式来动态配置 `build.rollupOptions.externals`。
```typescript
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import qiankun from 'vite-plugin-qiankun'
import path from 'path'

export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd())
const isQiankunMode = env.VITE_QIANKUN === 'true'

return {
plugins: [
vue(),
vueJsx(),
qiankun('app1', { useDevMode: !isQiankunMode })
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
preserveSymlinks: true,
modules: [
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, '../../node_modules')
]
},
server: {
port: 8081,
open: true,
cors: true
},
base: isQiankunMode ? '/app1/' : '/',
build: {
rollupOptions: {
external: isQiankunMode ? [
'vue', 'vue-router', 'pinia', 'element-plus', 'axios',
'@element-plus/icons-vue', '@your-org/utils', '@your-org/hooks', '@your-org/components', '@your-org/request'
] : [],
output: {
globals: isQiankunMode ? {
vue: 'Vue',
'vue-router': 'VueRouter',
pinia: 'Pinia',
'element-plus': 'ElementPlus',
axios: 'axios',
'@element-plus/icons-vue': 'ElementPlusIconsVue',
'@your-org/utils': 'YourOrgUtils',
'@your-org/hooks': 'YourOrgHooks',
'@your-org/components': 'YourOrgComponents',
'@your-org/request': 'YourOrgRequest'
} : {}
}
}
}
}
})
```

4. **创建 `apps/app1/.env.qiankun`**
创建 `apps/app1/.env.qiankun` 文件,用于 qiankun 模式
```bash
cat > .env.qiankun << EOF
NODE_ENV=development
VITE_QIANKUN=true
EOF
```

5. **修改 `tsconfig.json`**
同样继承根目录配置
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true,
"baseUrl": ".", // 基础路径
"paths": {
"@/*": ["src/*"] // 映射 @/ 到 src/
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
```

6. **编写微应用代码**
微应用的入口文件 `src/main.ts` 需要遵循 qiankun 的协议,导出 `bootstrap`, `mount`, `unmount` 三个生命周期函数。
- `src/router/index.ts`
```typescript
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home/index.vue'
import List from '@/views/List/index.vue'

const routes = [
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/list', component: List }
]

const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})

export default router
```
- `src/main.ts`
```typescript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { CommonButton } from '@your-org/components'
import request from '@your-org/request'

let app: any = null

function render(props: any = {}) {
const { container } = props
app = createApp(App)

for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}

app.config.globalProperties.$request = request
app.component('CommonButton', CommonButton)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)

app.mount(container ? container.querySelector('#app') : '#app')
}

if (!(window as any).__POWERED_BY_QIANKUN__) {
render()
}

export async function bootstrap() {
console.log('微应用 app1 启动')
}

export async function mount(props: any) {
console.log('微应用 app1 挂载', props)
render(props)
}

export async function unmount() {
console.log('微应用 app1 卸载')
app.unmount()
app = null
}
```
> **重要**: 主应用需要在全局 (`window`) 上挂载微应用 `externals` 中声明的那些库,例如 `window.Vue = Vue`,这样微应用在运行时才能找到它们。这部分逻辑通常放在主应用的 `src/main.ts` 中。
---

## **第八步:配置主应用和微应用的路由**
- 主应用路由:负责加载微应用(如 `/app1` 路径)。
- 微应用路由:内部路由相对独立(如 `/home`、`/list`),会被 qiankun 自动拼接为 `/app1/home`、`/app1/list`。

---

## **第九步:测试和运行**
1. **安装所有依赖**
```bash
cd ../../..
pnpm install
```
2. **安装所有依赖**
这会根据所有 `package.json` 的声明,从根目录统一安装和链接。

```bash
pnpm install
```
3. **启动项目**
```bash
# 同时启动所有应用
pnpm dev

# 或者单独启动
pnpm --filter @your-org/main dev
pnpm --filter @your-org/app1 dev:qiankun
```

4. **访问地址**
- 主应用:http://localhost:8080
- 微应用独立运行:http://localhost:8081
- 主应用加载微应用:http://localhost:8080/app1

---

## **第十步. 构建和部署**
1. **构建项目**
```bash
pnpm build
```

2. **部署配置(Nginx 示例)**
```nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/vue3-monorepo-qiankun/apps/main/dist;

location / {
try_files $uri $uri/ /index.html;
}

location /app1 {
alias /path/to/vue3-monorepo-qiankun/apps/app1/dist;
try_files $uri $uri/ /app1/index.html;
}
}
```

---

## **总结**
通过以上步骤,你已经成功搭建了一个完整的 Vue 3 + Vite + Monorepo + Qiankun 微前端项目,包括公共工具库、Hooks 库、UI 组件库和请求封装。所有公共依赖都提取到了根目录进行统一管理,实现了代码复用和版本统一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/979829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

涂鸦智能:扫地机器人一体化解决方案

在智能家居的普及浪潮中,扫地机器人已从早期的“新奇玩具”升级为许多家庭的清洁刚需。对于希望进入或升级此产品的厂商而言,选择一个强大的技术方案商,是应对日益激烈的市场竞争的关键。???? 扫地机器人方案商…

GD32F407VE天空星开发板的MQ135的空气质量检测 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年销棒粉碎机厂商权威推荐榜单:钉盘磨/棒销磨/棒销式粉碎机源头厂家精选

在工业粉体加工与材料科学领域,销棒粉碎机作为实现超微超细粉碎的关键设备,其技术水平与工艺精度直接影响到成品粒度分布与生产效率。随着新材料、锂电池、精细化工等产业的快速发展,对高精度、高效率、无污染的粉碎…

2025年中国十大GEO全域搜索营销专业公司推荐:靠谱的GE

本榜单依托AI营销场景全维度调研与真实客户口碑反馈,深度筛选出十家在GEO全域搜索营销领域具备技术壁垒与实战成果的标杆企业,为企业解决获客难、成本高痛点提供客观选型依据,助力精准匹配适配的AI搜索优化服务伙伴…

2025年11月重庆保洁公司排名推荐:基于真实数据的客观评价

随着生活节奏加快和工作压力增大,越来越多的重庆家庭和企业开始将保洁服务纳入日常管理范畴。根据重庆市商务委2024年发布的居民服务消费数据显示,超过60%的城市家庭每月至少使用一次专业保洁服务,而企事业单位的保…

2025年度十大AI手机推荐,有高刷新率屏幕的AI手机、AI

在AI技术深度渗透智能终端的2025年,AI手机已从功能叠加转向场景重构,成为企业降本提效的数字化新载体。面对市场上品类繁杂的AI手机产品,如何精准匹配业务需求?以下结合有高刷新率屏幕的AI手机AI手机服务怎么联系A…

2025年11月电磁吸盘厂家推荐榜:五大厂家综合对比与权威评价

作为工业制造领域的关键设备,电磁吸盘广泛应用于机床加工、物流搬运、冶金等行业,其性能直接影响生产效率和安全性。许多用户在选购时面临厂家众多、参数复杂、服务质量参差不齐等问题。典型用户包括中小型机械加工企…

2025年WMS仓库管理系统选型指南(最新)

WMS仓库管理系统排名推荐:五大品牌对比分析国内WMS市场概况 随着数字经济与智能供应链的发展,仓库管理系统(WMS)已经成为企业降本增效、提升仓储管理效率的核心数字化基础设施。2024-2025年,中国WMS市场呈现高速增…

数组和张量

数组和张量Numpy和PyTorch的基础语法几乎一致,具体表现为:1 np对应torch2 数组array对应张量tensor3 Numpy的n维数组对应着PyTorch的n阶张量数组与张量之间可以相互转换:1 数组arr转为张量ts:ts = torch.tensor(arr…

2025年十大AI获客手机服务排行榜,新测评精选AI获客手机

为帮企业高效锁定适配自身需求的AI获客手机服务合作伙伴,避免选型走弯路,我们从技术落地能力(如功能完整性、系统稳定性)、场景适配广度(含行业针对性、多场景覆盖度)、服务质量(覆盖部署培训到后期运维)及真实…

涂鸦智能:宠物饮水机智能化的首选方案商!

智能宠物饮水机市场正以稳定的年增长率持续扩张,在这场技术革命中,一家物联网平台正凭借其雄厚的技术实力成为品牌商和制造商的秘密武器。 据统计,2024年全球智能宠物饮水机市场已达数十亿元人民币,并以稳定的年增…

2025年数字员工手机十大推荐:高性价比、抗摔能力与服务体验

在数字化劳动力快速渗透的2025年,数字员工手机作为实体员工+数字分身协同办公的核心终端,已成为企业降本提效的关键工具。面对市场上功能各异的产品,如何选择性价比高的、抗摔能力出色且服务响应及时的设备?以下结…

如何使用VBScript创建集合

在 VBScript 中,可以通过以下几种方式创建集合(Collection):1. 使用 Collection 对象(最常用) Collection 是 VBScript 内置的集合对象,可以存储任意类型的值,并支持按索引或键(Key)访问。 示例代码:创建…

布尔型数组

布尔型数组import numpy as nparr = np.arange(1,7).reshape(2,3)print(arr)print("数组与数字的比较" + "\n" + str(arr >= 4))arr1 = np.arange(2,8).reshape(2,3)print("同维数组的比较…

涂鸦智能:电壁炉智能化升级的核心“引擎”

预计到2027年,中国取暖电器行业市场规模将达到1274.5亿元,智能取暖正迎来高速发展期。 随着冬季取暖需求不断升级和“它经济”的持续升温,电壁炉已从单纯的取暖设备,逐渐转变为集家居装饰、智能控制、节能环保于一…

tabcontrol 动态添加用户页面

动态添加用户控件并选择最后一次添加的页面1 <TabControl ItemsSource="{Binding TabItems}" SelectedItem="{Binding SelectedTabItem}" >2 <!-- ItemTemplate定义选项卡头(He…

2025佛山桶装水配送公司TOP5权威推荐:佛山市水专家电子

桶装水作为家庭与企业日常饮水的核心选择,其配送服务的时效性、安全性、性价比直接影响用户体验。2024年佛山地区桶装水配送投诉数据显示,42%的纠纷集中在配送超时水质存疑服务不规范三大领域,用户常因临时缺水难补…

佛山口碑好的桶装水配送专业公司推荐:本地靠谱的桶装水配送品牌

本榜单依托佛山本地市场真实消费口碑、配送服务时效与水质安全检测数据,筛选出5家标杆桶装水配送企业,为家庭及企业用户提供客观选型参考,助力精准匹配品质+速度+信任兼备的服务伙伴。 TOP1 推荐:佛山市水专家电…

PostgreSQL里的JSONB到底怎么玩

最近PGSQL越来越火,不论是常用JSON的个人项目,还是某些需要国产数据库的项目(大多数是翻版的PGSQL)都和PGSQL脱不开关系。 先写一下json的一些规则:JSON的键名、字符串都只能是由" "包裹,不允许使用 ,…

视频融合平台EasyCVR通道快照获取与Base64转换问题排查实录

一、问题背景 近期,我们收到用户反馈,在调用EasyCVR平台接口获取通道实时快照后,将返回的数据放入在线转换工具中无法成功转换为图片。经过排查发现,返回的格式与常规转换工具要求的格式存在差异。以下是该问题的详…