瀏覽代碼

feat: add docker shell

vben 11 月之前
父節點
當前提交
38d58394e3

+ 5 - 0
.dockerignore

@@ -0,0 +1,5 @@
+node_modules
+.git
+.gitignore
+*.md
+dist

+ 20 - 3
.vscode/settings.json

@@ -12,6 +12,8 @@
 
   // editor
   "editor.tabSize": 2,
+  "editor.detectIndentation": false,
+  "editor.cursorBlinking": "expand",
   "editor.defaultFormatter": "esbenp.prettier-vscode",
   "editor.fontFamily": "Input Mono, FiraCode-Retina, monospace",
   "editor.fontLigatures": true,
@@ -20,9 +22,17 @@
   "editor.cursorSmoothCaretAnimation": "on",
   "editor.guides.bracketPairs": "active",
   "editor.inlineSuggest.enabled": true,
-  "editor.suggestSelection": "first",
+  "editor.suggestSelection": "recentlyUsedByPrefix",
+  "editor.acceptSuggestionOnEnter": "smart",
+  "editor.suggest.snippetsPreventQuickSuggestions": false,
   "editor.stickyScroll.enabled": true,
   "editor.hover.sticky": true,
+  "editor.suggest.insertMode": "replace",
+  "editor.bracketPairColorization.enabled": true,
+  "editor.autoClosingBrackets": "beforeWhitespace",
+  "editor.autoClosingDelete": "always",
+  "editor.autoClosingOvertype": "always",
+  "editor.autoClosingQuotes": "beforeWhitespace",
   "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?",
   "editor.codeActionsOnSave": {
     "source.fixAll.eslint": "explicit",
@@ -38,6 +48,7 @@
   "terminal.integrated.persistentSessionReviveProcess": "never",
   "terminal.integrated.tabs.enabled": true,
   "terminal.integrated.scrollback": 10000,
+  "terminal.integrated.stickyScroll.enabled": true,
 
   // files
   "files.eol": "\n",
@@ -46,8 +57,8 @@
   "files.associations": {
     "*.ejs": "html",
     "*.art": "html",
-    "**/tsconfig.json": "jsonc"
-    // "*.json": "jsonc"
+    "**/tsconfig.json": "jsonc",
+    "*.json": "jsonc"
   },
 
   "files.exclude": {
@@ -77,6 +88,7 @@
   },
 
   // search
+  "search.searchEditor.singleClickBehaviour": "peekDefinition",
   "search.followSymlinks": false,
   // 在使用搜索功能时,将这些文件夹/文件排除在外
   "search.exclude": {
@@ -124,6 +136,10 @@
   "stylelint.packageManager": "pnpm",
   "stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
 
+  "typescript.inlayHints.enumMemberValues.enabled": true,
+  "typescript.preferences.preferTypeOnlyAutoImports": true,
+  "typescript.preferences.includePackageJsonAutoImports": "on",
+
   // Enable the ESlint flat config support
   "eslint.experimental.useFlatConfig": true,
   "eslint.validate": [
@@ -179,6 +195,7 @@
     "*.env": "$(capture).env.*",
     "README.md": "README*,CHANGELOG*,LICENSE,CNAME",
     "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json",
+    "Dockerfile": "Dockerfile,.docker*,docker-entrypoint.sh,build-local-docker*",
     "eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,.ls-lint*",
     "tailwind.config.mjs": "postcss.*"
   },

+ 30 - 0
Dockerfile

@@ -0,0 +1,30 @@
+FROM node:20-slim AS builder
+
+# --max-old-space-size
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+ENV NODE_OPTIONS=--max-old-space-size=8192
+ENV TZ=Asia/Shanghai
+
+RUN corepack enable
+
+WORKDIR /app
+
+# copy package.json and pnpm-lock.yaml to workspace
+COPY . /app
+
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
+RUN pnpm run build
+
+RUN echo "Builder Success 🎉"
+
+FROM nginx:stable-alpine as production
+
+COPY --from=builder /app/apps/antd-view/dist /usr/share/nginx/html
+
+COPY ./deploy/nginx.conf /etc/nginx/nginx.conf
+
+EXPOSE 8080
+
+# start nginx
+CMD ["nginx", "-g", "daemon off;"]

+ 33 - 0
apps/antd-view/src/bootstrap.ts

@@ -0,0 +1,33 @@
+import '@vben/styles';
+
+import { setupI18n } from '@vben/locales';
+import { preference } from '@vben/preference';
+import { setupStore } from '@vben/stores';
+import { createApp } from 'vue';
+
+import App from './app.vue';
+import { router } from './router';
+
+async function bootstrap(namespace: string, env: string) {
+  const app = createApp(App);
+
+  // 国际化 i18n 配置
+  await setupI18n(app, { defaultLocale: preference.locale });
+
+  // 配置 pinia-store
+  await setupStore(app, { env, namespace });
+
+  // 配置路由及路由守卫
+  app.use(router);
+
+  app.mount('#app');
+
+  // production mock server
+  if (import.meta.env.PROD) {
+    import('./mock-prod-server').then(({ setupProdMockServer }) => {
+      setupProdMockServer();
+    });
+  }
+}
+
+export { bootstrap };

+ 1 - 15
apps/antd-view/src/layouts/basic.vue

@@ -2,12 +2,7 @@
 import type { NotificationItem } from '@vben/common-ui';
 
 import { Notification, UserDropdown } from '@vben/common-ui';
-import {
-  IcRoundCreditScore,
-  IcRoundSettingsSuggest,
-  MdiDriveDocument,
-  MdiGithub,
-} from '@vben/icons';
+import { IcRoundCreditScore, MdiDriveDocument, MdiGithub } from '@vben/icons';
 import { BasicLayout } from '@vben/layouts';
 import { $t } from '@vben/locales';
 import { preference } from '@vben/preference';
@@ -79,15 +74,6 @@ const menus = computed(() => [
     icon: IcRoundCreditScore,
     text: $t('widgets.qa'),
   },
-  {
-    handler: () => {
-      // openWindow('https://github.com/vbenjs/vue-vben-admin', {
-      //   target: '_blank',
-      // });
-    },
-    icon: IcRoundSettingsSuggest,
-    text: $t('widgets.setting'),
-  },
 ]);
 
 const accessStore = useAccessStore();

+ 13 - 31
apps/antd-view/src/main.ts

@@ -1,40 +1,22 @@
-import '@vben/styles';
+import { setupPreference } from '@vben/preference';
 
-import { setupI18n } from '@vben/locales';
-import { preference, setupPreference } from '@vben/preference';
-import { setupStore } from '@vben/stores';
-import { createApp } from 'vue';
-
-import App from './app.vue';
 import { overridesPreference } from './preference';
-import { router } from './router';
 
-async function bootstrap(cachePrefix: string) {
-  // app偏好设置
+/**
+ * 应用初始化完成之后再进行页面加载渲染
+ */
+async function initApplication() {
+  const namespace = 'antd-view';
+  const env = import.meta.env.PROD ? 'prod' : 'dev';
+
+  // app偏好设置初始化
   await setupPreference({
-    cachePrefix,
+    env,
+    namespace,
     overrides: overridesPreference,
   });
 
-  const app = createApp(App);
-
-  // 国际化 i18n 配置
-  await setupI18n(app, { defaultLocale: preference.locale });
-
-  // 配置 pinia-store
-  await setupStore(app, { cachePrefix });
-
-  // 配置路由及路由守卫
-  app.use(router);
-
-  app.mount('#app');
-
-  // production mock server
-  if (import.meta.env.PROD) {
-    import('./mock-prod-server').then(({ setupProdMockServer }) => {
-      setupProdMockServer();
-    });
-  }
+  import('./bootstrap').then((m) => m.bootstrap(namespace, env));
 }
 
-bootstrap('vben-admin-pro-antd');
+initApplication();

+ 55 - 0
build-local-docker-image.sh

@@ -0,0 +1,55 @@
+#!/bin/bash
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log
+ERROR=""
+IMAGE_NAME="vben-admin-pro-local"
+
+function stop_and_remove_container() {
+    # Stop and remove the existing container
+    docker stop ${IMAGE_NAME} >/dev/null 2>&1
+    docker rm ${IMAGE_NAME} >/dev/null 2>&1
+}
+
+function remove_image() {
+    # Remove the existing image
+    docker rmi vben-admin-pro >/dev/null 2>&1
+}
+
+function install_dependencies() {
+    # Install all dependencies
+    cd ${SCRIPT_DIR}
+    pnpm install || ERROR="install_dependencies failed"
+}
+
+function build_image() {
+    # build docker
+    docker build . -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed"
+}
+
+function log_message() {
+    if [[ ${ERROR} != "" ]];
+    then
+        >&2 echo "build failed, Please check build-local-docker-image.log for more details"
+        >&2 echo "ERROR: ${ERROR}"
+        exit 1
+    else
+        echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container"
+        echo ""
+        echo "docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}"
+    fi
+}
+
+echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE}
+stop_and_remove_container
+remove_image
+
+echo "Info: Installing dependencies" | tee -a ${LOG_FILE}
+install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}
+
+if [[ ${ERROR} == "" ]]; then
+    echo "Info: Building docker image" | tee -a ${LOG_FILE}
+    build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}
+fi
+
+log_message | tee -a ${LOG_FILE}

+ 87 - 0
deploy/nginx.conf

@@ -0,0 +1,87 @@
+
+#user  nobody;
+worker_processes 1;
+
+#error_log  logs/error.log;
+#error_log  logs/error.log  notice;
+#error_log  logs/error.log  info;
+
+#pid        logs/nginx.pid;
+
+
+events {
+  worker_connections 1024;
+}
+
+
+http {
+  include mime.types;
+  default_type application/octet-stream;
+
+  types {
+    application/javascript  js mjs;
+    text/css                css;
+    text/html               html;
+  }
+
+  sendfile on;
+  # tcp_nopush     on;
+
+  #keepalive_timeout  0;
+  # keepalive_timeout 65;
+
+  # gzip on;
+  # gzip_buffers 32 16k;
+  # gzip_comp_level 6;
+  # gzip_min_length 1k;
+  # gzip_static on;
+  # gzip_types text/plain
+  #   text/css
+  #   application/javascript
+  #   application/json
+  #   application/x-javascript
+  #   text/xml
+  #   application/xml
+  #   application/xml+rss
+  #   text/javascript; #设置压缩的文件类型
+  # gzip_vary on;
+
+  server {
+    listen 8080;
+    server_name localhost;
+
+    location / {
+      root /usr/share/nginx/html;
+      try_files $uri $uri/ /index.html;
+      index index.html;
+      # Enable CORS
+      add_header 'Access-Control-Allow-Origin' '*';
+      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+      add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
+      if ($request_method = 'OPTIONS') {
+        add_header 'Access-Control-Max-Age' 1728000;
+        add_header 'Content-Type' 'text/plain charset=UTF-8';
+        add_header 'Content-Length' 0;
+        return 204;
+      }
+    }
+
+    error_page 500 502 503 504 /50x.html;
+
+    location = /50x.html {
+        root /usr/share/nginx/html;
+    }
+  }
+}
+
+# stream {    # stream 模块配置和 http 模块在相同级别
+#     upstream redis {
+#         server 127.0.0.1:6379 max_fails=3 fail_timeout=30s;
+#     }
+#     server {
+#         listen 16379;
+#         proxy_connect_timeout 1s;
+#         proxy_timeout 3s;
+#         proxy_pass redis;
+#     }
+# }

+ 1 - 1
internal/lint-configs/eslint-config/package.json

@@ -43,7 +43,7 @@
     "eslint-config-prettier": "^9.1.0",
     "eslint-plugin-eslint-comments": "^3.2.0",
     "eslint-plugin-i": "^2.29.1",
-    "eslint-plugin-jsdoc": "^48.2.5",
+    "eslint-plugin-jsdoc": "^48.2.6",
     "eslint-plugin-jsonc": "^2.15.1",
     "eslint-plugin-n": "^17.7.0",
     "eslint-plugin-no-only-tests": "^3.1.0",

+ 2 - 2
internal/tailwind-config/package.json

@@ -47,14 +47,14 @@
     "./*": "./*"
   },
   "dependencies": {
-    "@iconify/json": "^2.2.212",
+    "@iconify/json": "^2.2.213",
     "@iconify/tailwind": "^1.1.1",
     "@tailwindcss/forms": "^0.5.7",
     "autoprefixer": "^10.4.19",
     "cssnano": "^7.0.1",
     "postcss": "^8.4.38",
     "postcss-antd-fixes": "^0.2.0",
-    "postcss-preset-env": "^9.5.13",
+    "postcss-preset-env": "^9.5.14",
     "tailwindcss": "^3.4.3",
     "tailwindcss-animate": "^1.0.7"
   },

+ 2 - 1
package.json

@@ -45,7 +45,8 @@
     "format": "vsh lint --format",
     "prepare": "is-ci || husky",
     "reinstall": "pnpm clean --del-lock && pnpm bootstrap",
-    "test": "vitest"
+    "test": "vitest",
+    "build:docker": "./build-local-docker-image.sh"
   },
   "devDependencies": {
     "@changesets/cli": "^2.27.3",

+ 3 - 0
packages/@vben-core/README.md

@@ -0,0 +1,3 @@
+# @vben-core
+
+系统一些比较基础的SDK和UI组件库,请勿将任何业务逻辑和业务包放在这里。

+ 2 - 0
packages/@vben-core/shared/typings/src/preference.ts

@@ -91,6 +91,8 @@ interface Preference {
   pageTransitionEnable: boolean;
   /** 是否开启半深色菜单(只在theme='light'时生效) */
   semiDarkMenu: boolean;
+  /** 是否显示偏好设置 */
+  showPreference: boolean;
   /** 侧边栏是否折叠 */
   sideCollapse: boolean;
   /** 侧边栏折叠时,是否显示title */

+ 29 - 0
packages/@vben-core/shared/typings/src/tools.ts

@@ -80,6 +80,33 @@ type MaybeReadonlyRef<T> = (() => T) | ComputedRef<T>;
  */
 type MaybeComputedRef<T> = MaybeReadonlyRef<T> | MaybeRef<T>;
 
+type Merge<O extends object, T extends object> = {
+  [K in keyof O | keyof T]: K extends keyof T
+    ? T[K]
+    : K extends keyof O
+      ? O[K]
+      : never;
+};
+
+/**
+ * T = [
+ *  { name: string; age: number; },
+ *  { sex: 'male' | 'female'; age: string }
+ * ]
+ * =>
+ * MergeAll<T> = {
+ *  name: string;
+ *  sex: 'male' | 'female';
+ *  age: string
+ * }
+ */
+type MergeAll<
+  T extends object[],
+  R extends object = Record<string, any>,
+> = T extends [infer F extends object, ...infer Rest extends object[]]
+  ? MergeAll<Rest, Merge<R, F>>
+  : R;
+
 export {
   type AnyFunction,
   type AnyNormalFunction,
@@ -89,6 +116,8 @@ export {
   type IntervalHandle,
   type MaybeComputedRef,
   type MaybeReadonlyRef,
+  type Merge,
+  type MergeAll,
   type NonNullable,
   type Nullable,
   type ReadonlyRecordable,

+ 1 - 1
packages/@vben-core/uikit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue

@@ -22,6 +22,6 @@ const delegatedProps = computed(() => {
 <template>
   <DropdownMenuSeparator
     v-bind="delegatedProps"
-    :class="cn('bg-muted -mx-1 my-1 h-px', props.class)"
+    :class="cn('bg-border -mx-1 my-1 h-px', props.class)"
   />
 </template>

+ 5 - 7
packages/business/common-ui/src/preference/preference.vue

@@ -14,7 +14,7 @@ import {
 import { $t } from '@vben/locales';
 import { preference, resetPreference, usePreference } from '@vben/preference';
 import { useClipboard } from '@vueuse/core';
-import { computed, ref } from 'vue';
+import { computed } from 'vue';
 
 import {
   Animation,
@@ -33,6 +33,7 @@ import {
   ThemeColor,
 } from './blocks';
 import Trigger from './trigger.vue';
+import { useOpenPreference } from './use-open-preference';
 
 withDefaults(defineProps<{ colorPrimaryPresets: string[] }>(), {
   colorPrimaryPresets: () => [],
@@ -106,11 +107,7 @@ const showBreadcrumbConfig = computed(() => {
   );
 });
 
-const openSheet = ref(false);
-
-function handlerOpenSheet() {
-  openSheet.value = true;
-}
+const { openPreference } = useOpenPreference();
 
 async function handleCopy() {
   await copy(JSON.stringify(diffPreference.value, null, 2));
@@ -130,11 +127,12 @@ function handleReset() {
 <template>
   <div class="z-100 fixed right-0 top-1/3">
     <VbenSheet
+      v-model:open="openPreference"
       :description="$t('preference.preferences-subtitle')"
       :title="$t('preference.preferences')"
     >
       <template #trigger>
-        <Trigger @click="handlerOpenSheet" />
+        <Trigger />
       </template>
       <template #extra>
         <VbenIconButton

+ 16 - 0
packages/business/common-ui/src/preference/use-open-preference.ts

@@ -0,0 +1,16 @@
+import { ref } from 'vue';
+
+const openPreference = ref(false);
+
+function useOpenPreference() {
+  function handleOpenPreference() {
+    openPreference.value = true;
+  }
+
+  return {
+    handleOpenPreference,
+    openPreference,
+  };
+}
+
+export { useOpenPreference };

+ 27 - 15
packages/business/common-ui/src/user-dropdown/user-dropdown.vue

@@ -1,5 +1,7 @@
 <script setup lang="ts">
-import { IcRoundLogout } from '@vben-core/iconify';
+import type { AnyFunction } from '@vben/types';
+
+import { IcRoundLogout, IcRoundSettingsSuggest } from '@vben-core/iconify';
 import {
   Badge,
   DropdownMenu,
@@ -16,9 +18,11 @@ import {
 import type { Component } from 'vue';
 
 import { $t } from '@vben/locales';
-import { AnyFunction } from '@vben/types';
+import { preference } from '@vben/preference';
 import { ref } from 'vue';
 
+import { useOpenPreference } from '../preference/use-open-preference';
+
 interface Props {
   /**
    * 头像
@@ -59,6 +63,8 @@ const emit = defineEmits<{ logout: [] }>();
 const openPopover = ref(false);
 const openDialog = ref(false);
 
+const { handleOpenPreference } = useOpenPreference();
+
 function handleLogout() {
   // emit
   openDialog.value = true;
@@ -90,8 +96,8 @@ function handleSubmitLogout() {
         </div>
       </div>
     </DropdownMenuTrigger>
-    <DropdownMenuContent class="mr-2 min-w-[240px] p-0">
-      <DropdownMenuLabel class="border-border flex items-center border-b p-3">
+    <DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
+      <DropdownMenuLabel class="flex items-center p-3">
         <VbenAvatar
           :alt="text"
           :src="avatar"
@@ -117,22 +123,28 @@ function handleSubmitLogout() {
       <DropdownMenuItem
         v-for="menu in menus"
         :key="menu.text"
-        class="mx-1 rounded-sm py-2.5"
+        class="lineh mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
         @click="menu.handler"
       >
-        <VbenIcon :icon="menu.icon" class="mr-2 size-4" />
+        <VbenIcon :icon="menu.icon" class="mr-2 size-5" />
         {{ menu.text }}
       </DropdownMenuItem>
-
       <DropdownMenuSeparator />
-      <DropdownMenuItem class="w-full p-0">
-        <div
-          class="border-border flex-center hover:bg-accent hover:text-accent-foreground h-10 w-full cursor-pointer border-t"
-          @click="handleLogout"
-        >
-          <IcRoundLogout class="mr-2" />
-          {{ $t('common.logout') }}
-        </div>
+      <DropdownMenuItem
+        v-if="preference"
+        class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
+        @click="handleOpenPreference"
+      >
+        <IcRoundSettingsSuggest class="mr-2 size-5" />
+        {{ $t('preference.preferences') }}
+      </DropdownMenuItem>
+      <DropdownMenuSeparator />
+      <DropdownMenuItem
+        class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
+        @click="handleLogout"
+      >
+        <IcRoundLogout class="mr-2 size-5" />
+        {{ $t('common.logout') }}
       </DropdownMenuItem>
     </DropdownMenuContent>
   </DropdownMenu>

+ 1 - 1
packages/business/layouts/src/basic/layout.vue

@@ -127,7 +127,7 @@ function wrapperMenus(menus: MenuRecordRaw[]) {
       (value: boolean) => updatePreference('sideExpandOnHover', value)
     "
   >
-    <template #preference>
+    <template v-if="preference.showPreference" #preference>
       <PreferenceWidget />
     </template>
 

+ 2 - 3
packages/preference/src/cache.ts

@@ -2,7 +2,7 @@ import type { Preference } from '@vben-core/typings';
 
 class PreferenceCache {
   cachePrefix: string;
-  constructor(cachePrefix: string = 'vben-admin') {
+  constructor(cachePrefix: string) {
     this.cachePrefix = cachePrefix;
   }
 
@@ -24,8 +24,7 @@ class PreferenceCache {
    * 获取偏好设置的缓存键
    */
   getCacheKey(name: string = 'preference') {
-    const env = import.meta.env.DEV ? 'dev' : 'prod';
-    return `__${this.cachePrefix}-${name}-${env}__`;
+    return `__${this.cachePrefix}-${name}__`;
   }
 
   /**

+ 2 - 1
packages/preference/src/config.ts

@@ -34,8 +34,9 @@ const defaultPreference: Preference = {
   pageTransition: 'fade-slide',
   pageTransitionEnable: true,
   semiDarkMenu: true,
+  showPreference: true,
   sideCollapse: false,
-  sideCollapseShowTitle: false,
+  sideCollapseShowTitle: true,
   sideExpandOnHover: true,
   sideExtraCollapse: true,
   sideVisible: true,

+ 8 - 6
packages/preference/src/setup.ts

@@ -4,22 +4,24 @@ import { PreferenceCache } from './cache';
 import { overridesPreference } from './preference';
 
 interface SetupPreferenceOptions {
+  /**
+   * @zh_CN 环境
+   */
+  env: string;
   /**
    * @zh_CN 应用名,由于 @vben/preference 是公用的,后续可能有多个app,为了防止多个app缓存冲突,可在这里配置应用名
    * 应用名将被用于持久化的前缀
    */
-  cachePrefix?: string;
+  namespace: string;
   /**
    * @zh_CN app自行覆盖偏好设置
    */
   overrides?: DeepPartial<Preference>;
 }
 
-async function setupPreference(options: SetupPreferenceOptions = {}) {
-  const { cachePrefix = 'vben-admin-pro', overrides = {} } = options;
-
-  const cache = new PreferenceCache(cachePrefix);
-
+async function setupPreference(options: SetupPreferenceOptions) {
+  const { env, namespace, overrides = {} } = options;
+  const cache = new PreferenceCache(`${namespace}-${env}`);
   overridesPreference(overrides, cache);
 }
 

+ 8 - 5
packages/stores/src/setup.ts

@@ -3,26 +3,29 @@ import type { App } from 'vue';
 import { createPinia } from 'pinia';
 
 interface SetupStoreOptions {
+  /**
+   * @zh_CN 环境
+   */
+  env: string;
   /**
    * @zh_CN 应用名,由于 @vben/stores 是公用的,后续可能有多个app,为了防止多个app缓存冲突,可在这里配置应用名
    * 应用名将被用于持久化的前缀
    */
-  cachePrefix?: string;
+  namespace: string;
 }
 
 /**
  * @zh_CN 初始化pinia
  * @param app vue app 实例
  */
-async function setupStore(app: App, options: SetupStoreOptions = {}) {
+async function setupStore(app: App, options: SetupStoreOptions) {
   const { createPersistedState } = await import('pinia-plugin-persistedstate');
   const pinia = createPinia();
-  const { cachePrefix = 'vben-admin-pro' } = options;
-  const env = import.meta.env.DEV ? 'dev' : 'prod';
+  const { env, namespace } = options;
   pinia.use(
     createPersistedState({
       // key $appName-$store.id
-      key: (storeKey) => `__${cachePrefix}-${storeKey}-${env}__`,
+      key: (storeKey) => `__${namespace}-${env}-${storeKey}__`,
       storage: localStorage,
     }),
   );

+ 4 - 3
packages/styles/package.json

@@ -19,9 +19,6 @@
   "files": [
     "dist"
   ],
-  "sideEffects": [
-    "**/*.css"
-  ],
   "main": "./dist/index.mjs",
   "module": "./dist/index.mjs",
   "imports": {
@@ -42,6 +39,10 @@
       }
     }
   },
+  "peerDependencies": {
+    "@vben-core/design": "workspace:*",
+    "@vben-core/design-tokens": "workspace:*"
+  },
   "dependencies": {
     "@vben-core/design": "workspace:*",
     "@vben-core/design-tokens": "workspace:*"

+ 37 - 25
pnpm-lock.yaml

@@ -198,8 +198,8 @@ importers:
         specifier: ^2.29.1
         version: 2.29.1(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
       eslint-plugin-jsdoc:
-        specifier: ^48.2.5
-        version: 48.2.5(eslint@8.57.0)
+        specifier: ^48.2.6
+        version: 48.2.6(eslint@8.57.0)
       eslint-plugin-jsonc:
         specifier: ^2.15.1
         version: 2.15.1(eslint@8.57.0)
@@ -331,8 +331,8 @@ importers:
   internal/tailwind-config:
     dependencies:
       '@iconify/json':
-        specifier: ^2.2.212
-        version: 2.2.212
+        specifier: ^2.2.213
+        version: 2.2.213
       '@iconify/tailwind':
         specifier: ^1.1.1
         version: 1.1.1
@@ -352,8 +352,8 @@ importers:
         specifier: ^0.2.0
         version: 0.2.0(postcss@8.4.38)
       postcss-preset-env:
-        specifier: ^9.5.13
-        version: 9.5.13(postcss@8.4.38)
+        specifier: ^9.5.14
+        version: 9.5.14(postcss@8.4.38)
       tailwindcss:
         specifier: ^3.4.3
         version: 3.4.3
@@ -1815,8 +1815,8 @@ packages:
   '@humanwhocodes/object-schema@2.0.3':
     resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
 
-  '@iconify/json@2.2.212':
-    resolution: {integrity: sha512-d1IXjpbSwk8V3C9D+mruRTJRPqZZpCnOWh9zyG/Zc5zJmPDLBEHNTKz+ZmeiJQ6LdzgjwLJai1WgFvt1HWVIPw==}
+  '@iconify/json@2.2.213':
+    resolution: {integrity: sha512-5tcEn+ZDoWlBXmlJidYjMsJyFXhXuVscbg7PRpaon86GqrDlwW/cl8mR682C06Oq4AfeypmfVI18YTnczwdqxA==}
 
   '@iconify/tailwind@1.1.1':
     resolution: {integrity: sha512-4mmA//qjZigv7D4KlqcVSYTqfRIJzyts2/lSCAJfCL0rVMIE76+ifJnaE5jxCo1+nYGBF8FsFo0qFOs+sX4EnA==}
@@ -3643,8 +3643,8 @@ packages:
     peerDependencies:
       eslint: ^7.2.0 || ^8
 
-  eslint-plugin-jsdoc@48.2.5:
-    resolution: {integrity: sha512-ZeTfKV474W1N9niWfawpwsXGu+ZoMXu4417eBROX31d7ZuOk8zyG66SO77DpJ2+A9Wa2scw/jRqBPnnQo7VbcQ==}
+  eslint-plugin-jsdoc@48.2.6:
+    resolution: {integrity: sha512-GNk9jtpYmoEVeD/U6yYYmd6T8vSOoPs7CL8ZeX85iD8P3qifDdLQGze6+cw9boobDthmYnnxvIoHrhuSffj09g==}
     engines: {node: '>=18'}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
@@ -5554,8 +5554,8 @@ packages:
     peerDependencies:
       postcss: ^8.2.14
 
-  postcss-nesting@12.1.4:
-    resolution: {integrity: sha512-CcHOq94K137E+U4Ommu7pexcpp0Tjm24zl4UcqWs1oSLAr5cLI+jLrqQ5h/bdjhMX6cMbzunyustVNnvrzF8Zg==}
+  postcss-nesting@12.1.5:
+    resolution: {integrity: sha512-N1NgI1PDCiAGWPTYrwqm8wpjv0bgDmkYHH72pNsqTCv9CObxjxftdYu6AKtGN+pnJa7FQjMm3v4sp8QJbFsYdQ==}
     engines: {node: ^14 || ^16 || >=18}
     peerDependencies:
       postcss: ^8.4
@@ -5643,8 +5643,8 @@ packages:
     peerDependencies:
       postcss: ^8.4
 
-  postcss-preset-env@9.5.13:
-    resolution: {integrity: sha512-YQMwWu6MAc4Envrjf/mW2BTrb5J8WkrJ4dV2VostZVDhrmEPpYREOyhmvtlFLDxK1/AmTDY8aXjZViMC1qKu/w==}
+  postcss-preset-env@9.5.14:
+    resolution: {integrity: sha512-gTMi+3kENN/mN+K59aR+vEOjlkujTmmXJcM9rnAqGh9Y/euQ/ypdp9rd8mO1eoIjAD8vNS15+xbkBxoi+65BqQ==}
     engines: {node: ^14 || ^16 || >=18}
     peerDependencies:
       postcss: ^8.4
@@ -5703,6 +5703,10 @@ packages:
     resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
     engines: {node: '>=4'}
 
+  postcss-selector-parser@6.1.0:
+    resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
+    engines: {node: '>=4'}
+
   postcss-sorting@8.0.2:
     resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==}
     peerDependencies:
@@ -8036,9 +8040,9 @@ snapshots:
     dependencies:
       postcss: 8.4.38
 
-  '@csstools/selector-resolve-nested@1.1.0(postcss-selector-parser@6.0.16)':
+  '@csstools/selector-resolve-nested@1.1.0(postcss-selector-parser@6.1.0)':
     dependencies:
-      postcss-selector-parser: 6.0.16
+      postcss-selector-parser: 6.1.0
 
   '@csstools/selector-specificity@3.0.3(postcss-selector-parser@6.0.16)':
     dependencies:
@@ -8048,6 +8052,10 @@ snapshots:
     dependencies:
       postcss-selector-parser: 6.0.16
 
+  '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.1.0)':
+    dependencies:
+      postcss-selector-parser: 6.1.0
+
   '@csstools/utilities@1.0.0(postcss@8.4.38)':
     dependencies:
       postcss: 8.4.38
@@ -8280,7 +8288,7 @@ snapshots:
 
   '@humanwhocodes/object-schema@2.0.3': {}
 
-  '@iconify/json@2.2.212':
+  '@iconify/json@2.2.213':
     dependencies:
       '@iconify/types': 2.0.0
       pathe: 1.1.2
@@ -10390,7 +10398,7 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-plugin-jsdoc@48.2.5(eslint@8.57.0):
+  eslint-plugin-jsdoc@48.2.6(eslint@8.57.0):
     dependencies:
       '@es-joy/jsdoccomment': 0.43.0
       are-docs-informative: 0.0.2
@@ -10399,7 +10407,6 @@ snapshots:
       escape-string-regexp: 4.0.0
       eslint: 8.57.0
       esquery: 1.5.0
-      is-builtin-module: 3.2.1
       semver: 7.6.2
       spdx-expression-parse: 4.0.0
     transitivePeerDependencies:
@@ -12353,12 +12360,12 @@ snapshots:
       postcss: 8.4.38
       postcss-selector-parser: 6.0.16
 
-  postcss-nesting@12.1.4(postcss@8.4.38):
+  postcss-nesting@12.1.5(postcss@8.4.38):
     dependencies:
-      '@csstools/selector-resolve-nested': 1.1.0(postcss-selector-parser@6.0.16)
-      '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.0.16)
+      '@csstools/selector-resolve-nested': 1.1.0(postcss-selector-parser@6.1.0)
+      '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.0)
       postcss: 8.4.38
-      postcss-selector-parser: 6.0.16
+      postcss-selector-parser: 6.1.0
 
   postcss-normalize-charset@7.0.0(postcss@8.4.38):
     dependencies:
@@ -12429,7 +12436,7 @@ snapshots:
       postcss: 8.4.38
       postcss-value-parser: 4.2.0
 
-  postcss-preset-env@9.5.13(postcss@8.4.38):
+  postcss-preset-env@9.5.14(postcss@8.4.38):
     dependencies:
       '@csstools/postcss-cascade-layers': 4.0.6(postcss@8.4.38)
       '@csstools/postcss-color-function': 3.0.16(postcss@8.4.38)
@@ -12484,7 +12491,7 @@ snapshots:
       postcss-image-set-function: 6.0.3(postcss@8.4.38)
       postcss-lab-function: 6.0.16(postcss@8.4.38)
       postcss-logical: 7.0.1(postcss@8.4.38)
-      postcss-nesting: 12.1.4(postcss@8.4.38)
+      postcss-nesting: 12.1.5(postcss@8.4.38)
       postcss-opacity-percentage: 2.0.0(postcss@8.4.38)
       postcss-overflow-shorthand: 5.0.1(postcss@8.4.38)
       postcss-page-break: 3.0.4(postcss@8.4.38)
@@ -12537,6 +12544,11 @@ snapshots:
       cssesc: 3.0.0
       util-deprecate: 1.0.2
 
+  postcss-selector-parser@6.1.0:
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+
   postcss-sorting@8.0.2(postcss@8.4.38):
     dependencies:
       postcss: 8.4.38