Browse Source

refactor(project): @vben/vite-connect is reconfigured to support synchronization

vben 11 months ago
parent
commit
e441d14fa2

+ 2 - 0
apps/backend-mock/package.json

@@ -26,6 +26,7 @@
     "cross-env": "^7.0.3",
     "joi": "^17.13.3",
     "js-yaml": "^4.1.0",
+    "mockjs": "^1.1.0",
     "passport": "^0.7.0",
     "passport-jwt": "^4.0.1",
     "passport-local": "^1.0.0",
@@ -36,6 +37,7 @@
     "@nestjs/cli": "^10.4.2",
     "@nestjs/schematics": "^10.1.2",
     "@types/express": "^4.17.21",
+    "@types/mockjs": "^1.0.10",
     "@types/node": "^20.14.10",
     "nodemon": "^3.1.4",
     "ts-node": "^10.9.2",

+ 2 - 0
apps/web-antd/.env

@@ -1,3 +1,5 @@
+VITE_PORT = 5555
+
 # spa-title
 VITE_GLOB_APP_TITLE = Vben Admin Pro
 

+ 2 - 2
apps/web-antd/package.json

@@ -1,12 +1,12 @@
 {
   "name": "@vben/web-antd",
   "version": "5.0.0",
-  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "homepage": "https://vben.pro",
   "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
   "repository": {
     "type": "git",
     "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
-    "directory": "apps/vben-admin"
+    "directory": "apps/web-antd"
   },
   "license": "MIT",
   "author": {

+ 25 - 51
apps/web-antd/vite.config.mts

@@ -1,59 +1,33 @@
-import { defineConfig, loadAndConvertEnv } from '@vben/vite-config';
+import {
+  defaultImportmapOptions,
+  defineConfig,
+  getDefaultPwaOptions,
+  loadAndConvertEnv,
+} from '@vben/vite-config';
 
-export default defineConfig({
-  application: async ({ mode }) => {
-    const envConfig = await loadAndConvertEnv();
-
-    return {
+export default defineConfig(async () => {
+  const { appTitle, port, ...envConfig } = await loadAndConvertEnv();
+  return {
+    application: {
       ...envConfig,
       importmap: false,
-      importmapOptions: {
-        // 通过 Importmap CDN 方式引入,
-        // 目前只有esm.sh源兼容性好一点,jspm.io对于 esm 入口要求高
-        defaultProvider: 'esm.sh',
-        importmap: [
-          { name: 'vue' },
-          { name: 'pinia' },
-          { name: 'vue-router' },
-          { name: 'vue-i18n' },
-          { name: 'dayjs' },
-          { name: 'vue-demi' },
-        ],
-      },
+      importmapOptions: defaultImportmapOptions,
       pwa: false,
-      pwaOptions: {
-        manifest: {
-          description:
-            'Vben Admin Pro is a modern admin dashboard template based on Vue 3. ',
-          icons: [
-            {
-              sizes: '192x192',
-              src: 'https://cdn.jsdelivr.net/npm/@vbenjs/static-source@0.1.3/source/pwa-icon-192.png',
-              type: 'image/png',
-            },
-            {
-              sizes: '512x512',
-              src: 'https://cdn.jsdelivr.net/npm/@vbenjs/static-source@0.1.3/source/pwa-icon-512.png',
-              type: 'image/png',
-            },
-          ],
-          name: `Vben Admin Pro ${mode}`,
-          short_name: `Vben Admin Pro ${mode}`,
-        },
-      },
-    };
-  },
-  vite: {
-    server: {
-      proxy: {
-        '/api': {
-          changeOrigin: true,
-          rewrite: (path) => path.replace(/^\/api/, ''),
-          // 代理目标地址 - backend-mock 项目
-          target: 'http://localhost:5320/api',
-          ws: true,
+      pwaOptions: getDefaultPwaOptions(appTitle),
+    },
+    vite: {
+      server: {
+        port,
+        proxy: {
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // 代理目标地址 - backend-mock 项目
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
         },
       },
     },
-  },
+  };
 });

+ 5 - 9
internal/vite-config/src/config/application.ts

@@ -7,10 +7,11 @@ import { defineConfig, loadEnv, mergeConfig } from 'vite';
 import { loadApplicationPlugins } from '../plugins';
 import { getCommonConfig } from './common';
 
-function defineApplicationConfig(options: DefineApplicationOptions = {}) {
+function defineApplicationConfig(userConfigPromise: DefineApplicationOptions) {
   return defineConfig(async (config) => {
+    const options = await userConfigPromise?.(config);
     const { command, mode } = config;
-    const { application = {}, vite = {} } = options;
+    const { application = {}, vite = {} } = options || {};
     const root = process.cwd();
     const isBuild = command === 'build';
     const env = loadEnv(mode, root);
@@ -30,9 +31,7 @@ function defineApplicationConfig(options: DefineApplicationOptions = {}) {
       mode,
       pwa: true,
       turboConsole: false,
-      ...(typeof application === 'function'
-        ? await application(config)
-        : application),
+      ...application,
     });
 
     const applicationConfig: UserConfig = {
@@ -69,10 +68,7 @@ function defineApplicationConfig(options: DefineApplicationOptions = {}) {
       await getCommonConfig(),
       applicationConfig,
     );
-    return mergeConfig(
-      mergedConfig,
-      typeof vite === 'function' ? await vite(config) : vite,
-    );
+    return mergeConfig(mergedConfig, vite);
   });
 }
 

+ 6 - 5
internal/vite-config/src/config/index.ts

@@ -9,9 +9,10 @@ import { defineLibraryConfig } from './library';
 export * from './application';
 export * from './library';
 
-function defineConfig(options: DefineConfig = {}) {
-  const { type = 'auto', ...defineOptions } = options;
-
+function defineConfig(
+  userConfigPromise?: DefineConfig,
+  type: 'application' | 'auto' | 'library' = 'auto',
+) {
   let projectType = type;
 
   // 根据包是否存在 index.html,自动判断类型
@@ -22,10 +23,10 @@ function defineConfig(options: DefineConfig = {}) {
 
   switch (projectType) {
     case 'application': {
-      return defineApplicationConfig(defineOptions);
+      return defineApplicationConfig(userConfigPromise);
     }
     case 'library': {
-      return defineLibraryConfig(defineOptions);
+      return defineLibraryConfig(userConfigPromise);
     }
     default: {
       throw new Error(`Unsupported project type: ${projectType}`);

+ 7 - 9
internal/vite-config/src/config/library.ts

@@ -1,4 +1,4 @@
-import type { UserConfig } from 'vite';
+import type { ConfigEnv, UserConfig } from 'vite';
 
 import type { DefineLibraryOptions } from '../typing';
 
@@ -9,11 +9,12 @@ import { defineConfig, mergeConfig } from 'vite';
 import { loadLibraryPlugins } from '../plugins';
 import { getCommonConfig } from './common';
 
-function defineLibraryConfig(options: DefineLibraryOptions = {}) {
-  return defineConfig(async (config) => {
+function defineLibraryConfig(userConfigPromise: DefineLibraryOptions) {
+  return defineConfig(async (config: ConfigEnv) => {
+    const options = await userConfigPromise?.(config);
     const { command, mode } = config;
     const root = process.cwd();
-    const { library = {}, vite = {} } = options;
+    const { library = {}, vite = {} } = options || {};
     const isBuild = command === 'build';
 
     const plugins = await loadLibraryPlugins({
@@ -22,7 +23,7 @@ function defineLibraryConfig(options: DefineLibraryOptions = {}) {
       injectMetadata: true,
       isBuild,
       mode,
-      ...(typeof library === 'function' ? await library(config) : library),
+      ...library,
     });
 
     const { dependencies = {}, peerDependencies = {} } =
@@ -52,10 +53,7 @@ function defineLibraryConfig(options: DefineLibraryOptions = {}) {
     };
     const commonConfig = await getCommonConfig();
     const mergedConfig = mergeConfig(commonConfig, packageConfig);
-    return mergeConfig(
-      mergedConfig,
-      typeof vite === 'function' ? await vite(config) : vite,
-    );
+    return mergeConfig(mergedConfig, vite);
   });
 }
 

+ 1 - 0
internal/vite-config/src/index.ts

@@ -1,3 +1,4 @@
 export * from './config';
+export * from './options';
 export * from './plugins';
 export { loadAndConvertEnv } from './utils/env';

+ 42 - 0
internal/vite-config/src/options.ts

@@ -0,0 +1,42 @@
+import type { Options as PwaPluginOptions } from 'vite-plugin-pwa';
+
+import type { ImportmapPluginOptions } from './typing';
+
+const isDevelopment = process.env.NODE_ENV === 'development';
+
+const getDefaultPwaOptions = (name: string): Partial<PwaPluginOptions> => ({
+  manifest: {
+    description:
+      'Vben Admin Pro is a modern admin dashboard template based on Vue 3. ',
+    icons: [
+      {
+        sizes: '192x192',
+        src: 'https://cdn.jsdelivr.net/npm/@vbenjs/static-source@0.1.3/source/pwa-icon-192.png',
+        type: 'image/png',
+      },
+      {
+        sizes: '512x512',
+        src: 'https://cdn.jsdelivr.net/npm/@vbenjs/static-source@0.1.3/source/pwa-icon-512.png',
+        type: 'image/png',
+      },
+    ],
+    name: `${name}o${isDevelopment ? ' dev' : ''}`,
+    short_name: `${name}${isDevelopment ? ' dev' : ''}`,
+  },
+});
+
+const defaultImportmapOptions: ImportmapPluginOptions = {
+  // 通过 Importmap CDN 方式引入,
+  // 目前只有esm.sh源兼容性好一点,jspm.io对于 esm 入口要求高
+  defaultProvider: 'esm.sh',
+  importmap: [
+    { name: 'vue' },
+    { name: 'pinia' },
+    { name: 'vue-router' },
+    { name: 'vue-i18n' },
+    { name: 'dayjs' },
+    { name: 'vue-demi' },
+  ],
+};
+
+export { defaultImportmapOptions, getDefaultPwaOptions };

+ 1 - 4
internal/vite-config/src/plugins/inject-metadata.ts

@@ -44,7 +44,7 @@ async function resolveMonorepoDependencies() {
 async function viteMetadataPlugin(
   root = process.cwd(),
 ): Promise<PluginOption | undefined> {
-  const { author, description, homepage, license, repository, version } =
+  const { author, description, homepage, license, version } =
     await readPackageJSON(root);
 
   const buildTime = dateUtil().format('YYYY-MM-DD HH:mm:ss');
@@ -53,8 +53,6 @@ async function viteMetadataPlugin(
     async config() {
       const { dependencies, devDependencies } =
         await resolveMonorepoDependencies();
-      const repositoryUrl =
-        typeof repository === 'object' ? repository.url : repository;
 
       const isAuthorObject = typeof author === 'object';
       const authorName = isAuthorObject ? author.name : author;
@@ -73,7 +71,6 @@ async function viteMetadataPlugin(
             devDependencies,
             homepage,
             license,
-            repositoryUrl,
             version,
           }),
         },

+ 9 - 14
internal/vite-config/src/typing.ts

@@ -91,22 +91,17 @@ interface ApplicationOptions extends ApplicationPluginOptions {}
 
 interface LibraryOptions extends LibraryPluginOptions {}
 
-interface DefineApplicationOptions {
-  application?:
-    | ((config: ConfigEnv) => Promise<ApplicationOptions>)
-    | ApplicationOptions;
-  vite?: ((config: ConfigEnv) => Promise<UserConfig>) | UserConfig;
-}
+type DefineApplicationOptions = (config?: ConfigEnv) => Promise<{
+  application?: ApplicationOptions;
+  vite?: UserConfig;
+}>;
 
-interface DefineLibraryOptions {
-  library?: ((config: ConfigEnv) => Promise<LibraryOptions>) | LibraryOptions;
-  vite?: ((config: ConfigEnv) => Promise<UserConfig>) | UserConfig;
-}
+type DefineLibraryOptions = (config?: ConfigEnv) => Promise<{
+  library?: LibraryOptions;
+  vite?: UserConfig;
+}>;
 
-type DefineConfig = {
-  type?: 'application' | 'auto' | 'library';
-} & DefineApplicationOptions &
-  DefineLibraryOptions;
+type DefineConfig = DefineApplicationOptions | DefineLibraryOptions;
 
 export type {
   ApplicationPluginOptions,

+ 5 - 1
internal/vite-config/src/utils/env.ts

@@ -54,7 +54,9 @@ async function loadEnv<T = Record<string, string>>(
 async function loadAndConvertEnv(
   match = 'VITE_',
   confFiles = getConfFiles(),
-): Promise<Partial<ApplicationPluginOptions>> {
+): Promise<
+  { appTitle: string; port: number } & Partial<ApplicationPluginOptions>
+> {
   const envConfig = await loadEnv(match, confFiles);
   const visualizer = envConfig.visualizer || '';
   const pwa = envConfig.pwa || '';
@@ -63,8 +65,10 @@ async function loadAndConvertEnv(
     .split(',')
     .filter((item) => ['brotli', 'gzip'].includes(item));
   return {
+    appTitle: envConfig?.VITE_GLOB_APP_TITLE ?? 'Vben Admin Pro',
     compress: !!compress,
     compressTypes: compressTypes as ('brotli' | 'gzip')[],
+    port: Number(envConfig.VITE_PORT) || 5173,
     pwa: !!pwa,
     visualizer: !!visualizer,
   };

+ 5 - 1
packages/@core/forward/README.md

@@ -1,3 +1,7 @@
 # @vben-core/forward
 
-该目录内的包,可直接被app所引用
+该目录内的包,可直接被app所引用,其是项目基础功能的一层抽象。允许轻微的副作用耦合,如`locales`的集成。
+
+## 注意事项
+
+- `forward` 内的包不允许相互引用,有相互引用的情况请考虑是否放到`packages/effects`下

+ 4 - 2
packages/@core/forward/request/src/request-client/modules/interceptor.ts

@@ -4,6 +4,8 @@ import {
   type InternalAxiosRequestConfig,
 } from 'axios';
 
+const errorHandler = (res: Error) => Promise.reject(res);
+
 class InterceptorManager {
   private axiosInstance: AxiosInstance;
 
@@ -19,7 +21,7 @@ class InterceptorManager {
   ) {
     this.axiosInstance.interceptors.request.use(
       fulfilled,
-      rejected || ((res) => Promise.reject(res)),
+      rejected || errorHandler,
     );
   }
 
@@ -31,7 +33,7 @@ class InterceptorManager {
   ) {
     this.axiosInstance.interceptors.response.use(
       fulfilled,
-      rejected || ((res) => Promise.reject(res)),
+      rejected || errorHandler,
     );
   }
 }

+ 11 - 1
packages/@core/shared/constants/src/index.ts

@@ -3,10 +3,20 @@
  */
 const VBEN_GITHUB_URL = 'https://github.com/vbenjs/vue-vben-admin';
 
+/**
+ * @zh_CN 文档地址
+ */
+const VBEN_DOC_URL = 'https://doc.vben.pro';
+
 /**
  * @zh_CN Vben Logo
  */
 const VBEN_LOGO_URL =
   'https://cdn.jsdelivr.net/npm/@vbenjs/static-source@0.1.3/source/logo-v1.webp';
 
-export { VBEN_GITHUB_URL, VBEN_LOGO_URL };
+/**
+ * @zh_CN Vben Admin 首页地址
+ */
+const VBEN_PREVIEW_URL = 'https://vben.pro';
+
+export { VBEN_DOC_URL, VBEN_GITHUB_URL, VBEN_LOGO_URL, VBEN_PREVIEW_URL };

+ 6 - 4
packages/@core/shared/design/vite.config.mts

@@ -1,7 +1,9 @@
 import { defineConfig } from '@vben/vite-config';
 
-export default defineConfig({
-  vite: {
-    publicDir: 'src/scss-bem',
-  },
+export default defineConfig(async () => {
+  return {
+    vite: {
+      publicDir: 'src/scss-bem',
+    },
+  };
 });

+ 1 - 1
packages/effects/README.md

@@ -2,7 +2,7 @@
 
 `effects` 目录专门用于存放与副作用相关的代码和逻辑。如果你的包具有以下特点,建议将其放置在 `effects` 目录下:
 
-- 使用状态管理框架 Pinia,并包含处理副作用(如异步操作、API 调用)的部分。
+- 使用状态管理框架 `pinia`,并包含处理副作用(如异步操作、API 调用)的部分。
 - 使用 `@vben-core/preferences` 处理用户偏好设置,涉及本地存储或浏览器缓存逻辑(如使用 `localStorage`)。
 - 处理导航、页面跳转等场景,需要管理路由变化的逻辑。
 - 包含与特定组件库紧密耦合或依赖大型仓库的部分。

+ 9 - 12
packages/effects/common-ui/src/about/about.vue

@@ -3,6 +3,11 @@ import type { AboutProps, DescriptionItem } from './about';
 
 import { h } from 'vue';
 
+import {
+  VBEN_DOC_URL,
+  VBEN_GITHUB_URL,
+  VBEN_PREVIEW_URL,
+} from '@vben/constants';
 import { VbenLink, VbenRenderContent } from '@vben-core/shadcn-ui';
 
 interface Props extends AboutProps {}
@@ -27,7 +32,6 @@ const {
   devDependencies = {},
   homepage,
   license,
-  repositoryUrl,
   version,
   // vite inject-metadata 插件注入的全局变量
   // eslint-disable-next-line no-undef
@@ -47,24 +51,17 @@ const vbenDescriptionItems: DescriptionItem[] = [
     title: '最后构建时间',
   },
   {
-    // TODO:
     content: h(VbenLink, { href: homepage }, { default: () => '点击查看' }),
     title: '主页',
   },
   {
-    // TODO:
-    content: h(
-      VbenLink,
-      { href: repositoryUrl },
-      { default: () => '点击查看' },
-    ),
+    content: h(VbenLink, { href: VBEN_DOC_URL }, { default: () => '点击查看' }),
     title: '文档地址',
   },
   {
-    // TODO:
     content: h(
       VbenLink,
-      { href: repositoryUrl },
+      { href: VBEN_PREVIEW_URL },
       { default: () => '点击查看' },
     ),
     title: '预览地址',
@@ -72,7 +69,7 @@ const vbenDescriptionItems: DescriptionItem[] = [
   {
     content: h(
       VbenLink,
-      { href: repositoryUrl },
+      { href: VBEN_GITHUB_URL },
       { default: () => '点击查看' },
     ),
     title: 'Github',
@@ -113,7 +110,7 @@ const devDependenciesItems = Object.keys(devDependencies).map((key) => ({
           {{ title }}
         </h3>
         <p class="text-foreground/80 mt-3 text-sm leading-6">
-          <VbenLink :href="repositoryUrl">
+          <VbenLink :href="VBEN_GITHUB_URL">
             {{ name }}
           </VbenLink>
           {{ description }}

+ 12 - 10
packages/styles/vite.config.mts

@@ -1,16 +1,18 @@
 import { defineConfig } from '@vben/vite-config';
 
-export default defineConfig({
-  vite: {
-    build: {
-      lib: {
-        entry: {
-          antd: 'src/antd/index.ts',
-          index: 'src/index.ts',
+export default defineConfig(async () => {
+  return {
+    vite: {
+      build: {
+        lib: {
+          entry: {
+            antd: 'src/antd/index.ts',
+            index: 'src/index.ts',
+          },
+          fileName: (_format, name) => `${name}.mjs`,
         },
-        fileName: (_format, name) => `${name}.mjs`,
       },
+      publicDir: 'src/bem',
     },
-    publicDir: 'src/bem',
-  },
+  };
 });

+ 20 - 0
pnpm-lock.yaml

@@ -137,6 +137,9 @@ importers:
       js-yaml:
         specifier: ^4.1.0
         version: 4.1.0
+      mockjs:
+        specifier: ^1.1.0
+        version: 1.1.0
       passport:
         specifier: ^0.7.0
         version: 0.7.0
@@ -162,6 +165,9 @@ importers:
       '@types/express':
         specifier: ^4.17.21
         version: 4.17.21
+      '@types/mockjs':
+        specifier: ^1.0.10
+        version: 1.0.10
       '@types/node':
         specifier: ^20.14.10
         version: 20.14.10
@@ -3002,6 +3008,7 @@ packages:
 
   '@ls-lint/ls-lint@2.2.3':
     resolution: {integrity: sha512-ekM12jNm/7O2I/hsRv9HvYkRdfrHpiV1epVuI2NP+eTIcEgdIdKkKCs9KgQydu/8R5YXTov9aHdOgplmCHLupw==}
+    cpu: [x64, arm64, s390x]
     os: [darwin, linux, win32]
     hasBin: true
 
@@ -3530,6 +3537,9 @@ packages:
   '@types/minimist@1.2.5':
     resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
 
+  '@types/mockjs@1.0.10':
+    resolution: {integrity: sha512-SXgrhajHG7boLv6oU93CcmdDm0HYRiceuz6b+7z+/2lCJPTWDv0V5YiwFHT2ejE4bQqgSXQiVPQYPWv7LGsK1g==}
+
   '@types/node@12.20.55':
     resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
 
@@ -6710,6 +6720,10 @@ packages:
   mlly@1.7.1:
     resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==}
 
+  mockjs@1.1.0:
+    resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==}
+    hasBin: true
+
   modern-normalize@2.0.0:
     resolution: {integrity: sha512-CxBoEVKh5U4DH3XuNbc5ONLF6dQBc8dSc7pdZ1957FGbIO5JBqGqqchhET9dTexri8/pk9xBL6+5ceOtCIp1QA==}
     engines: {node: '>=6'}
@@ -12254,6 +12268,8 @@ snapshots:
 
   '@types/minimist@1.2.5': {}
 
+  '@types/mockjs@1.0.10': {}
+
   '@types/node@12.20.55': {}
 
   '@types/node@18.19.39':
@@ -15922,6 +15938,10 @@ snapshots:
       pkg-types: 1.1.3
       ufo: 1.5.3
 
+  mockjs@1.1.0:
+    dependencies:
+      commander: 12.1.0
+
   modern-normalize@2.0.0: {}
 
   mri@1.2.0: {}