Compare commits
38 Commits
urv
...
042c47f34f
| Author | SHA1 | Date | |
|---|---|---|---|
| 042c47f34f | |||
| 17730cfb10 | |||
| c4b93140f0 | |||
| 1a9257249f | |||
|
|
66280dc6a1 | ||
| 16c93a82a2 | |||
| 16d4b3f749 | |||
| 42f63f7134 | |||
| 9d12927793 | |||
| bb82a6ab83 | |||
| 76d2a45015 | |||
|
|
935251ee53 | ||
| 5472f1c9b9 | |||
| 744703811a | |||
| be3d59691b | |||
| f6bccd7536 | |||
| 4673d622b6 | |||
| 0e467a1e9d | |||
| 7a5610c0dc | |||
| 80d989f6d0 | |||
| 6097d39752 | |||
| 4bc62221b6 | |||
| c405bc9481 | |||
| 54cc46b33a | |||
| 65ee7cccb3 | |||
| 6da6e59b6d | |||
| 8e6d7488f4 | |||
|
|
9e050306bb | ||
| 7f1811098f | |||
| 40b3686f2e | |||
| dfc64ecece | |||
| 1df5110034 | |||
| 731a3da55d | |||
| 4e5b3cb96c | |||
| 5e8df2572f | |||
|
|
7d6474c92b | ||
|
|
86920da611 | ||
| 3828f12a2d |
@@ -1,65 +1,31 @@
|
|||||||
{
|
{
|
||||||
"image": "ghcr.io/yanhao98/h-devcontainer:main",
|
"image": "ghcr.io/yanhao98/h-devcontainer:main",
|
||||||
"runArgs": ["--name=${localWorkspaceFolderBasename}-devcontainer"],
|
"runArgs": [
|
||||||
"forwardPorts": [4730, 4731], // vscode://settings/remote.localPortHost -> 默认只监听 localhost
|
"--hostname=devcontainer-host",
|
||||||
|
"--name=${localWorkspaceFolderBasename}-devcontainer"
|
||||||
|
],
|
||||||
|
"forwardPorts": [4730, 4731, 5901],
|
||||||
"portsAttributes": {
|
"portsAttributes": {
|
||||||
"4730": { "label": "开发服务器端口", "onAutoForward": "notify" },
|
"4730": { "label": "开发服务器端口", "onAutoForward": "notify" },
|
||||||
"4731": { "label": "预览服务器端口", "onAutoForward": "notify" }
|
"4731": { "label": "预览服务器端口", "onAutoForward": "notify" }
|
||||||
},
|
},
|
||||||
"remoteEnv": {
|
|
||||||
"ANTHROPIC_AUTH_TOKEN": "${localEnv:ANTHROPIC_AUTH_TOKEN}",
|
|
||||||
"ANTHROPIC_BASE_URL": "${localEnv:ANTHROPIC_BASE_URL}",
|
|
||||||
"GEMINI_API_KEY": "${localEnv:GEMINI_API_KEY}",
|
|
||||||
"GOOGLE_GEMINI_BASE_URL": "${localEnv:GOOGLE_GEMINI_BASE_URL}"
|
|
||||||
},
|
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"NODE_OPTIONS": "--max-old-space-size=4096",
|
|
||||||
"TZ": "${localEnv:TZ:Asia/Shanghai}"
|
"TZ": "${localEnv:TZ:Asia/Shanghai}"
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": ["prettier.prettier-vscode", "vue.volar"],
|
||||||
// AI
|
|
||||||
"github.copilot-chat",
|
|
||||||
"anthropic.claude-code",
|
|
||||||
"google.gemini-cli-vscode-ide-companion",
|
|
||||||
"vicanent.gcmp",
|
|
||||||
// >>>>>
|
|
||||||
// "eamodio.gitlens",
|
|
||||||
"tu6ge.naive-ui-intelligence",
|
|
||||||
"gruntfuggly.todo-tree",
|
|
||||||
"lokalise.i18n-ally",
|
|
||||||
"vitest.explorer",
|
|
||||||
"antfu.unocss",
|
|
||||||
"vue.volar",
|
|
||||||
// <<<<<
|
|
||||||
// 代码质量 / 格式化 / Lint
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"stylelint.vscode-stylelint",
|
|
||||||
"oxc.oxc-vscode",
|
|
||||||
"esbenp.prettier-vscode"
|
|
||||||
],
|
|
||||||
"settings": {
|
"settings": {
|
||||||
"editor.formatOnSave": true,
|
// "tasks": { "version": "2.0.0", "tasks": [] },
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"github.copilot.chat.codeGeneration.instructions": [
|
||||||
"editor.codeActionsOnSave": {
|
{
|
||||||
"source.fixAll.eslint": "explicit"
|
"text": "This dev container includes a lightweight Fluxbox based desktop that can be accessed using a VNC viewer or the web. GUI-based commands executed from the built-in VS Code terminal will open on the desktop automatically."
|
||||||
},
|
}
|
||||||
"chat.extensionUnification.enabled": true,
|
]
|
||||||
"chat.tools.terminal.autoApprove": {
|
|
||||||
"/.*/": true,
|
|
||||||
"git push": false
|
|
||||||
},
|
|
||||||
// * 尽管使用了“/.*/”,但有些还是会失败,因为有几个错误的默认值:
|
|
||||||
// * https://github.com/microsoft/vscode/issues/266651#issuecomment-3292581459
|
|
||||||
"chat.tools.terminal.ignoreDefaultAutoApproveRules": true,
|
|
||||||
"tasks": { "version": "2.0.0", "tasks": [] },
|
|
||||||
"terminal.integrated.defaultProfile.linux": "zsh"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mounts": [
|
"mounts": [
|
||||||
// 不挂载还可能会遇到:`Cannot run macOS (Mach-O) executable in Docker: Exec format error`
|
|
||||||
"source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
|
"source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
|
||||||
"source=${localWorkspaceFolder}/.devcontainer/lifecycle-scripts.d,target=/usr/local/etc/lifecycle-scripts.d,type=bind,consistency=delegated"
|
"source=${localWorkspaceFolder}/.devcontainer/lifecycle-scripts.d,target=/usr/local/etc/lifecycle-scripts.d,type=bind,consistency=delegated"
|
||||||
],
|
],
|
||||||
@@ -69,7 +35,5 @@
|
|||||||
"updateContentCommand": "/usr/local/bin/run-lifecycle-scripts.sh updateContentCommand",
|
"updateContentCommand": "/usr/local/bin/run-lifecycle-scripts.sh updateContentCommand",
|
||||||
"postCreateCommand": "/usr/local/bin/run-lifecycle-scripts.sh postCreateCommand",
|
"postCreateCommand": "/usr/local/bin/run-lifecycle-scripts.sh postCreateCommand",
|
||||||
"postStartCommand": "/usr/local/bin/run-lifecycle-scripts.sh postStartCommand",
|
"postStartCommand": "/usr/local/bin/run-lifecycle-scripts.sh postStartCommand",
|
||||||
"postAttachCommand": "/usr/local/bin/run-lifecycle-scripts.sh postAttachCommand",
|
"postAttachCommand": "/usr/local/bin/run-lifecycle-scripts.sh postAttachCommand"
|
||||||
"waitFor": "updateContentCommand",
|
|
||||||
"remoteUser": "usr_vscode"
|
|
||||||
}
|
}
|
||||||
|
|||||||
0
.devcontainer/lifecycle-scripts.d/.gitkeep
Normal file
0
.devcontainer/lifecycle-scripts.d/.gitkeep
Normal file
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/zsh -eu
|
|
||||||
# 打印带有颜色的欢迎信息
|
|
||||||
echo -e "\033[1;32m↘️ 容器首次创建!\033[0m"
|
|
||||||
|
|
||||||
# 修复权限问题(比如 node_modules 目录)
|
|
||||||
sudo chown -R $(whoami):$(whoami) /workspaces || true
|
|
||||||
|
|
||||||
# 调用内置命令 (这些命令在 _build-context/builtin-scripts 目录中的脚本中定义)
|
|
||||||
h-setup-locale
|
|
||||||
h-setup-zsh
|
|
||||||
|
|
||||||
h-setup-bun-bin
|
|
||||||
h-setup-pnpm-bin
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash -eu
|
|
||||||
# 容器内容更新时的消息和依赖安装
|
|
||||||
|
|
||||||
echo '↘️ 容器内容已更新!'
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
if command -v pnpm >/dev/null 2>&1; then
|
|
||||||
# 跳过: The modules directory at "/workspaces/h-devcontainers/node_modules" will be removed and reinstalled from scratch. Proceed? (Y/n) ·
|
|
||||||
time pnpm install --config.confirmModulesPurge=false
|
|
||||||
else
|
|
||||||
echo '❌错误: pnpm 未安装'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
14
.devcontainer/lifecycle-scripts.d/04-postStartCommand.d/-
Executable file
14
.devcontainer/lifecycle-scripts.d/04-postStartCommand.d/-
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/zsh -eu
|
||||||
|
h-setup-zh-locale
|
||||||
|
|
||||||
|
h-setup-bun-bin
|
||||||
|
h-setup-pnpm-bin
|
||||||
|
|
||||||
|
h-setup-chromium
|
||||||
|
h-setup-desktop-lite
|
||||||
|
|
||||||
|
h-install-node-modules
|
||||||
|
|
||||||
|
echo "-----------------------------"
|
||||||
|
echo "开发容器已启动并配置完成!"
|
||||||
|
echo "-----------------------------"
|
||||||
2
.github/workflows/ci-cd.yaml
vendored
2
.github/workflows/ci-cd.yaml
vendored
@@ -14,7 +14,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
playwright:
|
playwright:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: mcr.microsoft.com/playwright:v1.56.1-noble
|
container: mcr.microsoft.com/playwright:v1.57.0-noble
|
||||||
steps:
|
steps:
|
||||||
- name: ⚙️ 设置 Node 环境
|
- name: ⚙️ 设置 Node 环境
|
||||||
uses: yanhao98/composite-actions/setup-node-environment@faab20ac2f9c85dfce1a4147fca493bf632bd744
|
uses: yanhao98/composite-actions/setup-node-environment@faab20ac2f9c85dfce1a4147fca493bf632bd744
|
||||||
|
|||||||
2
.github/workflows/测试最新依赖.yaml
vendored
2
.github/workflows/测试最新依赖.yaml
vendored
@@ -60,7 +60,7 @@ jobs:
|
|||||||
|
|
||||||
playwright:
|
playwright:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: mcr.microsoft.com/playwright:v1.56.1-noble
|
container: mcr.microsoft.com/playwright:v1.57.0-noble
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"trailingComma": "all"
|
"trailingComma": "all",
|
||||||
|
"plugins": ["@prettier/plugin-oxc"]
|
||||||
}
|
}
|
||||||
|
|||||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -5,7 +5,7 @@
|
|||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"EditorConfig.EditorConfig",
|
"EditorConfig.EditorConfig",
|
||||||
"oxc.oxc-vscode",
|
"oxc.oxc-vscode",
|
||||||
"esbenp.prettier-vscode",
|
"prettier.prettier-vscode",
|
||||||
"stylelint.vscode-stylelint",
|
"stylelint.vscode-stylelint",
|
||||||
"lokalise.i18n-ally"
|
"lokalise.i18n-ally"
|
||||||
]
|
]
|
||||||
|
|||||||
50
.vscode/settings.json
vendored
50
.vscode/settings.json
vendored
@@ -1,29 +1,54 @@
|
|||||||
{
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"typescript.preferences.autoImportFileExcludePatterns": [
|
||||||
|
"vue-router$",
|
||||||
|
"**/src/composables/**",
|
||||||
|
"**/*-auto-imports.ts",
|
||||||
|
"**/*-auto-imports.types.ts"
|
||||||
|
],
|
||||||
|
"search.exclude": {
|
||||||
|
"public/report-ui-dist": true
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 代码格式化相关配置
|
||||||
|
// ============================================================
|
||||||
|
"prettier.enable": true,
|
||||||
|
"files.readonlyInclude": {
|
||||||
|
"dist/**": true
|
||||||
|
},
|
||||||
|
"eslint.enable": true,
|
||||||
|
"oxc.enable": true,
|
||||||
|
"stylelint.enable": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": "explicit",
|
"source.fixAll": "explicit",
|
||||||
"source.fixAll.eslint": "explicit",
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.fixAll.stylelint": "explicit",
|
|
||||||
"source.fixAll.oxc": "explicit",
|
"source.fixAll.oxc": "explicit",
|
||||||
"source.organizeImports": "never"
|
"source.fixAll.stylelint": "explicit",
|
||||||
|
"source.organizeImports": "explicit"
|
||||||
},
|
},
|
||||||
"eslint.enable": true,
|
|
||||||
"stylelint.enable": true,
|
|
||||||
"oxc.enable": true,
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"stylelint.validate": ["css", "less", "postcss", "scss", "vue"],
|
"stylelint.validate": ["css", "less", "postcss", "scss", "vue"],
|
||||||
"scss.lint.unknownAtRules": "ignore",
|
"scss.lint.unknownAtRules": "ignore",
|
||||||
"css.lint.unknownAtRules": "ignore",
|
"css.lint.unknownAtRules": "ignore",
|
||||||
"less.lint.unknownAtRules": "ignore",
|
"less.lint.unknownAtRules": "ignore",
|
||||||
|
"editor.defaultFormatter": "prettier.prettier-vscode",
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "prettier.prettier-vscode"
|
||||||
|
},
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "prettier.prettier-vscode"
|
||||||
},
|
},
|
||||||
"[json]": {
|
"[json]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "prettier.prettier-vscode"
|
||||||
},
|
},
|
||||||
"[jsonc]": {
|
"[jsonc]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "prettier.prettier-vscode"
|
||||||
},
|
},
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
||||||
|
// ============================================================
|
||||||
|
// i18n-ally 配置
|
||||||
|
// ============================================================
|
||||||
// >>>>>
|
// >>>>>
|
||||||
"i18n-ally.readonly": false,
|
"i18n-ally.readonly": false,
|
||||||
"i18n-ally.namespace": false /* 禁用命名空间(@intlify/unplugin-vue-i18n不支持吧?) */,
|
"i18n-ally.namespace": false /* 禁用命名空间(@intlify/unplugin-vue-i18n不支持吧?) */,
|
||||||
@@ -34,10 +59,7 @@
|
|||||||
"i18n-ally.enabledParsers": ["json"],
|
"i18n-ally.enabledParsers": ["json"],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.sourceLanguage": "zh-CN", // 翻译源语言 (源文件) 根据此语言文件翻译其他语言文件的变量和内容
|
"i18n-ally.sourceLanguage": "zh-CN", // 翻译源语言 (源文件) 根据此语言文件翻译其他语言文件的变量和内容
|
||||||
"i18n-ally.displayLanguage": "zh-CN", // 显示语言 (显示文件/翻译文件)
|
"i18n-ally.displayLanguage": "zh-CN" // 显示语言 (显示文件/翻译文件)
|
||||||
// <<<<<
|
// <<<<<
|
||||||
// https://github.com/copilot/share/8a1a019a-0180-80e7-8141-a40be02c4006
|
|
||||||
// "iconify.customCollectionJsonPaths": ["https://example.com/my-icons.json", "./local/icons.json"],
|
// "iconify.customCollectionJsonPaths": ["https://example.com/my-icons.json", "./local/icons.json"],
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
|
||||||
"typescript.preferences.autoImportFileExcludePatterns": ["vue-router/auto$"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
6
auto-imports.d.ts
vendored
6
auto-imports.d.ts
vendored
@@ -42,6 +42,7 @@ declare global {
|
|||||||
const debouncedWatch: typeof import('@vueuse/core').debouncedWatch
|
const debouncedWatch: typeof import('@vueuse/core').debouncedWatch
|
||||||
const deepFreeze: typeof import('deep-freeze-es6').default
|
const deepFreeze: typeof import('deep-freeze-es6').default
|
||||||
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
|
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
|
||||||
|
const defineBasicLoader: typeof import('unplugin-vue-router/data-loaders/basic').defineBasicLoader
|
||||||
const defineComponent: typeof import('vue').defineComponent
|
const defineComponent: typeof import('vue').defineComponent
|
||||||
const defineStore: typeof import('pinia').defineStore
|
const defineStore: typeof import('pinia').defineStore
|
||||||
const eagerComputed: typeof import('@vueuse/core').eagerComputed
|
const eagerComputed: typeof import('@vueuse/core').eagerComputed
|
||||||
@@ -64,7 +65,6 @@ declare global {
|
|||||||
const isRef: typeof import('vue').isRef
|
const isRef: typeof import('vue').isRef
|
||||||
const isShallow: typeof import('vue').isShallow
|
const isShallow: typeof import('vue').isShallow
|
||||||
const makeDestructurable: typeof import('@vueuse/core').makeDestructurable
|
const makeDestructurable: typeof import('@vueuse/core').makeDestructurable
|
||||||
const manualResetRef: typeof import('@vueuse/core').manualResetRef
|
|
||||||
const mapActions: typeof import('pinia').mapActions
|
const mapActions: typeof import('pinia').mapActions
|
||||||
const mapGetters: typeof import('pinia').mapGetters
|
const mapGetters: typeof import('pinia').mapGetters
|
||||||
const mapState: typeof import('pinia').mapState
|
const mapState: typeof import('pinia').mapState
|
||||||
@@ -222,7 +222,6 @@ declare global {
|
|||||||
const useIntervalFn: typeof import('@vueuse/core').useIntervalFn
|
const useIntervalFn: typeof import('@vueuse/core').useIntervalFn
|
||||||
const useKeyModifier: typeof import('@vueuse/core').useKeyModifier
|
const useKeyModifier: typeof import('@vueuse/core').useKeyModifier
|
||||||
const useLastChanged: typeof import('@vueuse/core').useLastChanged
|
const useLastChanged: typeof import('@vueuse/core').useLastChanged
|
||||||
const useLink: typeof import('vue-router/auto').useLink
|
|
||||||
const useLoadingBar: typeof import('naive-ui').useLoadingBar
|
const useLoadingBar: typeof import('naive-ui').useLoadingBar
|
||||||
const useLocalStorage: typeof import('@vueuse/core').useLocalStorage
|
const useLocalStorage: typeof import('@vueuse/core').useLocalStorage
|
||||||
const useMagicKeys: typeof import('@vueuse/core').useMagicKeys
|
const useMagicKeys: typeof import('@vueuse/core').useMagicKeys
|
||||||
@@ -388,6 +387,7 @@ declare module 'vue' {
|
|||||||
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
|
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
|
||||||
readonly deepFreeze: UnwrapRef<typeof import('deep-freeze-es6')['default']>
|
readonly deepFreeze: UnwrapRef<typeof import('deep-freeze-es6')['default']>
|
||||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||||
|
readonly defineBasicLoader: UnwrapRef<typeof import('unplugin-vue-router/data-loaders/basic')['defineBasicLoader']>
|
||||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||||
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
||||||
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
|
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
|
||||||
@@ -410,7 +410,6 @@ declare module 'vue' {
|
|||||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||||
readonly isShallow: UnwrapRef<typeof import('vue')['isShallow']>
|
readonly isShallow: UnwrapRef<typeof import('vue')['isShallow']>
|
||||||
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']>
|
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']>
|
||||||
readonly manualResetRef: UnwrapRef<typeof import('@vueuse/core')['manualResetRef']>
|
|
||||||
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
||||||
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
||||||
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
||||||
@@ -568,7 +567,6 @@ declare module 'vue' {
|
|||||||
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
|
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
|
||||||
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
|
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
|
||||||
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
|
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
|
||||||
readonly useLink: UnwrapRef<typeof import('vue-router/auto')['useLink']>
|
|
||||||
readonly useLoadingBar: UnwrapRef<typeof import('naive-ui')['useLoadingBar']>
|
readonly useLoadingBar: UnwrapRef<typeof import('naive-ui')['useLoadingBar']>
|
||||||
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
|
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
|
||||||
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>
|
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import type { UserConfig } from '@commitlint/types';
|
import type { UserConfig } from '@commitlint/types';
|
||||||
|
|
||||||
|
|
||||||
const Configuration: UserConfig = {
|
const Configuration: UserConfig = {
|
||||||
extends: ['@commitlint/config-conventional'],
|
extends: ['@commitlint/config-conventional'],
|
||||||
formatter: '@commitlint/format',
|
formatter: '@commitlint/format',
|
||||||
|
rules: {
|
||||||
|
'body-max-line-length': [2, 'always', 500],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Configuration;
|
export default Configuration;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "@tsconfig/node22/tsconfig.json",
|
"extends": "@tsconfig/node24/tsconfig.json",
|
||||||
"include": ["./**/*"]
|
"include": ["./**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
import pluginImport from 'eslint-plugin-import';
|
import pluginImport from 'eslint-plugin-import';
|
||||||
import pluginJsonc from 'eslint-plugin-jsonc';
|
import pluginJsonc from 'eslint-plugin-jsonc';
|
||||||
import pluginOxlint from 'eslint-plugin-oxlint';
|
import pluginOxlint from 'eslint-plugin-oxlint';
|
||||||
|
import pluginPerfectionist from 'eslint-plugin-perfectionist';
|
||||||
import pluginPlaywright from 'eslint-plugin-playwright';
|
import pluginPlaywright from 'eslint-plugin-playwright';
|
||||||
import pluginVue from 'eslint-plugin-vue';
|
import pluginVue from 'eslint-plugin-vue';
|
||||||
import { globalIgnores } from 'eslint/config';
|
import { globalIgnores } from 'eslint/config';
|
||||||
@@ -24,7 +25,14 @@ export default defineConfigWithVueTs(
|
|||||||
files: ['**/*.{ts,mts,tsx,vue}'],
|
files: ['**/*.{ts,mts,tsx,vue}'],
|
||||||
},
|
},
|
||||||
|
|
||||||
globalIgnores(['worker-configuration.d.ts', '**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
|
globalIgnores([
|
||||||
|
'worker-configuration.d.ts',
|
||||||
|
'**/dist/**',
|
||||||
|
'**/dist-ssr/**',
|
||||||
|
'**/coverage/**',
|
||||||
|
'**/public/**',
|
||||||
|
'**/-----TEMP-----/**',
|
||||||
|
]),
|
||||||
|
|
||||||
pluginVue.configs['flat/essential'],
|
pluginVue.configs['flat/essential'],
|
||||||
vueTsConfigs.recommended,
|
vueTsConfigs.recommended,
|
||||||
@@ -45,6 +53,13 @@ export default defineConfigWithVueTs(
|
|||||||
{
|
{
|
||||||
rules: {
|
rules: {
|
||||||
'@intlify/vue-i18n/no-raw-text': 'off',
|
'@intlify/vue-i18n/no-raw-text': 'off',
|
||||||
|
'@intlify/vue-i18n/no-unused-keys': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
src: './src',
|
||||||
|
extensions: ['.js', '.ts', '.tsx', '.vue'],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
'vue-i18n': {
|
'vue-i18n': {
|
||||||
@@ -54,9 +69,7 @@ export default defineConfigWithVueTs(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
plugins: {
|
plugins: { import: pluginImport },
|
||||||
import: pluginImport,
|
|
||||||
},
|
|
||||||
rules: {
|
rules: {
|
||||||
'import/first': 'error',
|
'import/first': 'error',
|
||||||
'import/no-duplicates': 'error',
|
'import/no-duplicates': 'error',
|
||||||
@@ -70,6 +83,8 @@ export default defineConfigWithVueTs(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ plugins: { perfectionist: pluginPerfectionist } },
|
||||||
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 启用 sort-keys 规则以强制对象键按字母顺序排序
|
* 启用 sort-keys 规则以强制对象键按字母顺序排序
|
||||||
@@ -102,7 +117,11 @@ export default defineConfigWithVueTs(
|
|||||||
'vue/attributes-order': 'error',
|
'vue/attributes-order': 'error',
|
||||||
'vue/multi-word-component-names': 'off',
|
'vue/multi-word-component-names': 'off',
|
||||||
'vue/padding-line-between-blocks': ['error', 'always'],
|
'vue/padding-line-between-blocks': ['error', 'always'],
|
||||||
|
'vue/component-name-in-template-casing': [
|
||||||
|
'error',
|
||||||
|
'PascalCase',
|
||||||
|
{ registeredComponentsOnly: false, ignores: [] },
|
||||||
|
],
|
||||||
// '@stylistic/padding-line-between-statements': [
|
// '@stylistic/padding-line-between-statements': [
|
||||||
// 'error',
|
// 'error',
|
||||||
// { blankLine: 'always', prev: '*', next: ['const', 'let', 'var'] },
|
// { blankLine: 'always', prev: '*', next: ['const', 'let', 'var'] },
|
||||||
|
|||||||
37
package.json
37
package.json
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"packageManager": "pnpm@10.23.0",
|
"packageManager": "pnpm@10.25.0",
|
||||||
"name": "vue-ts-example-2025",
|
"name": "vue-ts-example-2025",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"all": "run-s lint format:prettier build-only type-check test:unit:DisableWatch",
|
"all": "run-s lint format:prettier build-only type-check test:unit:DisableWatch",
|
||||||
"dev": "vite --port 4730 --host --strictPort",
|
"dev": "nodemon --delay 280ms --watch vite-plugins --ext ts -x vite -- --port 4730 --host --strictPort",
|
||||||
"build": "run-p type-check \"build-only {@}\" --",
|
"build": "run-p type-check \"build-only {@}\" --",
|
||||||
"build-only": "vite build",
|
"build-only": "vite build",
|
||||||
"preview": "vite preview --port 4731 --host --strictPort",
|
"preview": "vite preview --port 4731 --host --strictPort",
|
||||||
@@ -57,8 +57,8 @@
|
|||||||
"@commitlint/cli": "^20.1.0",
|
"@commitlint/cli": "^20.1.0",
|
||||||
"@commitlint/config-conventional": "^20.0.0",
|
"@commitlint/config-conventional": "^20.0.0",
|
||||||
"@formkit/auto-animate": "^0.9.0",
|
"@formkit/auto-animate": "^0.9.0",
|
||||||
"@pinia/colada": "^0.17.8",
|
"@pinia/colada": "^0.21.0",
|
||||||
"@primeuix/themes": "^1.2.5",
|
"@primeuix/themes": "^2.0.0",
|
||||||
"@sa/materials": "workspace:*",
|
"@sa/materials": "workspace:*",
|
||||||
"@unhead/vue": "^2.0.19",
|
"@unhead/vue": "^2.0.19",
|
||||||
"@vueuse/core": "^14.0.0",
|
"@vueuse/core": "^14.0.0",
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
"primelocale": "^2.2.2",
|
"primelocale": "^2.2.2",
|
||||||
"primevue": "^4.4.1",
|
"primevue": "^4.4.1",
|
||||||
"ts-enum-util": "^4.1.0",
|
"ts-enum-util": "^4.1.0",
|
||||||
"utils4u": "^4.2.3",
|
"utils4u": "^5",
|
||||||
"vue": "^3.5.24",
|
"vue": "^3.5.24",
|
||||||
"vue-i18n": "^11.2.1",
|
"vue-i18n": "^11.2.1",
|
||||||
"vue-memoize-dict": "^1.1.3",
|
"vue-memoize-dict": "^1.1.3",
|
||||||
@@ -86,14 +86,14 @@
|
|||||||
"@iconify-json/material-symbols": "^1.2.47",
|
"@iconify-json/material-symbols": "^1.2.47",
|
||||||
"@intlify/eslint-plugin-vue-i18n": "^4.1.0",
|
"@intlify/eslint-plugin-vue-i18n": "^4.1.0",
|
||||||
"@intlify/unplugin-vue-i18n": "^11.0.1",
|
"@intlify/unplugin-vue-i18n": "^11.0.1",
|
||||||
"@playwright/test": "^1.56.1",
|
"@playwright/test": "^1.57.0",
|
||||||
"@prettier/plugin-oxc": "^0.0.5",
|
"@prettier/plugin-oxc": "^0.1.3",
|
||||||
"@primevue/auto-import-resolver": "^4.4.1",
|
"@primevue/auto-import-resolver": "^4.4.1",
|
||||||
"@primevue/metadata": "^4.4.1",
|
"@primevue/metadata": "^4.4.1",
|
||||||
"@stylelint-types/stylelint-order": "^7.0.0",
|
"@stylelint-types/stylelint-order": "^7.0.0",
|
||||||
"@stylelint-types/stylelint-scss": "^6.11.0",
|
"@stylelint-types/stylelint-scss": "^6.11.0",
|
||||||
"@stylistic/eslint-plugin": "^5.6.1",
|
"@stylistic/eslint-plugin": "^5.6.1",
|
||||||
"@tsconfig/node22": "^22.0.5",
|
"@tsconfig/node24": "^24.0.0",
|
||||||
"@types/html-minifier-terser": "^7.0.2",
|
"@types/html-minifier-terser": "^7.0.2",
|
||||||
"@types/jsdom": "^27.0.0",
|
"@types/jsdom": "^27.0.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
@@ -106,11 +106,13 @@
|
|||||||
"@vue/eslint-config-typescript": "^14.6.0",
|
"@vue/eslint-config-typescript": "^14.6.0",
|
||||||
"@vue/test-utils": "^2.4.6",
|
"@vue/test-utils": "^2.4.6",
|
||||||
"@vue/tsconfig": "^0.8.1",
|
"@vue/tsconfig": "^0.8.1",
|
||||||
|
"boxen": "^8.0.1",
|
||||||
"consola": "^3.4.2",
|
"consola": "^3.4.2",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-jsonc": "^2.21.0",
|
"eslint-plugin-jsonc": "^2.21.0",
|
||||||
"eslint-plugin-oxlint": "~1.29.0",
|
"eslint-plugin-oxlint": "~1.32.0",
|
||||||
|
"eslint-plugin-perfectionist": "^5.0.0",
|
||||||
"eslint-plugin-playwright": "^2.3.0",
|
"eslint-plugin-playwright": "^2.3.0",
|
||||||
"eslint-plugin-vue": "~10.6.0",
|
"eslint-plugin-vue": "~10.6.0",
|
||||||
"happy-dom": "^20.0.10",
|
"happy-dom": "^20.0.10",
|
||||||
@@ -118,11 +120,12 @@
|
|||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jsdom": "^27.2.0",
|
"jsdom": "^27.2.0",
|
||||||
"lint-staged": "^16.2.7",
|
"lint-staged": "^16.2.7",
|
||||||
|
"nodemon": "^3.1.11",
|
||||||
"npm-run-all2": "^8.0.4",
|
"npm-run-all2": "^8.0.4",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"oxlint": "~1.29.0",
|
"oxlint": "~1.29.0",
|
||||||
"postcss-html": "^1.8.0",
|
"postcss-html": "^1.8.0",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.7.4",
|
||||||
"rollup": "^4.53.3",
|
"rollup": "^4.53.3",
|
||||||
"sass-embedded": "^1.93.3",
|
"sass-embedded": "^1.93.3",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
@@ -144,7 +147,7 @@
|
|||||||
"unplugin-vue-markdown": "^29.2.0",
|
"unplugin-vue-markdown": "^29.2.0",
|
||||||
"unplugin-vue-router": "^0.19.0",
|
"unplugin-vue-router": "^0.19.0",
|
||||||
"vite": "^7.2.4",
|
"vite": "^7.2.4",
|
||||||
"vite-plugin-checker": "^0.11.0",
|
"vite-plugin-checker": "^0.12.0",
|
||||||
"vite-plugin-fake-server": "^2.2.2",
|
"vite-plugin-fake-server": "^2.2.2",
|
||||||
"vite-plugin-image-optimizer": "^2.0.3",
|
"vite-plugin-image-optimizer": "^2.0.3",
|
||||||
"vite-plugin-vue-devtools": "^8.0.5",
|
"vite-plugin-vue-devtools": "^8.0.5",
|
||||||
@@ -153,14 +156,8 @@
|
|||||||
"vitest": "^4.0.13",
|
"vitest": "^4.0.13",
|
||||||
"vue-component-type-helpers": "^3.1.4",
|
"vue-component-type-helpers": "^3.1.4",
|
||||||
"vue-i18n-extract": "^2.0.7",
|
"vue-i18n-extract": "^2.0.7",
|
||||||
"vue-macros": "3.1.1",
|
"vue-macros": "3.1.2",
|
||||||
"vue-tsc": "^3.1.4",
|
"vue-tsc": "^3.1.8",
|
||||||
"wrangler": "^4.50.0"
|
"wrangler": "^4.50.0"
|
||||||
},
|
}
|
||||||
"overrides": {
|
|
||||||
"vue-tsc": "$vue-tsc"
|
|
||||||
},
|
|
||||||
"workspaces": [
|
|
||||||
"packages/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
3714
pnpm-lock.yaml
generated
3714
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
|||||||
packages:
|
packages:
|
||||||
- 'packages/*'
|
- 'packages/*'
|
||||||
# shamefullyHoist: false # https://pnpm.io/zh/settings#shamefullyhoist
|
# shamefullyHoist: false # https://pnpm.io/zh/settings#shamefullyhoist
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
vue-tsc: $vue-tsc
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
|
|||||||
<Toast style="z-index: 5000" />
|
<Toast style="z-index: 5000" />
|
||||||
|
|
||||||
<AppNaiveUIProvider>
|
<AppNaiveUIProvider>
|
||||||
<router-view v-slot="{ Component }">
|
<RouterView v-slot="{ Component }">
|
||||||
<transition name="fade" mode="out-in">
|
<Transition name="fade" mode="out-in">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</transition>
|
</Transition>
|
||||||
</router-view>
|
</RouterView>
|
||||||
</AppNaiveUIProvider>
|
</AppNaiveUIProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -42,17 +42,17 @@ declare global {
|
|||||||
:theme="appStore.isDark ? darkTheme : null"
|
:theme="appStore.isDark ? darkTheme : null"
|
||||||
abstract
|
abstract
|
||||||
>
|
>
|
||||||
<n-loading-bar-provider>
|
<NLoadingBarProvider>
|
||||||
<n-message-provider>
|
<NMessageProvider>
|
||||||
<n-notification-provider>
|
<NNotificationProvider>
|
||||||
<n-modal-provider>
|
<NModalProvider>
|
||||||
<n-dialog-provider>
|
<NDialogProvider>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<ContextHolder />
|
<ContextHolder />
|
||||||
</n-dialog-provider>
|
</NDialogProvider>
|
||||||
</n-modal-provider>
|
</NModalProvider>
|
||||||
</n-notification-provider>
|
</NNotificationProvider>
|
||||||
</n-message-provider>
|
</NMessageProvider>
|
||||||
</n-loading-bar-provider>
|
</NLoadingBarProvider>
|
||||||
</NConfigProvider>
|
</NConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { createGetRoutes } from '@/plugins/00.router-plugin';
|
|
||||||
import type { MenuInst, MenuOption } from 'naive-ui';
|
import type { MenuInst, MenuOption } from 'naive-ui';
|
||||||
|
import { createGetRoutes } from 'virtual:meta-layouts';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import type { RouteRecordRaw } from 'vue-router';
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink } from 'vue-router';
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function handleSelect(key: string) {
|
|||||||
<NDropdown trigger="hover" placement="bottom-end" :options="options" @select="handleSelect">
|
<NDropdown trigger="hover" placement="bottom-end" :options="options" @select="handleSelect">
|
||||||
<NButton quaternary class="flex items-center gap-1">
|
<NButton quaternary class="flex items-center gap-1">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon-clarity-language-line w-4.5 h-4.5 />
|
<IconClarityLanguageLine w-4.5 h-4.5 />
|
||||||
</template>
|
</template>
|
||||||
<span>{{ languageLabels[locale] }}</span>
|
<span>{{ languageLabels[locale] }}</span>
|
||||||
</NButton>
|
</NButton>
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ const themeLabels: Record<AppThemeMode, string> = {
|
|||||||
{{ themeLabels[appStore.themeMode] }}
|
{{ themeLabels[appStore.themeMode] }}
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton quaternary @click="appStore.cycleTheme()">
|
<NButton quaternary @click="appStore.cycleTheme()">
|
||||||
<icon-line-md-sunny-filled-loop-to-moon-filled-loop-transition
|
<IconLineMdSunnyFilledLoopToMoonFilledLoopTransition
|
||||||
v-if="appStore.themeMode === 'light'"
|
v-if="appStore.themeMode === 'light'"
|
||||||
w-4.5
|
w-4.5
|
||||||
h-4.5
|
h-4.5
|
||||||
/>
|
/>
|
||||||
<icon-line-md-moon-filled-to-sunny-filled-loop-transition
|
<IconLineMdMoonFilledToSunnyFilledLoopTransition
|
||||||
v-else-if="appStore.themeMode === 'dark'"
|
v-else-if="appStore.themeMode === 'dark'"
|
||||||
w-4.5
|
w-4.5
|
||||||
h-4.5
|
h-4.5
|
||||||
/>
|
/>
|
||||||
<icon-line-md-computer v-else w-4.5 h-4.5 />
|
<IconLineMdComputer v-else w-4.5 h-4.5 />
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ function toggleCollapsed() {
|
|||||||
{{ appStore.sidebarCollapsed ? '展开菜单' : '收起菜单' }}
|
{{ appStore.sidebarCollapsed ? '展开菜单' : '收起菜单' }}
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton ref="buttonRef" quaternary @click="toggleCollapsed">
|
<NButton ref="buttonRef" quaternary @click="toggleCollapsed">
|
||||||
<icon-line-md-menu-fold-right v-if="appStore.sidebarCollapsed" w-4.5 h-4.5 />
|
<IconLineMdMenuFoldRight v-if="appStore.sidebarCollapsed" w-4.5 h-4.5 />
|
||||||
<icon-line-md-menu-fold-left v-else w-4.5 h-4.5 />
|
<IconLineMdMenuFoldLeft v-else w-4.5 h-4.5 />
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function handleSelect(key: string) {
|
|||||||
<template>
|
<template>
|
||||||
<NDropdown :options="options" placement="bottom-end" @select="handleSelect">
|
<NDropdown :options="options" placement="bottom-end" @select="handleSelect">
|
||||||
<NButton quaternary circle>
|
<NButton quaternary circle>
|
||||||
<icon-material-symbols-account-circle w-5 h-5 />
|
<IconMaterialSymbolsAccountCircle w-5 h-5 />
|
||||||
</NButton>
|
</NButton>
|
||||||
</NDropdown>
|
</NDropdown>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ const appStore = useAppStore();
|
|||||||
<BaseLayoutSider />
|
<BaseLayoutSider />
|
||||||
</template>
|
</template>
|
||||||
<!-- <div>GlobalContent</div> -->
|
<!-- <div>GlobalContent</div> -->
|
||||||
<router-view v-slot="{ Component }">
|
<RouterView v-slot="{ Component }">
|
||||||
<transition name="fade" mode="out-in">
|
<Transition name="fade" mode="out-in">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</transition>
|
</Transition>
|
||||||
</router-view>
|
</RouterView>
|
||||||
<!-- <div>ThemeDrawer</div> -->
|
<!-- <div>ThemeDrawer</div> -->
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
import messages from '@intlify/unplugin-vue-i18n/messages';
|
import messages from '@intlify/unplugin-vue-i18n/messages';
|
||||||
|
|
||||||
import { createGetRoutes, router } from '@/plugins/00.router-plugin';
|
import { router } from '@/plugins/00.router-plugin';
|
||||||
|
import { createGetRoutes } from 'virtual:meta-layouts';
|
||||||
import { createI18n } from 'vue-i18n';
|
import { createI18n } from 'vue-i18n';
|
||||||
import { START_LOCATION } from 'vue-router';
|
import { START_LOCATION } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
/*eslint sort-keys: "error"*/
|
/*eslint perfectionist/sort-objects: "error"*/
|
||||||
/**
|
/**
|
||||||
* 启用 sort-keys 规则以强制对象键按字母顺序排序
|
* 启用 perfectionist/sort-objects 规则以强制对象键按字母顺序排序
|
||||||
* 原因:
|
* 原因:
|
||||||
* 1. 减少多人协作时的合并冲突
|
* 1. 减少多人协作时的合并冲突
|
||||||
* 2. 保持代码一致性,提高可维护性
|
* 2. 保持代码一致性,提高可维护性
|
||||||
|
*
|
||||||
|
* 运行以下命令自动修复排序:
|
||||||
|
* pnpm exec eslint --fix --no-ignore src/locales-utils/route-messages/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
/*eslint sort-keys: "error"*/
|
/*eslint perfectionist/sort-objects: "error"*/
|
||||||
/**
|
/**
|
||||||
* 启用 sort-keys 规则以强制对象键按字母顺序排序
|
* 启用 perfectionist/sort-objects 规则以强制对象键按字母顺序排序
|
||||||
* 原因:
|
* 原因:
|
||||||
* 1. 减少多人协作时的合并冲突
|
* 1. 减少多人协作时的合并冲突
|
||||||
* 2. 保持代码一致性,提高可维护性
|
* 2. 保持代码一致性,提高可维护性
|
||||||
|
*
|
||||||
|
* 运行以下命令自动修复排序:
|
||||||
|
* pnpm exec eslint --fix --no-ignore src/locales-utils/route-messages/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
definePage({
|
|
||||||
// name: false,
|
|
||||||
meta: {
|
|
||||||
_file: '(layout-group).page.vue',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div>⬇️ b:</div>
|
|
||||||
<RouterView />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
definePage({
|
|
||||||
alias: '/',
|
|
||||||
meta: {
|
|
||||||
_file: '(layout)/a.page.vue',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>a.page.vue</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
definePage({
|
|
||||||
meta: {
|
|
||||||
_file: '(layout)/b.page.vue',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>b.page.vue</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
definePage({
|
|
||||||
meta: {
|
|
||||||
_file: '(ccc)/c.page.vue',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>c.page.vue</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
definePage({
|
|
||||||
meta: {
|
|
||||||
_file: '(home).page.vue',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<n-button @click="$router.push({ name: 'DemosCreate' })">DemosCreate</n-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import TheBaseLayout from '@/layouts/base-layout/the-base-layout.vue';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<TheBaseLayout></TheBaseLayout>
|
|
||||||
</template>
|
|
||||||
@@ -128,7 +128,7 @@ const resetCount = () => {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Naive UI 按钮 -->
|
<!-- Naive UI 按钮 -->
|
||||||
<n-button
|
<NButton
|
||||||
type="warning"
|
type="warning"
|
||||||
size="large"
|
size="large"
|
||||||
block
|
block
|
||||||
@@ -148,7 +148,7 @@ const resetCount = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
点击 +1 (Naive UI)
|
点击 +1 (Naive UI)
|
||||||
</n-button>
|
</NButton>
|
||||||
|
|
||||||
<!-- 重置按钮 -->
|
<!-- 重置按钮 -->
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ definePage({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>create.page.vue</div>
|
<div></div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -9,29 +9,29 @@ function setLocale(newLocale: 'en-US' | 'zh-CN') {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<n-h1>{{ t('page.i18n-demo.title') }}</n-h1>
|
<NH1>{{ t('page.i18n-demo.title') }}</NH1>
|
||||||
|
|
||||||
<n-card :title="t('page.i18n-demo.change-language')">
|
<NCard :title="t('page.i18n-demo.change-language')">
|
||||||
<n-p>
|
<NP>
|
||||||
{{ t('page.i18n-demo.current-language') }}:
|
{{ t('page.i18n-demo.current-language') }}:
|
||||||
<span class="font-bold">{{ locale }}</span>
|
<span class="font-bold">{{ locale }}</span>
|
||||||
</n-p>
|
</NP>
|
||||||
|
|
||||||
<n-p>
|
<NP>
|
||||||
{{ t('page.i18n-demo.hello', { name: 'Kilo' }) }}
|
{{ t('page.i18n-demo.hello', { name: 'Kilo' }) }}
|
||||||
</n-p>
|
</NP>
|
||||||
|
|
||||||
<n-space>
|
<NSpace>
|
||||||
<n-button type="primary" @click="setLocale('en-US')"> English </n-button>
|
<NButton type="primary" @click="setLocale('en-US')"> English </NButton>
|
||||||
<n-button type="success" @click="setLocale('zh-CN')"> 简体中文 </n-button>
|
<NButton type="success" @click="setLocale('zh-CN')"> 简体中文 </NButton>
|
||||||
</n-space>
|
</NSpace>
|
||||||
</n-card>
|
</NCard>
|
||||||
|
|
||||||
<!-- 这里响应式有问题: -->
|
<!-- 这里响应式有问题: -->
|
||||||
<n-p> $route.meta.title: {{ $route.meta.title }} </n-p>
|
<NP> $route.meta.title: {{ $route.meta.title }} </NP>
|
||||||
<!-- 这样才正常 -->
|
<!-- 这样才正常 -->
|
||||||
<n-p>
|
<NP>
|
||||||
routeI18nInstance.global.t($route.name): {{ routeI18nInstance.global.t($route.name) }}
|
routeI18nInstance.global.t($route.name): {{ routeI18nInstance.global.t($route.name) }}
|
||||||
</n-p>
|
</NP>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
7
src/pages/index.page.vue
Normal file
7
src/pages/index.page.vue
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<NButton @click="$router.push({ name: 'DemosCreate' })">DemosCreate</NButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders';
|
import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders';
|
||||||
// import { setupLayouts } from 'virtual:meta-layouts';
|
import { setupLayouts } from 'virtual:meta-layouts';
|
||||||
|
// import { createGetRoutes, setupLayouts } from 'virtual:generated-layouts';
|
||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
import type { Router } from 'vue-router';
|
import type { Router } from 'vue-router';
|
||||||
import { handleHotUpdate, routes } from 'vue-router/auto-routes';
|
import { handleHotUpdate, routes } from 'vue-router/auto-routes';
|
||||||
|
|
||||||
// const setupLayoutsResult = setupLayouts(routes);
|
const setupLayoutsResult = setupLayouts(routes);
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: routes /* ?? setupLayoutsResult */,
|
routes: /* routes ?? */ setupLayoutsResult,
|
||||||
scrollBehavior: (_to, _from, savedPosition) => {
|
scrollBehavior: (_to, _from, savedPosition) => {
|
||||||
return savedPosition ?? { left: 0, top: 0 };
|
return savedPosition ?? { left: 0, top: 0 };
|
||||||
},
|
},
|
||||||
@@ -49,11 +50,6 @@ export function install({ app }: { app: import('vue').App<Element> }) {
|
|||||||
// <<<
|
// <<<
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createGetRoutes(router: Router) {
|
|
||||||
const routes = router.getRoutes();
|
|
||||||
return () => routes.filter((route) => !route.meta.isLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__DEV__) Object.assign(window, { router });
|
if (__DEV__) Object.assign(window, { router });
|
||||||
|
|
||||||
// This will update routes at runtime without reloading the page
|
// This will update routes at runtime without reloading the page
|
||||||
@@ -61,4 +57,4 @@ if (import.meta.hot) {
|
|||||||
handleHotUpdate(router);
|
handleHotUpdate(router);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { router };
|
export { router, setupLayoutsResult };
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"vueCompilerOptions": {
|
"vueCompilerOptions": {
|
||||||
"plugins": [
|
"plugins": [
|
||||||
|
"vue-macros/volar",
|
||||||
"unplugin-vue-router/volar/sfc-route-blocks",
|
"unplugin-vue-router/volar/sfc-route-blocks",
|
||||||
"unplugin-vue-router/volar/sfc-typed-router"
|
"unplugin-vue-router/volar/sfc-typed-router"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "@tsconfig/node22/tsconfig.json",
|
"extends": "@tsconfig/node24/tsconfig.json",
|
||||||
"include": [
|
"include": [
|
||||||
"vite.config.*",
|
"vite.config.*",
|
||||||
"vitest.config.*",
|
"vitest.config.*",
|
||||||
|
|||||||
72
typed-router.d.ts
vendored
72
typed-router.d.ts
vendored
@@ -28,28 +28,6 @@ declare module 'vue-router/auto-routes' {
|
|||||||
'/',
|
'/',
|
||||||
Record<never, never>,
|
Record<never, never>,
|
||||||
Record<never, never>,
|
Record<never, never>,
|
||||||
| 'RootA'
|
|
||||||
| 'RootB'
|
|
||||||
>,
|
|
||||||
'RootA': RouteRecordInfo<
|
|
||||||
'RootA',
|
|
||||||
'/a',
|
|
||||||
Record<never, never>,
|
|
||||||
Record<never, never>,
|
|
||||||
| never
|
|
||||||
>,
|
|
||||||
'RootB': RouteRecordInfo<
|
|
||||||
'RootB',
|
|
||||||
'/b',
|
|
||||||
Record<never, never>,
|
|
||||||
Record<never, never>,
|
|
||||||
| never
|
|
||||||
>,
|
|
||||||
'RootC': RouteRecordInfo<
|
|
||||||
'RootC',
|
|
||||||
'/c',
|
|
||||||
Record<never, never>,
|
|
||||||
Record<never, never>,
|
|
||||||
| never
|
| never
|
||||||
>,
|
>,
|
||||||
'$Path': RouteRecordInfo<
|
'$Path': RouteRecordInfo<
|
||||||
@@ -59,20 +37,6 @@ declare module 'vue-router/auto-routes' {
|
|||||||
{ path: ParamValue<false> },
|
{ path: ParamValue<false> },
|
||||||
| never
|
| never
|
||||||
>,
|
>,
|
||||||
'DemosParent': RouteRecordInfo<
|
|
||||||
'DemosParent',
|
|
||||||
'/demos',
|
|
||||||
Record<never, never>,
|
|
||||||
Record<never, never>,
|
|
||||||
| 'Demos'
|
|
||||||
| 'DemosApiDemo'
|
|
||||||
| 'DemosCounterDemo'
|
|
||||||
| 'DemosCreate'
|
|
||||||
| 'DemosI18nDemo'
|
|
||||||
| 'DemosNaiveUiDemo'
|
|
||||||
| 'DemosPrimevueDemo'
|
|
||||||
| 'DemosWebsocketDemo'
|
|
||||||
>,
|
|
||||||
'Demos': RouteRecordInfo<
|
'Demos': RouteRecordInfo<
|
||||||
'Demos',
|
'Demos',
|
||||||
'/demos',
|
'/demos',
|
||||||
@@ -156,29 +120,9 @@ declare module 'vue-router/auto-routes' {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export interface _RouteFileInfoMap {
|
export interface _RouteFileInfoMap {
|
||||||
'src/pages-with-layout/(layout-group).page.vue': {
|
'src/pages/index.page.vue': {
|
||||||
routes:
|
routes:
|
||||||
| 'Root'
|
| 'Root'
|
||||||
| 'RootA'
|
|
||||||
| 'RootB'
|
|
||||||
views:
|
|
||||||
| 'default'
|
|
||||||
}
|
|
||||||
'src/pages-with-layout/(layout-group)/a.page.vue': {
|
|
||||||
routes:
|
|
||||||
| 'RootA'
|
|
||||||
views:
|
|
||||||
| never
|
|
||||||
}
|
|
||||||
'src/pages-with-layout/(layout-group)/b.page.vue': {
|
|
||||||
routes:
|
|
||||||
| 'RootB'
|
|
||||||
views:
|
|
||||||
| never
|
|
||||||
}
|
|
||||||
'src/pages/(ccc)/c.page.vue': {
|
|
||||||
routes:
|
|
||||||
| 'RootC'
|
|
||||||
views:
|
views:
|
||||||
| never
|
| never
|
||||||
}
|
}
|
||||||
@@ -188,20 +132,6 @@ declare module 'vue-router/auto-routes' {
|
|||||||
views:
|
views:
|
||||||
| never
|
| never
|
||||||
}
|
}
|
||||||
'src/pages/demos.page.vue': {
|
|
||||||
routes:
|
|
||||||
| 'Demos'
|
|
||||||
| 'DemosApiDemo'
|
|
||||||
| 'DemosCounterDemo'
|
|
||||||
| 'DemosCreate'
|
|
||||||
| 'DemosI18nDemo'
|
|
||||||
| 'DemosNaiveUiDemo'
|
|
||||||
| 'DemosParent'
|
|
||||||
| 'DemosPrimevueDemo'
|
|
||||||
| 'DemosWebsocketDemo'
|
|
||||||
views:
|
|
||||||
| 'default'
|
|
||||||
}
|
|
||||||
'src/pages/demos/index.page.vue': {
|
'src/pages/demos/index.page.vue': {
|
||||||
routes:
|
routes:
|
||||||
| 'Demos'
|
| 'Demos'
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||||
import consola from 'consola';
|
|
||||||
import { getPascalCaseRouteName } from 'unplugin-vue-router';
|
|
||||||
import vueRouter from 'unplugin-vue-router/vite';
|
import vueRouter from 'unplugin-vue-router/vite';
|
||||||
import type { PluginOption } from 'vite';
|
|
||||||
import VueMacros from 'vue-macros/vite';
|
import VueMacros from 'vue-macros/vite';
|
||||||
|
|
||||||
export default [
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
VueMacros({
|
|
||||||
plugins: {
|
|
||||||
vue: vue({ include: [/\.vue$/, /\.md$/] }),
|
|
||||||
vueJsx: vueJsx(),
|
|
||||||
|
|
||||||
// https://uvr.esm.is/guide/configuration.html
|
export const loadPlugin: LoadPluginFunction = async (_pluginLoadOptions) => {
|
||||||
// https://github.com/posva/unplugin-vue-router
|
return [
|
||||||
// ⚠️ Vue must be placed after VueRouter()
|
VueMacros({
|
||||||
vueRouter: vueRouter({
|
plugins: {
|
||||||
exclude: ['**/__*', '**/__*/**/*'],
|
vue: vue({ include: [/\.vue$/, /\.md$/] }),
|
||||||
extensions: ['.page.vue', '.page.md'],
|
vueJsx: vueJsx(),
|
||||||
getRouteName: (routeNode) => getPascalCaseRouteName(routeNode),
|
|
||||||
logs: true,
|
// https://uvr.esm.is/guide/configuration.html
|
||||||
routesFolder: ['src/pages', 'src/pages-with-layout'],
|
// https://github.com/posva/unplugin-vue-router
|
||||||
extendRoute(route) {
|
// ⚠️ Vue must be placed after VueRouter()
|
||||||
consola.info(`route.name :>> `, route.name);
|
vueRouter: vueRouter({
|
||||||
console.debug(`route.meta :>> `, route.meta);
|
routesFolder: 'src/pages',
|
||||||
console.debug(`route.path :>> `, route.path);
|
extensions: ['.page.vue', '.page.md'],
|
||||||
},
|
exclude: ['**/__*', '**/__*/**/*'],
|
||||||
}),
|
getRouteName: (await import('unplugin-vue-router')).getPascalCaseRouteName,
|
||||||
},
|
beforeWriteFiles(rootRoute) {
|
||||||
}),
|
for (/* 深度优先遍历 */ const route of rootRoute.traverseDFS()) {
|
||||||
] satisfies PluginOption;
|
route.addToMeta({ _: route.fullPath });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
logs: !true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import type { PluginOption } from 'vite';
|
|
||||||
import UnoCSS from 'unocss/vite';
|
import UnoCSS from 'unocss/vite';
|
||||||
|
|
||||||
export default [
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
// https://github.com/antfu/unocss
|
|
||||||
// see uno.config.ts for config
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
UnoCSS({
|
return [
|
||||||
checkImport: true,
|
// https://github.com/antfu/unocss
|
||||||
}),
|
// see uno.config.ts for config
|
||||||
] satisfies PluginOption;
|
UnoCSS({
|
||||||
|
checkImport: true,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
||||||
import type { PluginOption } from 'vite';
|
|
||||||
|
|
||||||
export default [
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
|
|
||||||
VueI18nPlugin({
|
|
||||||
/* options */
|
|
||||||
// locale messages resource pre-compile option
|
|
||||||
include: ['src/locales/**'],
|
|
||||||
|
|
||||||
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#transformi18nblock
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
// transformI18nBlock(src) {
|
return [
|
||||||
// console.debug(`src :>> `, src);
|
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
|
||||||
// console.debug(`typeof src :>> `, typeof src);
|
VueI18nPlugin({
|
||||||
// return src as string;
|
/* options */
|
||||||
// },
|
// locale messages resource pre-compile option
|
||||||
}),
|
include: ['src/locales/**'],
|
||||||
] satisfies PluginOption;
|
|
||||||
|
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#transformi18nblock
|
||||||
|
// transformI18nBlock(src) {
|
||||||
|
// console.debug(`src :>> `, src);
|
||||||
|
// console.debug(`typeof src :>> `, typeof src);
|
||||||
|
// return src as string;
|
||||||
|
// },
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import type { PluginOption } from 'vite';
|
|
||||||
import Markdown from 'unplugin-vue-markdown/vite';
|
import Markdown from 'unplugin-vue-markdown/vite';
|
||||||
|
|
||||||
export default [
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
// https://github.com/unplugin/unplugin-vue-markdown
|
|
||||||
Markdown({
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
headEnabled: true,
|
return [
|
||||||
}),
|
// https://github.com/unplugin/unplugin-vue-markdown
|
||||||
] satisfies PluginOption;
|
Markdown({
|
||||||
|
headEnabled: true,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import type { PluginOption } from 'vite';
|
|
||||||
import MetaLayouts from 'vite-plugin-vue-meta-layouts';
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// https://github.com/dishait/vite-plugin-vue-meta-layouts
|
|
||||||
MetaLayouts({
|
|
||||||
target: 'src/layouts',
|
|
||||||
excludes: ['**/!(the-)*.vue'], // 排除非 the- 开头的文件。
|
|
||||||
metaName: 'layout',
|
|
||||||
// defaultLayout: 'sakai-vue/AppLayout',
|
|
||||||
// defaultLayout: 'naive-ui/AppLayout',
|
|
||||||
defaultLayout: 'base-layout/the-base-layout',
|
|
||||||
// !⬇️: 当设置为 `sync` 时,注意`import 'virtual:uno.css'`的顺序问题。
|
|
||||||
// importMode: 'sync', // 默认为自动处理,SSG 时为 sync,非 SSG 时为 async
|
|
||||||
skipTopLevelRouteLayout: true, // 打开修复 https://github.com/JohnCampionJr/vite-plugin-vue-layouts/issues/134,默认为 false 关闭
|
|
||||||
}),
|
|
||||||
] satisfies PluginOption;
|
|
||||||
20
vite-plugins/01.vite-plugin-vue-meta-layouts.ts
Normal file
20
vite-plugins/01.vite-plugin-vue-meta-layouts.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import MetaLayouts from 'vite-plugin-vue-meta-layouts';
|
||||||
|
|
||||||
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
|
|
||||||
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
|
return [
|
||||||
|
// https://github.com/dishait/vite-plugin-vue-meta-layouts
|
||||||
|
MetaLayouts({
|
||||||
|
target: 'src/layouts',
|
||||||
|
excludes: ['**/!(the-)*.vue'], // 排除非 the- 开头的文件。
|
||||||
|
metaName: 'layout',
|
||||||
|
// defaultLayout: 'sakai-vue/AppLayout',
|
||||||
|
// defaultLayout: 'naive-ui/AppLayout',
|
||||||
|
defaultLayout: 'base-layout/the-base-layout',
|
||||||
|
// !⬇️: 当设置为 `sync` 时,注意`import 'virtual:uno.css'`的顺序问题。
|
||||||
|
// importMode: 'sync', // 默认为自动处理,SSG 时为 sync,非 SSG 时为 async
|
||||||
|
skipTopLevelRouteLayout: true, // 打开修复 https://github.com/JohnCampionJr/vite-plugin-vue-layouts/issues/134,默认为 false 关闭
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
@@ -9,7 +9,6 @@ import Icons from 'unplugin-icons/vite';
|
|||||||
import Components from 'unplugin-vue-components/vite';
|
import Components from 'unplugin-vue-components/vite';
|
||||||
import { VueRouterAutoImports } from 'unplugin-vue-router';
|
import { VueRouterAutoImports } from 'unplugin-vue-router';
|
||||||
import { createUtils4uAutoImports } from 'utils4u/auto-imports';
|
import { createUtils4uAutoImports } from 'utils4u/auto-imports';
|
||||||
import type { ConfigEnv, PluginOption } from 'vite';
|
|
||||||
|
|
||||||
// >>>>>
|
// >>>>>
|
||||||
// eslint-disable-next-line import/no-duplicates
|
// eslint-disable-next-line import/no-duplicates
|
||||||
@@ -26,6 +25,8 @@ import { PrimeVueResolver } from '@primevue/auto-import-resolver';
|
|||||||
import { VantResolver } from '@vant/auto-import-resolver';
|
import { VantResolver } from '@vant/auto-import-resolver';
|
||||||
// <<<<<
|
// <<<<<
|
||||||
|
|
||||||
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
|
|
||||||
function _getNaiveUiComponentNames() {
|
function _getNaiveUiComponentNames() {
|
||||||
// [dtsTsx](https://github.com/unplugin/unplugin-vue-components/pull/673/files/84e80738885cfe11298f41f070cda94a7a779276)
|
// [dtsTsx](https://github.com/unplugin/unplugin-vue-components/pull/673/files/84e80738885cfe11298f41f070cda94a7a779276)
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ function _getNaiveUiComponentNames() {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
return [
|
return [
|
||||||
// https://github.com/antfu/unplugin-auto-import
|
// https://github.com/antfu/unplugin-auto-import
|
||||||
AutoImport({
|
AutoImport({
|
||||||
@@ -76,7 +77,7 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
|||||||
createUtils4uAutoImports(['primevue']),
|
createUtils4uAutoImports(['primevue']),
|
||||||
{
|
{
|
||||||
'consola/browser': ['consola'],
|
'consola/browser': ['consola'],
|
||||||
'vue-router/auto': ['useLink'],
|
'unplugin-vue-router/data-loaders/basic': ['defineBasicLoader'],
|
||||||
'naive-ui': [
|
'naive-ui': [
|
||||||
'useModal',
|
'useModal',
|
||||||
'useDialog',
|
'useDialog',
|
||||||
@@ -141,4 +142,4 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { minify as minifyHtml } from 'html-minifier-terser';
|
import { minify as minifyHtml } from 'html-minifier-terser';
|
||||||
import { loadEnv } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
import type { ConfigEnv, PluginOption } from 'vite';
|
|
||||||
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
|
|
||||||
function IndexHtmlPlugin(): PluginOption {
|
function IndexHtmlPlugin(): PluginOption {
|
||||||
return {
|
return {
|
||||||
@@ -91,8 +92,14 @@ function ___(): PluginOption {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
export const loadPlugin: LoadPluginFunction = (pluginLoadOptions) => {
|
||||||
|
const { mode, env } = pluginLoadOptions;
|
||||||
// return [___()];
|
// return [___()];
|
||||||
const env = loadEnv(_configEnv.mode, process.cwd());
|
if (mode !== 'production') {
|
||||||
if (env.VITE_BUILD_MINIFY === 'true') return IndexHtmlPlugin();
|
return { plugins: [], message: '仅在生产模式下启用' };
|
||||||
}
|
}
|
||||||
|
if (env.VITE_BUILD_MINIFY !== 'true') {
|
||||||
|
return { plugins: [], message: `已通过环境变量禁用: VITE_BUILD_MINIFY=${env.VITE_BUILD_MINIFY}` };
|
||||||
|
}
|
||||||
|
return IndexHtmlPlugin();
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { consola } from 'consola';
|
|
||||||
import type { ConfigEnv, PluginOption } from 'vite';
|
|
||||||
import { vitePluginFakeServer } from 'vite-plugin-fake-server';
|
import { vitePluginFakeServer } from 'vite-plugin-fake-server';
|
||||||
// https://github.com/condorheroblog/vite-plugin-fake-server?tab=readme-ov-file#usage
|
|
||||||
|
|
||||||
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
if (_configEnv.mode !== 'development') {
|
|
||||||
consola.info('fake server plugin is disabled in non-development mode.');
|
// https://github.com/condorheroblog/vite-plugin-fake-server?tab=readme-ov-file#usage
|
||||||
return [];
|
export const loadPlugin: LoadPluginFunction = (pluginLoadOptions) => {
|
||||||
|
const { mode } = pluginLoadOptions;
|
||||||
|
if (mode !== 'development') {
|
||||||
|
return { plugins: [], message: '仅在开发模式下启用' };
|
||||||
}
|
}
|
||||||
return vitePluginFakeServer({
|
return vitePluginFakeServer({
|
||||||
basename: 'fake-api',
|
basename: 'fake-api',
|
||||||
enableProd: true,
|
enableProd: true,
|
||||||
include: 'fake',
|
include: 'fake',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import type { PluginOption } from 'vite';
|
|
||||||
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
|
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
|
||||||
|
|
||||||
export default [
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
// https://github.com/FatehAK/vite-plugin-image-optimizer?tab=readme-ov-file#default-configuration
|
|
||||||
ViteImageOptimizer({
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
/* pass your config */
|
return [
|
||||||
}),
|
// https://github.com/FatehAK/vite-plugin-image-optimizer?tab=readme-ov-file#default-configuration
|
||||||
] satisfies PluginOption;
|
ViteImageOptimizer({
|
||||||
|
/* pass your config */
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
import consola from 'consola';
|
|
||||||
import type { ConfigEnv, PluginOption } from 'vite';
|
|
||||||
import vueDevTools from 'vite-plugin-vue-devtools';
|
import vueDevTools from 'vite-plugin-vue-devtools';
|
||||||
|
|
||||||
export function loadPlugin(configEnv: ConfigEnv): PluginOption {
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
if (configEnv.mode !== 'development') {
|
|
||||||
consola.info('vue-devtools 插件仅在开发模式下使用。');
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
return [];
|
const { mode } = _pluginLoadOptions;
|
||||||
|
if (mode !== 'development') {
|
||||||
|
return { plugins: [], message: '仅在开发模式下启用' };
|
||||||
}
|
}
|
||||||
|
|
||||||
let launchEditor = 'code';
|
let launchEditor = 'code';
|
||||||
|
let message: string | undefined;
|
||||||
|
|
||||||
if (process.env.TERM_PROGRAM_VERSION?.toLowerCase()?.includes('insider')) {
|
if (process.env.TERM_PROGRAM_VERSION?.toLowerCase()?.includes('insider')) {
|
||||||
consola.info('检测到 VSCode Insiders 环境。');
|
|
||||||
launchEditor = 'code-insiders';
|
launchEditor = 'code-insiders';
|
||||||
|
message = '检测到 VSCode Insiders 环境';
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return {
|
||||||
vueDevTools({
|
plugins: [
|
||||||
launchEditor: launchEditor,
|
vueDevTools({
|
||||||
}),
|
launchEditor: launchEditor,
|
||||||
];
|
}),
|
||||||
}
|
],
|
||||||
|
message,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { cloudflare } from '@cloudflare/vite-plugin';
|
import { cloudflare } from '@cloudflare/vite-plugin';
|
||||||
import { loadEnv } from 'vite';
|
|
||||||
import type {ConfigEnv, PluginOption} from 'vite';
|
|
||||||
|
|
||||||
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
const env = loadEnv(_configEnv.mode, process.cwd());
|
|
||||||
if (_configEnv.mode === 'test') {
|
export const loadPlugin: LoadPluginFunction = (pluginLoadOptions) => {
|
||||||
console.log('cloudflare plugin disabled in test mode');
|
const { mode, env } = pluginLoadOptions;
|
||||||
return [];
|
if (mode === 'test') {
|
||||||
|
return { plugins: [], message: '在测试模式下禁用' };
|
||||||
}
|
}
|
||||||
if (env.VITE_CLOUDFLARE_SERVER_ENABLED !== 'true') {
|
if (env.VITE_CLOUDFLARE_SERVER_ENABLED !== 'true') {
|
||||||
console.log('cloudflare plugin disabled by env');
|
return {
|
||||||
return [];
|
plugins: [],
|
||||||
|
message: `已通过环境变量禁用: VITE_CLOUDFLARE_SERVER_ENABLED=${env.VITE_CLOUDFLARE_SERVER_ENABLED}`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return [cloudflare()];
|
return [cloudflare()];
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,30 +1,47 @@
|
|||||||
|
import boxen from 'boxen';
|
||||||
|
import consola from 'consola';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { pathToFileURL } from 'node:url';
|
import { pathToFileURL } from 'node:url';
|
||||||
|
|
||||||
import consola from 'consola';
|
|
||||||
import { glob } from 'tinyglobby';
|
import { glob } from 'tinyglobby';
|
||||||
import type { ConfigEnv, PluginOption } from 'vite';
|
import type { ConfigEnv, PluginOption } from 'vite';
|
||||||
|
import { loadEnv } from 'vite';
|
||||||
|
|
||||||
|
export type LoadPluginFunction = (
|
||||||
|
configEnv: ConfigEnv & {
|
||||||
|
env: Record<string, string>;
|
||||||
|
},
|
||||||
|
) => PluginOption | LoadPluginResult;
|
||||||
|
export interface LoadPluginResult {
|
||||||
|
plugins: PluginOption;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
type LoadPluginFunction = (configEnv: ConfigEnv) => PluginOption;
|
|
||||||
export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]> {
|
export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]> {
|
||||||
const plugins: PluginOption[] = [];
|
const plugins: PluginOption[] = [];
|
||||||
|
|
||||||
consola.start('开始加载 Vite 插件...');
|
const cwd = path.resolve(import.meta.dirname);
|
||||||
|
|
||||||
const pluginEntries = await glob('**/*.ts', {
|
const pluginEntries = await glob('**/*.ts', {
|
||||||
absolute: true,
|
absolute: true,
|
||||||
cwd: path.resolve(import.meta.dirname),
|
cwd,
|
||||||
ignore: [
|
ignore: [
|
||||||
'**/*.d.ts',
|
'**/*.d.ts',
|
||||||
'**/*.disabled.ts',
|
'**/*.disabled.ts',
|
||||||
'**/*.x.ts',
|
|
||||||
'**/*.X.ts',
|
|
||||||
'**/x-*.ts', // 禁用以 x- 开头的插件文件
|
'**/x-*.ts', // 禁用以 x- 开头的插件文件
|
||||||
|
'**/*-x.ts', // 禁用以 -x 结尾的插件文件
|
||||||
|
'**/*-X.ts', // 禁用以 -X 结尾的插件文件
|
||||||
'**/_*',
|
'**/_*',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
consola.info(`找到 ${pluginEntries.length} 个插件文件`);
|
const relativeCwd = path.relative(process.cwd(), cwd);
|
||||||
|
console.time('加载插件');
|
||||||
|
consola.log(
|
||||||
|
boxen(`正在加载 Vite 插件... (./${relativeCwd})`, {
|
||||||
|
borderStyle: 'classic',
|
||||||
|
borderColor: 'cyan',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// 计算最长的文件名长度,用于对齐输出
|
// 计算最长的文件名长度,用于对齐输出
|
||||||
const maxNameLength = Math.max(...pluginEntries.map((entry) => path.basename(entry).length));
|
const maxNameLength = Math.max(...pluginEntries.map((entry) => path.basename(entry).length));
|
||||||
@@ -35,36 +52,39 @@ export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]>
|
|||||||
const imported = await import(pathToFileURL(entry).href);
|
const imported = await import(pathToFileURL(entry).href);
|
||||||
|
|
||||||
const loadPlugin = imported.loadPlugin as LoadPluginFunction | undefined;
|
const loadPlugin = imported.loadPlugin as LoadPluginFunction | undefined;
|
||||||
let plugin: PluginOption | undefined;
|
|
||||||
let loadMethod = '';
|
|
||||||
|
|
||||||
// 优先使用 loadPlugin 函数(接收 configEnv 参数)
|
if (!loadPlugin || typeof loadPlugin !== 'function') {
|
||||||
if (loadPlugin && typeof loadPlugin === 'function') {
|
consola.warn(`插件未导出 loadPlugin 函数: ${paddedName}`);
|
||||||
plugin = loadPlugin(configEnv);
|
continue;
|
||||||
loadMethod = 'loadPlugin';
|
|
||||||
} else if (imported.default) {
|
|
||||||
plugin = imported.default;
|
|
||||||
loadMethod = 'default';
|
|
||||||
} else {
|
|
||||||
consola.warn(`插件未导出有效内容: ${paddedName}`);
|
|
||||||
continue; // 跳过无效插件
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin) {
|
const env = loadEnv(configEnv.mode, process.cwd());
|
||||||
const pluginArray = Array.isArray(plugin) ? plugin : [plugin];
|
const result = loadPlugin({ ...configEnv, env });
|
||||||
const validPlugins = pluginArray.filter(Boolean); // 过滤掉 null/undefined
|
|
||||||
const pluginCount = validPlugins.length;
|
|
||||||
|
|
||||||
if (pluginCount > 0) {
|
// 判断是否是 LoadPluginResult 对象
|
||||||
plugins.push(...validPlugins);
|
const isResultObject = (val: unknown): val is LoadPluginResult =>
|
||||||
consola.success(`${paddedName} → ${pluginCount} 个实例 (${loadMethod})`);
|
typeof val === 'object' && val !== null && 'plugins' in val;
|
||||||
} else {
|
|
||||||
consola.info(`${paddedName} 返回了空数组或无效值`);
|
const plugin = isResultObject(result) ? result.plugins : result;
|
||||||
}
|
const message = isResultObject(result) ? result.message : undefined;
|
||||||
|
|
||||||
|
const pluginArray = Array.isArray(plugin) ? plugin : [plugin];
|
||||||
|
const validPlugins = pluginArray.filter(Boolean);
|
||||||
|
const pluginCount = validPlugins.length;
|
||||||
|
|
||||||
|
if (pluginCount > 0) {
|
||||||
|
plugins.push(...validPlugins);
|
||||||
|
const suffix = message ? ` (${message})` : '';
|
||||||
|
consola.info(`${paddedName} → ${pluginCount} 个实例${suffix}`);
|
||||||
|
} else if (message) {
|
||||||
|
consola.info(`${paddedName} → ${message}`);
|
||||||
|
} else {
|
||||||
|
consola.info(`${paddedName} 返回了空数组或无效值`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
consola.success(`✅ 总共加载了 ${plugins.length} 个插件实例`);
|
consola.success(`共 ${pluginEntries.length} 个插件文件,已加载 ${plugins.length} 个实例`);
|
||||||
|
console.timeEnd('加载插件');
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import type { ConfigEnv, PluginOption } from 'vite';
|
import type { LoadPluginFunction } from './_loadPlugins';
|
||||||
import { loadEnv } from 'vite';
|
|
||||||
|
|
||||||
export default [
|
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
|
||||||
// ...
|
const env = _pluginLoadOptions.env;
|
||||||
] satisfies PluginOption;
|
|
||||||
|
|
||||||
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
|
// 示例:根据环境变量禁用插件并返回消息
|
||||||
const env = loadEnv(_configEnv.mode, process.cwd());
|
if (env.VITE_DEMO_ENABLED !== 'true') {
|
||||||
console.debug(`env :>> `, env);
|
return {
|
||||||
// ...
|
plugins: [],
|
||||||
return undefined;
|
message: `已通过环境变量禁用: VITE_DEMO_ENABLED=${env.VITE_DEMO_ENABLED}`,
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正常返回插件
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import type { PluginOption } from 'vite';
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// // 检查是否在VS Code终端中运行
|
|
||||||
// if (process.env.TERM_PROGRAM === 'vscode' || process.env.VSCODE_PID) {
|
|
||||||
// // plugins.push(
|
|
||||||
// // // 构建后自动将dist目录打包成zip文件
|
|
||||||
// // viteArchiverPlugin({
|
|
||||||
// // addTimestamp: false, // 是否添加时间戳到输出文件名
|
|
||||||
// // format: 'zip', // 输出的压缩文件格式
|
|
||||||
// // outputDir: '', // 输出目录,默认为项目根目录
|
|
||||||
// // outputFileName: 'dist', // 输出的zip文件名(不含扩展名)
|
|
||||||
// // sourceDir: 'dist', // 要打包的源目录
|
|
||||||
// // }),
|
|
||||||
// // )
|
|
||||||
// }
|
|
||||||
] satisfies PluginOption;
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ManualChunkMeta, PreRenderedAsset, RollupOptions } from 'rollup';
|
import type { /* ManualChunkMeta, PreRenderedAsset, */ RollupOptions } from 'rollup';
|
||||||
|
|
||||||
import path from 'node:path';
|
// import path from 'node:path';
|
||||||
|
|
||||||
// https://www.npmjs.com/package/utils4u/v/2.19.2?activeTab=code
|
// https://www.npmjs.com/package/utils4u/v/2.19.2?activeTab=code
|
||||||
|
|
||||||
@@ -12,106 +12,95 @@ export const viteConfigRollupOptions: RollupOptions = {
|
|||||||
if (warning.code === 'EVAL' && warning.id?.includes('node_modules/protobufjs')) return;
|
if (warning.code === 'EVAL' && warning.id?.includes('node_modules/protobufjs')) return;
|
||||||
warn(warning);
|
warn(warning);
|
||||||
}, */
|
}, */
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
// Keep hashed file names predictable across entry, chunk, and asset outputs.
|
// 如果一个 chunk 小于 10KB,Rollup 会尝试将它合并到其他 chunk 中。这样可以避免产生大量碎片文件
|
||||||
entryFileNames: 'entry/[name].[hash].js', // 默认: "[name].js"
|
experimentalMinChunkSize: 10 * 1024,
|
||||||
chunkFileNames: 'chunk/[name].[hash].js', // 默认: "[name]-[hash].js"
|
// // Keep hashed file names predictable across entry, chunk, and asset outputs.
|
||||||
// assetFileNames:'', // 默认: "assets/[name]-[hash][extname]"
|
// entryFileNames: 'entry/[name].[hash].js', // 默认: "[name].js"
|
||||||
// https://cn.rollupjs.org/configuration-options/#output-assetfilenames
|
// chunkFileNames: 'chunk/[name].[hash].js', // 默认: "[name]-[hash].js"
|
||||||
assetFileNames(chunkInfo: PreRenderedAsset) {
|
// // assetFileNames:'', // 默认: "assets/[name]-[hash][extname]"
|
||||||
const names = [...new Set(chunkInfo.names)];
|
// // https://cn.rollupjs.org/configuration-options/#output-assetfilenames
|
||||||
|
// assetFileNames(chunkInfo: PreRenderedAsset) {
|
||||||
if (names.length !== 1) {
|
// const names = [...new Set(chunkInfo.names)];
|
||||||
console.error('Multiple names for asset:', chunkInfo);
|
// if (names.length !== 1) {
|
||||||
process.exit(1);
|
// console.error('Multiple names for asset:', chunkInfo);
|
||||||
}
|
// process.exit(1);
|
||||||
|
// }
|
||||||
const assetName = names[0];
|
// const assetName = names[0];
|
||||||
const ext = assetName.split('.').pop()?.toLowerCase();
|
// const ext = assetName.split('.').pop()?.toLowerCase();
|
||||||
if (ext && /png|jpe?g|gif|svg|webp|avif/.test(ext)) {
|
// if (ext && /png|jpe?g|gif|svg|webp|avif/.test(ext)) {
|
||||||
return 'chunks/images/[name].[hash][extname]';
|
// return 'chunks/images/[name].[hash][extname]';
|
||||||
}
|
// }
|
||||||
if (ext && /woff2?|ttf|otf/.test(ext)) {
|
// if (ext && /woff2?|ttf|otf/.test(ext)) {
|
||||||
return 'chunks/fonts/[name].[hash][extname]';
|
// return 'chunks/fonts/[name].[hash][extname]';
|
||||||
}
|
// }
|
||||||
if (ext === 'css') {
|
// if (ext === 'css') {
|
||||||
return 'chunks/css/[name].[hash][extname]';
|
// return 'chunks/css/[name].[hash][extname]';
|
||||||
}
|
// }
|
||||||
return '_chunks/[name].[hash][extname]';
|
// return '_chunks/[name].[hash][extname]';
|
||||||
},
|
// },
|
||||||
|
// manualChunks: (id: string, _meta: ManualChunkMeta) => {
|
||||||
manualChunks: (id: string, _meta: ManualChunkMeta) => {
|
// // https://github.com/unocss/unocss/issues/4917
|
||||||
// https://github.com/unocss/unocss/issues/4917
|
// // if (['/src/layouts'].some((prefix) => id.includes(prefix))) {
|
||||||
// if (['/src/layouts'].some((prefix) => id.includes(prefix))) {
|
// // const url = new URL(id, 'file://');
|
||||||
// const url = new URL(id, 'file://');
|
// // if (!url.search /* ?vue&type=script&setup=true&lang.ts */) {
|
||||||
// if (!url.search /* ?vue&type=script&setup=true&lang.ts */) {
|
// // return 'layouts';
|
||||||
// return 'layouts';
|
// // }
|
||||||
// }
|
// // }
|
||||||
// }
|
// if (id.includes('meta-layouts')) {
|
||||||
|
// // console.debug(`id :>> `, id); // id :>> virtual:meta-layouts
|
||||||
if (id.includes('meta-layouts')) {
|
// // 这里很奇怪,打印 id 是`virtual:meta-layouts`,但是 `'virtual:meta-layouts' === id` 却是 false
|
||||||
// console.debug(`id :>> `, id); // id :>> virtual:meta-layouts
|
// return 'lib-meta-layouts';
|
||||||
// 这里很奇怪,打印 id 是`virtual:meta-layouts`,但是 `'virtual:meta-layouts' === id` 却是 false
|
// }
|
||||||
return 'lib-meta-layouts';
|
// if (id.includes('index.page.vue')) {
|
||||||
}
|
// const url = new URL(id, 'file://');
|
||||||
|
// if (!url.search /* ?vue&type=script&setup=true&lang.ts */) {
|
||||||
if (id.includes('index.page.vue')) {
|
// const parentDir = path.basename(path.dirname(id));
|
||||||
const url = new URL(id, 'file://');
|
// return `${parentDir}-index.page`;
|
||||||
if (!url.search /* ?vue&type=script&setup=true&lang.ts */) {
|
// }
|
||||||
const parentDir = path.basename(path.dirname(id));
|
// }
|
||||||
return `${parentDir}-index.page`;
|
// if (!id.includes('node_modules')) return;
|
||||||
}
|
// // 处理 pnpm 的特殊路径结构
|
||||||
}
|
// let packageName;
|
||||||
|
// if (id.includes('.pnpm')) {
|
||||||
if (!id.includes('node_modules')) return;
|
// // pnpm 路径: .pnpm/naive-ui@2.43.1_vue@3.5.22/node_modules/naive-ui/...
|
||||||
// 处理 pnpm 的特殊路径结构
|
// const pnpmMatch = id.match(/\.pnpm\/(.+?)@/);
|
||||||
let packageName;
|
// if (pnpmMatch) {
|
||||||
if (id.includes('.pnpm')) {
|
// packageName = pnpmMatch[1];
|
||||||
// pnpm 路径: .pnpm/naive-ui@2.43.1_vue@3.5.22/node_modules/naive-ui/...
|
// }
|
||||||
const pnpmMatch = id.match(/\.pnpm\/(.+?)@/);
|
// } else {
|
||||||
if (pnpmMatch) {
|
// // 普通路径: node_modules/lodash/...
|
||||||
packageName = pnpmMatch[1];
|
// const normalMatch = id.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)\//);
|
||||||
}
|
// if (normalMatch) {
|
||||||
} else {
|
// packageName = normalMatch[1];
|
||||||
// 普通路径: node_modules/lodash/...
|
// }
|
||||||
const normalMatch = id.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)\//);
|
// }
|
||||||
if (normalMatch) {
|
// if (packageName) {
|
||||||
packageName = normalMatch[1];
|
// if (['highlight.js'].includes(packageName)) {
|
||||||
}
|
// return 'lib-hljs';
|
||||||
}
|
// }
|
||||||
|
// // 根据包名分组
|
||||||
if (packageName) {
|
// if (['consola', 'lodash', '@juggle+resize-observer', 'vueuc'].includes(packageName)) {
|
||||||
if (['highlight.js'].includes(packageName)) {
|
// return 'lib-vendor';
|
||||||
return 'lib-hljs';
|
// }
|
||||||
}
|
// // // 拆了有问题
|
||||||
|
// // if (['naive-ui'].includes(packageName) && id.includes('_internal')) {
|
||||||
// 根据包名分组
|
// // return 'lib-naive-ui-internal';
|
||||||
if (['consola', 'lodash', '@juggle+resize-observer', 'vueuc'].includes(packageName)) {
|
// // }
|
||||||
return 'lib-vendor';
|
// if (['naive-ui'].includes(packageName)) {
|
||||||
}
|
// return 'lib-naive-ui';
|
||||||
|
// }
|
||||||
// // 拆了有问题
|
// if (
|
||||||
// if (['naive-ui'].includes(packageName) && id.includes('_internal')) {
|
// ['primelocale', 'primevue', 'primeuix', 'primeicons'].some((name) =>
|
||||||
// return 'lib-naive-ui-internal';
|
// packageName!.includes(name),
|
||||||
// }
|
// )
|
||||||
|
// ) {
|
||||||
if (['naive-ui'].includes(packageName)) {
|
// return 'lib-primevue';
|
||||||
return 'lib-naive-ui';
|
// }
|
||||||
}
|
// if (['vue', 'vue-router', 'pinia', 'vue-demi', 'vue-i18n'].includes(packageName)) {
|
||||||
|
// return 'lib-vue-vendor';
|
||||||
if (
|
// }
|
||||||
['primelocale', 'primevue', 'primeuix', 'primeicons'].some((name) =>
|
// }
|
||||||
packageName!.includes(name),
|
// },
|
||||||
)
|
|
||||||
) {
|
|
||||||
return 'lib-primevue';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (['vue', 'vue-router', 'pinia', 'vue-demi', 'vue-i18n'].includes(packageName)) {
|
|
||||||
return 'lib-vue-vendor';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { createViteProxy } from 'utils4u/vite';
|
|||||||
import { defineConfig, loadEnv } from 'vite';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
import { loadPlugins } from './vite-plugins/_loadPlugins';
|
import { loadPlugins } from './vite-plugins/_loadPlugins';
|
||||||
import { optimizeDeps } from './vite.config.optimizeDeps';
|
import { optimizeDeps } from './vite.config.optimizeDeps';
|
||||||
// import { viteConfigRollupOptions } from './vite.config.rollup';
|
import { viteConfigRollupOptions } from './vite.config.rollup';
|
||||||
import consola from 'consola';
|
import consola from 'consola';
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
@@ -24,7 +24,7 @@ export default defineConfig(async (configEnv) => {
|
|||||||
build: {
|
build: {
|
||||||
minify: env.VITE_BUILD_MINIFY === 'true' ? undefined /* 即默认 */ : false, // 默认: 'terser'
|
minify: env.VITE_BUILD_MINIFY === 'true' ? undefined /* 即默认 */ : false, // 默认: 'terser'
|
||||||
sourcemap: env.VITE_BUILD_SOURCE_MAP === 'true',
|
sourcemap: env.VITE_BUILD_SOURCE_MAP === 'true',
|
||||||
// rollupOptions: viteConfigRollupOptions,
|
rollupOptions: viteConfigRollupOptions,
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
devSourcemap: true,
|
devSourcemap: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user