/**
* Vue 应用初始化模块
*
* 这个模块负责创建和配置 Vue 应用实例,包括:
* - 创建应用实例和根组件
* - 注册全局插件(路由、状态管理、国际化、UI库)
* - 提供默认的依赖注入值
* - 支持外部配置和依赖注入覆盖
* - 挂载应用到 DOM
*
* @example 基本使用
* ```typescript
* import { initApp } from './core/initApp';
*
* // 使用默认配置初始化应用
* initApp();
* ```
*
* @example 使用自定义配置
* ```typescript
* import { initApp } from './core/initApp';
* import CustomLayout from './CustomLayout.vue';
* import { LayoutKey } from './core/composables/useProvideInject';
*
* initApp((app, { provide, hasProvided }) => {
* // 检查是否已经提供了布局
* if (!hasProvided(LayoutKey)) {
* provide(app, LayoutKey, CustomLayout);
* }
*
* // 或者强制覆盖默认布局
* provide(app, LayoutKey, CustomLayout, { override: true });
* });
* ```
*/
import { type App as App2 } from 'vue';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import App from './App.vue';
import router from './router';
import i18n from './i18n';
import './global.css';
import MainLayout from './layouts/MainLayout/index.vue';
import { appProvide, hasProvided, LayoutKey, getProvidedKeys } from './composables/useProvideInject';
/**
* 应用配置选项接口
*
* 定义了可以通过配置函数传递的选项类型。
* 这个接口可以扩展以支持更多的配置选项。
*/
export interface AppConfigOptions {
/** 自定义布局组件 */
Layout?: unknown;
/** 自定义主题配置 */
Theme?: unknown;
/** 其他自定义配置项 */
[key: string]: unknown;
}
/**
* 高级配置函数类型
*
* 这个函数类型定义了在应用初始化过程中可以执行的配置操作。
* 配置函数会在插件安装完成后、应用挂载前执行。
*
* @param app - Vue 应用实例
* @param utils - 提供的工具函数集合
* @param utils.provide - 安全的依赖注入提供函数
* @param utils.hasProvided - 检查某个键是否已经被提供的函数
* @param utils.getProvidedKeys - 获取所有已提供键的函数
*/
export type ConfigureFunction = (app: App2<Element>, utils: {
provide: typeof appProvide;
hasProvided: typeof hasProvided;
getProvidedKeys: typeof getProvidedKeys;
}) => void;
/**
* 初始化 Vue 应用
*
* 这个函数创建并配置一个完整的 Vue 应用实例。它按照以下顺序执行:
* 1. 创建 Vue 应用实例
* 2. 安装核心插件(路由、状态管理、国际化、UI库)
* 3. 执行外部配置函数(允许外部覆盖内部配置)
* 4. 提供默认的依赖注入值(如果外部没有提供的话)
* 5. 挂载应用到 DOM
* 6. 暴露全局调试接口
*
* @param configure - 可选的配置函数,在插件安装后、应用挂载前执行
*
* @example 基本初始化
* ```typescript
* // 使用默认配置初始化应用
* initApp();
* ```
*
* @example 自定义布局
* ```typescript
* import CustomLayout from './layouts/CustomLayout.vue';
*
* initApp((app, { provide, hasProvided }) => {
* // 提供自定义布局,优先于默认布局
* provide(app, LayoutKey, CustomLayout, { override: true });
* });
* ```
*
* @example 条件性配置
* ```typescript
* initApp((app, { provide, hasProvided, getProvidedKeys }) => {
* // 检查是否已经提供了布局
* if (!hasProvided(LayoutKey)) {
* provide(app, LayoutKey, MyCustomLayout);
* }
*
* // 调试:打印所有已提供的键
* console.log('已提供的依赖:', getProvidedKeys());
* });
* ```
*
* @example 提供多个依赖
* ```typescript
* initApp((app, { provide }) => {
* // 提供自定义主题
* provide(app, ThemeKey, {
* primaryColor: '#007fff',
* backgroundColor: '#f5f5f5'
* });
*
* // 提供应用配置
* provide(app, ConfigKey, {
* apiUrl: 'https://api.example.com',
* version: '1.0.0'
* });
* });
* ```
*/
export const initApp = async (configure?: ConfigureFunction) => {
const pinia = createPinia();
const app = createApp(App);
// 安装核心插件
app.use(router);
app.use(pinia);
app.use(i18n); // 添加 i18n 插件
app.use(ElementPlus);
// 执行外部配置函数,允许外部覆盖内部配置
// 这里外部可以提供自定义的依赖注入值,优先于默认值
await configure?.(app, {
provide: appProvide,
hasProvided,
getProvidedKeys
});
// 提供默认的依赖注入值
// 只有在外部没有提供的情况下才提供默认值
if (!hasProvided(LayoutKey)) {
appProvide(app, LayoutKey, MainLayout, { track: true });
}
app.mount('#app');
// 全局暴露路由和状态管理实例,方便调试和外部访问
// 在生产环境中可以考虑移除这些全局暴露
window.router = router;
window.store = pinia;
};
|