feat(@vben/docs): support english documents (#4202)

* chore(@vben/docs): 完成guide文档的翻译

* chore(@vben/docs): 完成other文档的翻译

* chore: 翻译部分文档

* chore: 完成英文config的配置

* chore: 完成in-depth的文档翻译

* chore: 调整调整链接

* chore: typo

* chore: typo

* chore: update links

---------

Co-authored-by: Li Kui <90845831+likui628@users.noreply.github.com>
pull/48/MERGE
invalid w 2024-08-23 19:46:51 +08:00 committed by GitHub
parent c27b97f933
commit 8230493651
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 5795 additions and 315 deletions

View File

@ -0,0 +1,221 @@
import { type DefaultTheme, defineConfig } from 'vitepress';
import { version } from '../../../package.json';
export const en = defineConfig({
description: 'Vben Admin & Enterprise level management system framework',
lang: 'en-US',
themeConfig: {
darkModeSwitchLabel: 'Theme',
darkModeSwitchTitle: 'Switch to Dark Mode',
docFooter: {
next: 'Next Page',
prev: 'Previous Page',
},
editLink: {
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
text: 'Edit this page on GitHub',
},
footer: {
copyright: `Copyright © 2020-${new Date().getFullYear()} Vben`,
message: 'Released under the MIT License.',
},
langMenuLabel: 'Language',
lastUpdated: {
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium',
},
text: 'Last updated on',
},
lightModeSwitchTitle: 'Switch to Light Mode',
nav: nav(),
outline: {
label: 'Navigate',
},
returnToTopLabel: 'Back to top',
sidebar: {
'/en/commercial/': {
base: '/en/commercial/',
items: sidebarCommercial(),
},
'/en/guide/': { base: '/en/guide/', items: sidebarGuide() },
},
},
});
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
collapsed: false,
text: 'Introduction',
items: [
{
link: 'introduction/vben',
text: 'About Vben Admin',
},
{
link: 'introduction/why',
text: 'Why Choose Us?',
},
{ link: 'introduction/quick-start', text: 'Quick Start' },
{ link: 'introduction/thin', text: 'Lite Version' },
],
},
{
text: 'Basics',
items: [
{ link: 'essentials/concept', text: 'Basic Concepts' },
{ link: 'essentials/development', text: 'Local Development' },
{ link: 'essentials/route', text: 'Routing and Menu' },
{ link: 'essentials/settings', text: 'Configuration' },
{ link: 'essentials/icons', text: 'Icons' },
{ link: 'essentials/styles', text: 'Styles' },
{ link: 'essentials/external-module', text: 'External Modules' },
{ link: 'essentials/build', text: 'Build and Deployment' },
{ link: 'essentials/server', text: 'Server Interaction and Data Mock' },
],
},
{
text: 'Advanced',
items: [
{ link: 'in-depth/login', text: 'Login' },
{ link: 'in-depth/theme', text: 'Theme' },
{ link: 'in-depth/access', text: 'Access Control' },
{ link: 'in-depth/locale', text: 'Internationalization' },
{ link: 'in-depth/features', text: 'Common Features' },
{ link: 'in-depth/check-updates', text: 'Check Updates' },
{ link: 'in-depth/loading', text: 'Global Loading' },
{ link: 'in-depth/ui-framework', text: 'UI Framework Switching' },
],
},
{
text: 'Engineering',
items: [
{ link: 'project/standard', text: 'Standards' },
{ link: 'project/cli', text: 'CLI' },
{ link: 'project/dir', text: 'Directory Explanation' },
{ link: 'project/test', text: 'Unit Testing' },
{ link: 'project/tailwindcss', text: 'Tailwind CSS' },
{ link: 'project/changeset', text: 'Changeset' },
{ link: 'project/vite', text: 'Vite Config' },
],
},
{
text: 'Others',
items: [
{ link: 'other/project-update', text: 'Project Update' },
{ link: 'other/remove-code', text: 'Remove Code' },
{ link: 'other/faq', text: 'FAQ' },
],
},
];
}
function sidebarCommercial(): DefaultTheme.SidebarItem[] {
return [
{
link: 'community',
text: 'Community',
},
{
link: 'technical-support',
text: 'Technical-support',
},
{
link: 'customized',
text: 'Customized',
},
];
}
function nav(): DefaultTheme.NavItem[] {
return [
{
text: 'Doc',
items: [
{
link: '/en/guide/introduction/vben',
text: 'Guide',
},
{
text: 'Historical Versions',
items: [
{
link: 'https://doc.vvbin.cn',
text: '2.x Version Documentation',
},
],
},
],
},
{
text: 'Demo',
items: [
{
text: 'Vben Admin',
items: [
{
link: 'https://www.vben.pro',
text: 'Demo Version',
},
{
link: 'https://ant.vben.pro',
text: 'Ant Design Vue Version',
},
{
link: 'https://naive.vben.pro',
text: 'Naive Version',
},
{
link: 'https://ele.vben.pro',
text: 'Element Plus Version',
},
],
},
{
text: 'Others',
items: [
{
link: 'https://vben.vvbin.cn',
text: 'Vben Admin 2.x',
},
],
},
],
},
{
text: version,
items: [
{
link: 'https://github.com/vbenjs/vue-vben-admin/releases',
text: 'Changelog',
},
{
link: 'https://github.com/orgs/vbenjs/projects/5',
text: 'Roadmap',
},
{
link: 'https://github.com/vbenjs/vue-vben-admin/blob/main/.github/contributing.md',
text: 'Contribution',
},
],
},
{
link: '/commercial/technical-support',
text: '🦄 Technical Support',
},
{
link: '/sponsor/personal',
text: '✨ Sponsor',
},
{
link: '/commercial/community',
text: '👨‍👦‍👦 Community',
},
{
link: '/friend-links/',
text: '🤝 Friend Links',
},
];
}

View File

@ -0,0 +1,25 @@
import { withPwa } from '@vite-pwa/vitepress';
import { defineConfigWithTheme } from 'vitepress';
import { en } from './en.mts';
import { shard } from './shard.mts';
import { zh } from './zh.mts';
export default withPwa(
defineConfigWithTheme({
...shard,
locales: {
en: {
label: 'English',
lang: 'en',
link: '/en/',
...en,
},
root: {
label: '简体中文',
lang: 'zh-CN',
...zh,
},
},
}),
);

View File

@ -0,0 +1,120 @@
import type { PwaOptions } from '@vite-pwa/vitepress';
import { resolve } from 'node:path';
import {
GitChangelog,
GitChangelogMarkdownSection,
} from '@nolebase/vitepress-plugin-git-changelog/vite';
import { defineConfig, type HeadConfig } from 'vitepress';
import { search as zhSearch } from './zh.mts';
export const shard = defineConfig({
head: head(),
pwa: pwa(),
srcDir: 'src',
themeConfig: {
i18nRouting: true,
logo: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp',
search: {
options: {
locales: {
...zhSearch,
},
},
provider: 'local',
},
siteTitle: 'Vben Admin',
socialLinks: [
{ icon: 'github', link: 'https://github.com/vbenjs/vue-vben-admin' },
],
},
title: 'Vben Admin',
vite: {
build: {
chunkSizeWarningLimit: Infinity,
minify: 'terser',
},
json: {
stringify: true,
},
plugins: [
GitChangelog({
repoURL: () => 'https://github.com/vbenjs/vue-vben-admin',
}),
GitChangelogMarkdownSection(),
],
server: {
fs: {
allow: ['../..'],
},
host: true,
port: 6173,
},
ssr: {
external: ['@vue/repl'],
},
},
});
function head(): HeadConfig[] {
return [
['meta', { content: 'Vbenjs Team', name: 'author' }],
[
'meta',
{
content: 'vben, vitejs, vite, shacdn-ui, vue',
name: 'keywords',
},
],
['link', { href: '/favicon.ico', rel: 'icon', type: 'image/svg+xml' }],
[
'meta',
{
content:
'width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no',
name: 'viewport',
},
],
['meta', { content: 'vben admin docs', name: 'keywords' }],
['link', { href: '/favicon.ico', rel: 'icon' }],
// [
// 'script',
// {
// src: 'https://cdn.tailwindcss.com',
// },
// ],
];
}
function pwa(): PwaOptions {
return {
includeManifestIcons: false,
manifest: {
description:
'Vben Admin is a modern admin dashboard template based on Vue 3. ',
icons: [
{
sizes: '192x192',
src: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/pwa-icon-192.png',
type: 'image/png',
},
{
sizes: '512x512',
src: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/pwa-icon-512.png',
type: 'image/png',
},
],
id: '/',
name: 'Vben Admin Doc',
short_name: 'vben_admin_doc',
theme_color: '#ffffff',
},
outDir: resolve(process.cwd(), '.vitepress/dist'),
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'],
},
};
}

View File

@ -1,126 +1,134 @@
import type { DefaultTheme, HeadConfig } from 'vitepress';
import { type DefaultTheme, defineConfig } from 'vitepress';
import { resolve } from 'node:path';
import { version } from '../../../package.json';
import {
GitChangelog,
GitChangelogMarkdownSection,
} from '@nolebase/vitepress-plugin-git-changelog/vite';
import { type PwaOptions, withPwa } from '@vite-pwa/vitepress';
import { defineConfigWithTheme } from 'vitepress';
import { version } from '../../package.json';
export default withPwa(
defineConfigWithTheme({
description: 'Vben Admin & 企业级管理系统框架',
head: head(),
lang: 'zh',
pwa: pwa(),
// locales: {
// en: {
// label: 'English',
// lang: 'en',
// link: '/en/',
// },
// root: {
// label: '简体中文',
// lang: 'zh-CN',
srcDir: 'src',
// },
themeConfig: {
darkModeSwitchLabel: '主题',
darkModeSwitchTitle: '切换到深色模式',
docFooter: {
next: '下一页',
prev: '上一页',
export const zh = defineConfig({
description: 'Vben Admin & 企业级管理系统框架',
lang: 'zh-Hans',
themeConfig: {
darkModeSwitchLabel: '主题',
darkModeSwitchTitle: '切换到深色模式',
docFooter: {
next: '下一页',
prev: '上一页',
},
editLink: {
pattern: 'https://github.com/vbenjs/vue-vben-admin/edit/main/docs/:path',
text: '在 GitHub 上编辑此页面',
},
footer: {
copyright: `Copyright © 2020-${new Date().getFullYear()} Vben`,
message: '基于 MIT 许可发布.',
},
langMenuLabel: '多语言',
lastUpdated: {
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium',
},
editLink: {
pattern:
'https://github.com/vbenjs/vue-vben-admin/edit/main/docs/:path',
text: '在 GitHub 上编辑此页面',
},
footer: {
copyright: `Copyright © 2020-${new Date().getFullYear()} Vben`,
message: '基于 MIT 许可发布.',
},
i18nRouting: true,
langMenuLabel: '多语言',
lastUpdated: {
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium',
text: '最后更新于',
},
lightModeSwitchTitle: '切换到浅色模式',
nav: nav(),
outline: {
label: '页面导航',
},
returnToTopLabel: '回到顶部',
sidebar: {
'/commercial/': { base: '/commercial/', items: sidebarCommercial() },
'/guide/': { base: '/guide/', items: sidebarGuide() },
},
sidebarMenuLabel: '菜单',
},
});
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
collapsed: false,
text: '简介',
items: [
{
link: 'introduction/vben',
text: '关于 Vben Admin',
},
text: '最后更新于',
},
lightModeSwitchTitle: '切换到浅色模式',
logo: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp',
nav: nav(),
outline: {
label: '页面导航',
},
returnToTopLabel: '回到顶部',
search: {
options: {
locales: {
zh: {
translations: {
button: {
buttonAriaLabel: '搜索文档',
buttonText: '搜索文档',
},
modal: {
footer: {
navigateText: '切换',
selectText: '选择',
},
noResultsText: '无法找到相关结果',
resetButtonTitle: '清除查询条件',
},
},
},
},
{
link: 'introduction/why',
text: '为什么选择我们?',
},
provider: 'local',
},
sidebar: {
'/commercial/': { base: '/commercial/', items: sidebarCommercial() },
'/guide/': { base: '/guide/', items: sidebarGuide() },
},
sidebarMenuLabel: '菜单',
siteTitle: 'Vben Admin',
socialLinks: [
{ icon: 'github', link: 'https://github.com/vbenjs/vue-vben-admin' },
{ link: 'introduction/quick-start', text: '快速开始' },
{ link: 'introduction/thin', text: '精简版本' },
],
},
title: 'Vben Admin',
vite: {
build: {
chunkSizeWarningLimit: Infinity,
minify: 'terser',
},
json: {
stringify: true,
},
plugins: [
GitChangelog({
repoURL: () => 'https://github.com/vbenjs/vue-vben-admin',
}),
GitChangelogMarkdownSection(),
{
text: '基础',
items: [
{ link: 'essentials/concept', text: '基础概念' },
{ link: 'essentials/development', text: '本地开发' },
{ link: 'essentials/route', text: '路由和菜单' },
{ link: 'essentials/settings', text: '配置' },
{ link: 'essentials/icons', text: '图标' },
{ link: 'essentials/styles', text: '样式' },
{ link: 'essentials/external-module', text: '外部模块' },
{ link: 'essentials/build', text: '构建与部署' },
{ link: 'essentials/server', text: '服务端交互与数据Mock' },
],
server: {
fs: {
allow: ['../..'],
},
host: true,
port: 6173,
},
ssr: {
external: ['@vue/repl'],
},
},
}),
);
{
text: '深入',
items: [
{ link: 'in-depth/login', text: '登录' },
// { link: 'in-depth/layout', text: '布局' },
{ link: 'in-depth/theme', text: '主题' },
{ link: 'in-depth/access', text: '权限' },
{ link: 'in-depth/locale', text: '国际化' },
{ link: 'in-depth/features', text: '常用功能' },
{ link: 'in-depth/check-updates', text: '检查更新' },
{ link: 'in-depth/loading', text: '全局loading' },
{ link: 'in-depth/ui-framework', text: '组件库切换' },
],
},
{
text: '工程',
items: [
{ link: 'project/standard', text: '规范' },
{ link: 'project/cli', text: 'CLI' },
{ link: 'project/dir', text: '目录说明' },
{ link: 'project/test', text: '单元测试' },
{ link: 'project/tailwindcss', text: 'Tailwind CSS' },
{ link: 'project/changeset', text: 'Changeset' },
{ link: 'project/vite', text: 'Vite Config' },
],
},
{
text: '其他',
items: [
{ link: 'other/project-update', text: '项目更新' },
{ link: 'other/remove-code', text: '移除代码' },
{ link: 'other/faq', text: '常见问题' },
],
},
];
}
function sidebarCommercial(): DefaultTheme.SidebarItem[] {
return [
{
link: 'community',
text: '社区交流',
},
{
link: 'technical-support',
text: '技术支持',
},
{
link: 'customized',
text: '定制开发',
},
];
}
function nav(): DefaultTheme.NavItem[] {
return [
@ -249,148 +257,46 @@ function nav(): DefaultTheme.NavItem[] {
];
}
function sidebarGuide(): DefaultTheme.SidebarItem[] {
return [
{
collapsed: false,
text: '简介',
items: [
{
link: 'introduction/vben',
text: '关于 Vben Admin',
},
{
link: 'introduction/why',
text: '为什么选择我们?',
},
{ link: 'introduction/quick-start', text: '快速开始' },
{ link: 'introduction/thin', text: '精简版本' },
],
},
{
text: '基础',
items: [
{ link: 'essentials/concept', text: '基础概念' },
{ link: 'essentials/development', text: '本地开发' },
{ link: 'essentials/route', text: '路由和菜单' },
{ link: 'essentials/settings', text: '配置' },
{ link: 'essentials/icons', text: '图标' },
{ link: 'essentials/styles', text: '样式' },
{ link: 'essentials/external-module', text: '外部模块' },
{ link: 'essentials/build', text: '构建与部署' },
{ link: 'essentials/server', text: '服务端交互与数据Mock' },
],
},
{
text: '深入',
items: [
{ link: 'in-depth/login', text: '登录' },
// { link: 'in-depth/layout', text: '布局' },
{ link: 'in-depth/theme', text: '主题' },
{ link: 'in-depth/access', text: '权限' },
{ link: 'in-depth/locale', text: '国际化' },
{ link: 'in-depth/features', text: '常用功能' },
{ link: 'in-depth/check-updates', text: '检查更新' },
{ link: 'in-depth/loading', text: '全局loading' },
{ link: 'in-depth/ui-framework', text: '组件库切换' },
],
},
{
text: '工程',
items: [
{ link: 'project/standard', text: '规范' },
{ link: 'project/cli', text: 'CLI' },
{ link: 'project/dir', text: '目录说明' },
{ link: 'project/test', text: '单元测试' },
{ link: 'project/tailwindcss', text: 'Tailwind CSS' },
{ link: 'project/changeset', text: 'Changeset' },
{ link: 'project/vite', text: 'Vite Config' },
],
},
{
text: '其他',
items: [
{ link: 'other/project-update', text: '项目更新' },
{ link: 'other/remove-code', text: '移除代码' },
{ link: 'other/faq', text: '常见问题' },
],
},
];
}
function sidebarCommercial(): DefaultTheme.SidebarItem[] {
return [
{
link: 'community',
text: '社区交流',
},
{
link: 'technical-support',
text: '技术支持',
},
{
link: 'customized',
text: '定制开发',
},
];
}
function head(): HeadConfig[] {
return [
['meta', { content: 'Vbenjs Team', name: 'author' }],
[
'meta',
{
content: 'vben, vitejs, vite, shacdn-ui, vue',
name: 'keywords',
export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
root: {
placeholder: '搜索文档',
translations: {
button: {
buttonAriaLabel: '搜索文档',
buttonText: '搜索文档',
},
],
['link', { href: '/favicon.ico', rel: 'icon', type: 'image/svg+xml' }],
[
'meta',
{
content:
'width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no',
name: 'viewport',
modal: {
errorScreen: {
helpText: '你可能需要检查你的网络连接',
titleText: '无法获取结果',
},
footer: {
closeText: '关闭',
navigateText: '切换',
searchByText: '搜索提供者',
selectText: '选择',
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
reportMissingResultsLinkText: '点击反馈',
reportMissingResultsText: '你认为该查询应该有结果?',
suggestedQueryText: '你可以尝试查询',
},
searchBox: {
cancelButtonAriaLabel: '取消',
cancelButtonText: '取消',
resetButtonAriaLabel: '清除查询条件',
resetButtonTitle: '清除查询条件',
},
startScreen: {
favoriteSearchesTitle: '收藏',
noRecentSearchesText: '没有搜索历史',
recentSearchesTitle: '搜索历史',
removeFavoriteSearchButtonTitle: '从收藏中移除',
removeRecentSearchButtonTitle: '从搜索历史中移除',
saveRecentSearchButtonTitle: '保存至搜索历史',
},
},
],
['meta', { content: 'vben admin docs', name: 'keywords' }],
['link', { href: '/favicon.ico', rel: 'icon' }],
// [
// 'script',
// {
// src: 'https://cdn.tailwindcss.com',
// },
// ],
];
}
function pwa(): PwaOptions {
return {
includeManifestIcons: false,
manifest: {
description:
'Vben Admin is a modern admin dashboard template based on Vue 3. ',
icons: [
{
sizes: '192x192',
src: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/pwa-icon-192.png',
type: 'image/png',
},
{
sizes: '512x512',
src: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/pwa-icon-512.png',
type: 'image/png',
},
],
id: '/',
name: 'Vben Admin Doc',
short_name: 'vben_admin_doc',
theme_color: '#ffffff',
},
outDir: resolve(process.cwd(), '.vitepress/dist'),
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'],
},
};
}
},
};

View File

@ -0,0 +1,243 @@
# Build and Deployment
::: tip Preface
Since this is a demonstration project, the package size after building is relatively large. If there are plugins in the project that are not used, you can delete the corresponding files or routes. If they are not referenced, they will not be packaged.
:::
## Building
After the project development is completed, execute the following command to build:
**Note:** Please execute the following command in the project root directory.
```bash
pnpm build
```
After the build is successful, a `dist` folder for the corresponding application will be generated in the root directory, which contains the built and packaged files, for example: `apps/web-antd/dist/`
## Preview
Before publishing, you can preview it locally in several ways, here are two:
- Using the project's custom command for preview (recommended)
**Note** Please execute the following command in the project root directory.
```bash
pnpm preview
```
After waiting for the build to succeed, visit `http://localhost:4173` to view the effect.
- Local server preview
You can globally install a `serve` service on your computer, such as `live-server`,
```bash
npm i -g live-server
```
Then execute the `live-server` command in the `dist` directory to view the effect locally.
```bash
cd apps/web-antd/dist
# Local preview, default port 8080
live-server
# Specify port
live-server --port 9000
```
## Compression
### Enable `gzip` Compression
To enable during the build process, change the `.env.production` configuration:
```bash
VITE_COMPRESS=gzip
```
### Enable `brotli` Compression
To enable during the build process, change the `.env.production` configuration:
```bash
VITE_COMPRESS=brotli
```
### Enable Both `gzip` and `brotli` Compression
To enable during the build process, change the `.env.production` configuration:
```bash
VITE_COMPRESS=gzip,brotli
```
::: tip Note
Both `gzip` and `brotli` require specific modules to be installed for use.
:::
::: details gzip 与 brotli 在 nginx 内的配置
```bash
http {
# Enable gzip
gzip on;
# Enable gzip_static
# After enabling gzip_static, there might be errors, requiring the installation of specific modules. The installation method can be researched independently.
# Only with this enabled, the .gz files packaged by vue files will be effective; otherwise, there is no need to enable gzip for packaging.
gzip_static on;
gzip_proxied any;
gzip_min_length 1k;
gzip_buffers 4 16k;
# If nginx uses multiple layers of proxy, this must be set to enable gzip.
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";
# Enable brotli compression
# Requires the installation of the corresponding nginx module, which can be researched independently.
# Can coexist with gzip without conflict.
brotli on;
brotli_comp_level 6;
brotli_buffers 16 8k;
brotli_min_length 20;
brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
}
```
:::
## Build Analysis
If your build files are large, you can optimize your code by analyzing the code size with the built-in [rollup-plugin-analyzer](https://github.com/doesdev/rollup-plugin-analyzer) plugin. Just execute the following command in the `root directory`:
```bash
pnpm run build:analyze
```
After running, you can see the specific distribution of sizes on the automatically opened page to analyze which dependencies are problematic.
![Build analysis report](/guide/report.png)
## Deployment
A simple deployment only requires publishing the final static files, the static files in the dist folder, to your CDN or static server. It's important to note that the index.html is usually the entry page for your backend service. After determining the static js and css, you may need to change the page's import path.
For example, to upload to an nginx server, you can upload the files under the dist folder to the server's `/srv/www/project/index.html` directory, and then access the configured domain name.
```bash
# nginx configuration
location / {
# Do not cache html to prevent cache from continuing to be effective after program updates
if ($request_filename ~* .*\.(?:htm|html)$) {
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
access_log on;
}
# This is the storage path for the files inside the vue packaged dist folder
root /srv/www/project/;
index index.html index.htm;
}
```
If you find the resource path is incorrect during deployment, you just need to modify the `.env.production` file.
```bash
# Configure the change according to your own path
# Note that it needs to start and end with /
VITE_BASE=/
VITE_BASE=/xxx/
```
### Integration of Frontend Routing and Server
The project uses vue-router for frontend routing, so you can choose between two modes: history and hash.
- `hash` mode will append `#` to the URL by default.
- `history` mode will not, but `history` mode requires server-side support.
You can modify the mode in `.env.production`:
```bash
VITE_ROUTER_HISTORY=hash
```
### Server Configuration for History Mode Routing
Enabling `history` mode requires server configuration. For more details on server configuration, see [history-mode](https://router.vuejs.org/guide/essentials/history-mode.html#html5-mode)
Here is an example of `nginx` configuration:
#### Deployment at the Root Directory
```bash {5}
server {
listen 80;
location / {
# For use with History mode
try_files $uri $uri/ /index.html;
}
}
```
#### Deployment to a Non-root Directory
- First, you need to change the `.env.production` configuration during packaging:
```bash
VITE_BASE = /sub/
```
- Then configure in the nginx configuration file
```bash {8}
server {
listen 80;
server_name localhost;
location /sub/ {
# This is the path where the vue packaged dist files are stored
alias /srv/www/project/;
index index.html index.htm;
try_files $uri $uri/ /sub/index.html;
}
}
```
## Cross-Domain Handling
Using nginx to handle cross-domain issues after project deployment
1. Configure the frontend project API address in the `.env.production` file in the project directory:
```bash
VITE_GLOB_API_URL=/api
```
2. Configure nginx to forward requests to the backend
```bash {10-11}
server {
listen 8080;
server_name localhost;
# API proxy for solving cross-domain issues
location /api {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Backend API address
proxy_pass http://110.110.1.1:8080/api;
rewrite "^/api/(.*)$" /$1 break;
proxy_redirect default;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
}
}
```

View File

@ -0,0 +1,70 @@
# Basic Concepts
In the new version, the entire project has been restructured. Now, we will introduce some basic concepts to help you better understand the entire document. Please make sure to read this section first.
## Monorepo
Monorepo refers to the repository of the entire project, which includes all code, packages, applications, standards, documentation, configurations, etc., that is, the entire content of a `Monorepo` directory.
## Applications
Applications refer to a complete project; a project can contain multiple applications, which can reuse the code, packages, standards, etc., within the monorepo. Applications are placed in the `apps` directory. Each application is independent and can be run, built, tested, and deployed separately; it can also include different component libraries, etc.
::: tip
Applications are not limited to front-end applications; they can also be back-end applications, mobile applications, etc. For example, `apps/backend-mock` is a back-end service.
:::
## Packages
A package refers to an independent module, which can be a component, a tool, a library, etc. Packages can be referenced by multiple applications or other packages. Packages are placed in the `packages` directory.
You can consider these packages as independent `npm` packages, and they are used in the same way as `npm` packages.
### Package Import
Importing a package in `package.json`:
```json {3}
{
"dependencies": {
"@vben/utils": "workspace:*"
}
}
```
### Package Usage
Importing a package in the code:
```ts
import { isString } from '@vben/utils';
```
## Aliases
In the project, you can see some paths starting with `#`, such as `#/api`, `#/views`. These paths are aliases, used for quickly locating a certain directory. They are not implemented through `vite`'s `alias`, but through the principle of [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) in `Node.js` itself. You only need to configure the `imports` field in `package.json`.
```json {3}
{
"imports": {
"#/*": "./src/*"
}
}
```
To make these aliases recognizable by the IDE, we also need to configure them in `tsconfig.json`:
```json {5}
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["src/*"]
}
}
}
```
This way, you can use aliases in your code.

View File

@ -0,0 +1,184 @@
# Local Development {#development}
::: tip Code Acquisition
If you haven't acquired the code yet, you can start by reading the documentation from [Quick Start](../introduction/quick-start.md).
:::
## Prerequisites
For a better development experience, we provide some tool configurations and project descriptions to facilitate your development.
### Required Basic Knowledge
This project requires some basic frontend knowledge. Please ensure you are familiar with the basics of Vue to handle common issues. It is recommended to learn the following topics before development. Understanding these will be very helpful for the project:
- [Vue3](https://vuejs.org/)
- [Tailwind CSS](https://tailwindcss.com/)
- [TypeScript](https://www.typescriptlang.org/)
- [Vue Router](https://router.vuejs.org/)
- [Vitejs](https://vitejs.dev/)
- [Pnpm](https://pnpm.io/)
- [Turbo](https://turbo.build/)
### Tool Configuration
If you are using [vscode](https://code.visualstudio.com/) (recommended) as your IDE, you can install the following tools to improve development efficiency and code formatting:
- [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Official Vue plugin (essential).
- [Tailwind CSS](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - Tailwind CSS autocomplete plugin.
- [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=vunguyentuan.vscode-css-variables) - CSS variable autocomplete plugin.
- [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) - Iconify icon plugin.
- [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) - i18n plugin.
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Script code linting.
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatting.
- [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - CSS formatting.
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Spelling checker.
- [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - .env file highlighting.
## Npm Scripts
Npm scripts are common configurations used in the project to perform common tasks such as starting the project, building the project, etc. The following scripts can be found in the `package.json` file at the root of the project.
The execution command is: `pnpm run [script]` or `npm run [script]`.
```json
{
"scripts": {
// Install dependencies
"bootstrap": "pnpm install",
// Build the project
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
// Build the project with analysis
"build:analyze": "turbo build:analyze",
// Build a local Docker image
"build:docker": "./build-local-docker-image.sh",
// Build the web-antd application separately
"build:antd": "pnpm run build --filter=@vben/web-antd",
// Build the documentation separately
"build:docs": "pnpm run build --filter=@vben/docs",
// Build the web-ele application separately
"build:ele": "pnpm run build --filter=@vben/web-ele",
// Build the web-naive application separately
"build:naive": "pnpm run build --filter=@vben/naive",
// Build the playground application separately
"build:play": "pnpm run build --filter=@vben/playground",
// Changeset version management
"changeset": "pnpm exec changeset",
// Check for various issues in the project
"check": "pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell",
// Check for circular dependencies
"check:circular": "vsh check-circular",
// Check spelling
"check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress"
// Check dependencies
"check:dep": "vsh check-dep",
// Check types
"check:type": "turbo run typecheck",
// Clean the project (delete node_modules, dist, .turbo, etc.)
"clean": "vsh clean",
// Commit code
"commit": "czg",
// Start the project (by default, the dev scripts of all packages in the entire repository will run)
"dev": "turbo-run dev",
// Start the web-antd application
"dev:antd": "pnpm -F @vben/web-antd run dev",
// Start the documentation
"dev:docs": "pnpm -F @vben/docs run dev",
// Start the web-ele application
"dev:ele": "pnpm -F @vben/web-ele run dev",
// Start the web-naive application
"dev:naive": "pnpm -F @vben/web-naive run dev",
// Start the playground application
"dev:play": "pnpm -F @vben/playground run dev",
// Format code
"format": "vsh lint --format",
// Lint code
"lint": "vsh lint",
// After installing dependencies, execute the stub script for all packages
"postinstall": "turbo run stub",
// Only allow using pnpm
"preinstall": "npx only-allow pnpm",
// Install husky
"prepare": "is-ci || husky",
// Preview the application
"preview": "turbo-run preview",
// Package specification check
"publint": "vsh publint",
// Delete all node_modules, yarn.lock, package.lock.json, and reinstall dependencies
"reinstall": "pnpm clean --del-lock && pnpm bootstrap",
// Run vitest unit tests
"test:unit": "vitest",
// Update project dependencies
"update:deps": " pnpm update --latest --recursive",
// Changeset generation and versioning
"version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile"
}
}
```
## Running the Project Locally
To run the documentation locally and make adjustments, you can execute the following command. This command allows you to select the application you want to develop:
```bash
pnpm dev
```
If you want to run a specific application directly, you can execute the following commands:
To run the `web-antd` application:
```bash
pnpm dev:antd
```
To run the `web-naive` application:
```bash
pnpm dev:naive
```
To run the `web-ele` application:
```bash
pnpm dev:ele
```
To run the `docs` application:
```bash
pnpm dev:docs
```
## DevTools
The project has a built-in [Vue DevTools](https://github.com/vuejs/devtools-next) plugin, which can be used during development. It is disabled by default, but can be enabled in the `.env.development` file. After enabling it, restart the project:
```bash
VITE_DEVTOOLS=true
```
Once enabled, a Vue DevTools icon will appear at the bottom of the page during project runtime. Click it to open the DevTools.
![Vue DevTools](/guide/devtools.png)
## Running Documentation Locally
To run the documentation locally and make adjustments, you can execute the following command:
```bash
pnpm dev:docs
```
## Troubleshooting
If you encounter dependency-related issues, you can try reinstalling the dependencies:
```bash
# Execute this command at the root of the project.
# This command will delete all node_modules, yarn.lock, and package.lock.json files
# and then reinstall dependencies (this process will be noticeably slower).
pnpm reinstall
```

View File

@ -0,0 +1,58 @@
# External Modules
In addition to the external modules that are included by default in the project, sometimes we need to import other external modules. Let's take [ant-design-vue](https://antdv.com/components/overview) as an example:
## Installing Dependencies
::: tip Install dependencies into a specific package
- Since the project uses [pnpm](https://pnpm.io/) as the package management tool, we need to use the `pnpm` command to install dependencies.
- As the project is managed using a Monorepo module, we need to install dependencies under a specific package. Please make sure you have entered the specific package directory before installing dependencies.
:::
```bash
# cd /path/to/your/package
pnpm add ant-design-vue
```
## Usage
### Global Import
```ts
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/reset.css';
const app = createApp(App);
app.use(Antd).mount('#app');
```
#### Usage
```vue
<template>
<a-button>text</a-button>
</template>
```
### Partial Import
```vue
<script setup lang="ts">
import { Button } from 'ant-design-vue';
</script>
<template>
<Button>text</Button>
</template>
```
::: warning Note
- If the component depends on styles, you also need to import the style file.
:::

View File

@ -0,0 +1,78 @@
# Icons
::: tip About Icon Management
- The icons in the project are mainly provided by the `@vben/icons` package. It is recommended to manage them within this package for unified management and maintenance.
- If you are using `Vscode`, it is recommended to install the [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) plugin, which makes it easy to find and use icons.
:::
There are several ways to use icons in the project, you can choose according to the actual situation:
## Iconify Icons <Badge text="Recommended" type="tip"/>
Integrated with the [iconify](https://github.com/iconify/iconify) icon library
### Adding New Icons
You can add new icons in the `packages/icons/src/iconify` directory:
```ts
// packages/icons/src/iconify/index.ts
import { createIconifyIcon } from '@vben-core/icons';
export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
```
### Usage
```vue
<script setup lang="ts">
import { MdiKeyboardEsc } from '@vben/icons';
</script>
<template>
<!-- An icon with a width and height of 20px -->
<MdiKeyboardEsc class="size-5" />
</template>
```
## SVG Icons <Badge text="Recommended" type="tip"/>
Instead of using Svg Sprite, SVG icons are directly imported,
### Adding New Icons
You can add new icon files `test.svg` in the `packages/icons/src/svg/icons` directory, and then import it in `packages/icons/src/svg/index.ts`:
```ts
// packages/icons/src/svg/index.ts
import { createIconifyIcon } from '@vben-core/icons';
const SvgTestIcon = createIconifyIcon('svg:test');
export { SvgTestIcon };
```
### Usage
```vue
<script setup lang="ts">
import { SvgTestIcon } from '@vben/icons';
</script>
<template>
<!-- An icon with a width and height of 20px -->
<SvgTestIcon class="size-5" />
</template>
```
## Tailwind CSS Icons <Badge text="Not Recommended" type="danger"/>
### Usage
You can use the icons by directly adding the Tailwind CSS icon class names, which can be found on [iconify](https://github.com/iconify/iconify)
```vue
<span class="icon-[mdi--ab-testing]"></span>
```

View File

@ -0,0 +1,560 @@
---
outline: deep
---
# Routing and Menus
In the project, the framework provides a basic routing system and **automatically generates the corresponding menu structure based on the routing file**.
## Route Types
Routes are divided into static routes and dynamic routes. Static routes are routes that have been determined when the project starts. Dynamic routes are generally routes that are dynamically generated based on the user's permissions after the user logs in.
### Static Routes
If your page project does not require permission control, you can directly use static routes. The configuration of static routes is in the `src/router/routes/index` directory under the application. Open the commented file content:
```ts
// If necessary, you can open your own comments and create folders
// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // [!code --]
const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); // [!code ++]
/** Dynamic routing */
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
/** External routing lists, which can be accessed without Layout, may be used for embedding in other systems */
// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles) // [!code --]
const externalRoutes: RouteRecordRaw[] = []; // [!code --]
const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // [!code ++]
```
### Dynamic routing
The configuration of dynamic routing is in the corresponding application `src/router/routes/modules` directory. All routing files are stored in this directory. The content format of each file is as follows, which is consistent with the routing configuration format of Vue Router. The following is the configuration of secondary routes and multi-level routes.
## Define the route
Static routes and dynamic routes are configured in the same way. The configuration of the level-2 and multi-level routes is as follows:
### Secondary route
::: details Example code of the secondary route
```ts
import type { RouteRecordRaw } from 'vue-router';
import { VBEN_LOGO_URL } from '@vben/constants';
import { BasicLayout } from '#/layouts';
import { $t } from '#/locales';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
badgeType: 'dot',
badgeVariants: 'destructive',
icon: VBEN_LOGO_URL,
order: 9999,
title: $t('page.vben.title'),
},
name: 'VbenProject',
path: '/vben-admin',
redirect: '/vben-admin/about',
children: [
{
name: 'VbenAbout',
path: '/vben-admin/about',
component: () => import('#/views/_core/about/index.vue'),
meta: {
badgeType: 'dot',
badgeVariants: 'destructive',
icon: 'lucide:copyright',
title: $t('page.vben.about'),
},
},
],
},
];
export default routes;
```
:::
### Multilevel routing
::: tip
- The parent route of multi-level routing does not need to set the 'component' attribute, only the 'children' attribute needs to be set. Unless you really need to display content under nested parent routing.
- If there are no special circumstances, the 'redirect' attribute of the parent route does not need to be specified and will default to the first child route.
:::
::: details Multilevel Routing Example Code
```ts
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
import { $t } from '#/locales';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'ic:baseline-view-in-ar',
keepAlive: true,
order: 1000,
title: $t('page.demos.title'),
},
name: 'Demos',
path: '/demos',
redirect: '/demos/access',
children: [
// 嵌套菜单
{
meta: {
icon: 'ic:round-menu',
title: $t('page.demos.nested.title'),
},
name: 'NestedDemos',
path: '/demos/nested',
redirect: '/demos/nested/menu1',
children: [
{
name: 'Menu1Demo',
path: '/demos/nested/menu1',
component: () => import('#/views/demos/nested/menu-1.vue'),
meta: {
icon: 'ic:round-menu',
keepAlive: true,
title: $t('page.demos.nested.menu1'),
},
},
{
name: 'Menu2Demo',
path: '/demos/nested/menu2',
meta: {
icon: 'ic:round-menu',
keepAlive: true,
title: $t('page.demos.nested.menu2'),
},
redirect: '/demos/nested/menu2/menu2-1',
children: [
{
name: 'Menu21Demo',
path: '/demos/nested/menu2/menu2-1',
component: () => import('#/views/demos/nested/menu-2-1.vue'),
meta: {
icon: 'ic:round-menu',
keepAlive: true,
title: $t('page.demos.nested.menu2_1'),
},
},
],
},
{
name: 'Menu3Demo',
path: '/demos/nested/menu3',
meta: {
icon: 'ic:round-menu',
title: $t('page.demos.nested.menu3'),
},
redirect: '/demos/nested/menu3/menu3-1',
children: [
{
name: 'Menu31Demo',
path: 'menu3-1',
component: () => import('#/views/demos/nested/menu-3-1.vue'),
meta: {
icon: 'ic:round-menu',
keepAlive: true,
title: $t('page.demos.nested.menu3_1'),
},
},
{
name: 'Menu32Demo',
path: 'menu3-2',
meta: {
icon: 'ic:round-menu',
title: $t('page.demos.nested.menu3_2'),
},
redirect: '/demos/nested/menu3/menu3-2/menu3-2-1',
children: [
{
name: 'Menu321Demo',
path: '/demos/nested/menu3/menu3-2/menu3-2-1',
component: () =>
import('#/views/demos/nested/menu-3-2-1.vue'),
meta: {
icon: 'ic:round-menu',
keepAlive: true,
title: $t('page.demos.nested.menu3_2_1'),
},
},
],
},
],
},
],
},
],
},
];
export default routes;
```
:::
## Add a New Page
To add a new page, you only need to add a route and the corresponding page component.
### Add a Route
Add a route object in the corresponding routing file as follows:
```ts
import type { RouteRecordRaw } from 'vue-router';
import { VBEN_LOGO_URL } from '@vben/constants';
import { BasicLayout } from '#/layouts';
import { $t } from '#/locales';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'mdi:home',
title: $t('page.home.title'),
},
name: 'Home',
path: '/home',
redirect: '/home/index',
children: [
{
name: 'HomeIndex',
path: '/home/index',
component: () => import('#/views/home/index.vue'),
meta: {
icon: 'mdi:home',
title: $t('page.home.index'),
},
},
],
},
];
export default routes;
```
### Add Page Component
In `#/views/home/`, add a new `index.vue` file as follows:
```vue
<template>
<div>
<h1>home page</h1>
</div>
</template>
```
### Verification
At this point, the page has been added. Access `http://localhost:5555/home/index` to see the corresponding page.
## Route Configuration
The route configuration mainly resides in the `meta` attribute of the route object. Below are some commonly used configuration items
```ts {5-8}
const routes = [
{
name: 'HomeIndex',
path: '/home/index',
meta: {
icon: 'mdi:home',
title: $t('page.home.index'),
},
},
];
```
::: details Route Meta Configuration Type Definition
```ts
interface RouteMeta {
/**
* Active icon (menu)
*/
activeIcon?: string;
/**
* The currently active menu, used when you want to activate a parent menu instead of the existing one
* @default false
*/
activePath?: string;
/**
* Whether to affix the tab
* @default false
*/
affixTab?: boolean;
/**
* The order of the affixed tab
* @default 0
*/
affixTabOrder?: number;
/**
* Specific role identifiers required for access
* @default []
*/
authority?: string[];
/**
* Badge
*/
badge?: string;
/**
* Badge type
*/
badgeType?: 'dot' | 'normal';
/**
* Badge color
*/
badgeVariants?:
| 'default'
| 'destructive'
| 'primary'
| 'success'
| 'warning'
| string;
/**
* Children of the current route do not show in the menu
* @default false
*/
hideChildrenInMenu?: boolean;
/**
* The current route does not show in the breadcrumb
* @default false
*/
hideInBreadcrumb?: boolean;
/**
* The current route does not show in the menu
* @default false
*/
hideInMenu?: boolean;
/**
* The current route does not show in tabs
* @default false
*/
hideInTab?: boolean;
/**
* Icon (menu/tab)
*/
icon?: string;
/**
* iframe address
*/
iframeSrc?: string;
/**
* Ignore access, can be accessed directly
* @default false
*/
ignoreAccess?: boolean;
/**
* Enable KeepAlive caching
*/
keepAlive?: boolean;
/**
* External link - redirect path
*/
link?: string;
/**
* Whether the route has been loaded
*/
loaded?: boolean;
/**
* Maximum number of open tabs
* @default false
*/
maxNumOfOpenTab?: number;
/**
* The menu is visible, but access will be redirected to 403
*/
menuVisibleWithForbidden?: boolean;
/**
* Used for route->menu sorting
*/
order?: number;
/**
* Title name
*/
title: string;
}
```
:::
### title
- Type: `string`
- Default value: `''`
Used to configure the page title, which will be displayed in the menu and tabs. It is generally used in conjunction with internationalization.
### icon
- Type: `string`
- Default value: `''`
Used to configure the page icon, which will be displayed in the menu and tabs. It is generally used in conjunction with an icon library. If it is an `http` link, the image will be automatically loaded.
### activeIcon
- Type: `string`
- Default value: `''`
Used to configure the active icon of the page, which will be displayed in the menu. It is generally used in conjunction with an icon library. If it is an `http` link, the image will be automatically loaded.
### keepAlive
- Type: `boolean`
- Default value: `false`
Used to configure whether the page caching is enabled. Once enabled, the page will be cached and not reloaded, only effective when tabs are enabled.
### hideInMenu
- Type: `boolean`
- Default value: `false`
Used to configure whether the page is hidden in the menu. If hidden, the page will not be displayed in the menu.
### hideInTab
- Type: `boolean`
- Default value: `false`
Used to configure whether the page is hidden in tabs. If hidden, the page will not be displayed in tabs.
### hideInBreadcrumb
- Type: `boolean`
- Default value: `false`
Used to configure whether the page is hidden in the breadcrumb. If hidden, the page will not be displayed in the breadcrumb.
### hideChildrenInMenu
- Type: `boolean`
- Default value: `false`
Used to configure whether the child pages of the page are hidden in the menu. If hidden, the child pages will not be displayed in the menu.
### authority
- Type: `string[]`
- Default value: `[]`
Used to configure the page's permissions. Only users with corresponding permissions can access the page. If not configured, no permissions are required.
### badge
- Type: `string`
- Default value: `''`
Used to configure the page's badge, which will be displayed in the menu.
### badgeType
- Type: `'dot' | 'normal'`
- Default value: `'normal'`
Used to configure the type of the page's badge. `dot` is a small red dot, `normal` is text.
### badgeVariants
- Type: `'default' | 'destructive' | 'primary' | 'success' | 'warning' | string`
- Default value: `'success'`
Used to configure the color of the page's badge.
### activePath
- Type: `string`
- Default value: `''`
Used to configure the currently active menu. Sometimes when the page is not displayed in the menu, it is used to activate the parent menu.
### affixTab
- Type: `boolean`
- Default value: `false`
Used to configure whether the page tab is pinned. Once pinned, the page cannot be closed.
### affixTabOrder
- Type: `number`
- Default value: `0`
Used to configure the order of the pinned page tabs, sorted in ascending order.
### iframeSrc
- Type: `string`
- Default value: `''`
Used to configure the `iframe` address of the embedded page. Once set, the corresponding page will be embedded in the current page.
### ignoreAccess
- Type: `boolean`
- Default value: `false`
Used to configure whether the page ignores permissions and can be accessed directly.
### link
- Type: `string`
- Default value: `''`
Used to configure the external link jump path, which will be opened in a new window.
### maxNumOfOpenTab
- Type: `number`
- Default value: `-1`
Used to configure the maximum number of open tabs. Once set, the earliest opened tab will be automatically closed when a new tab is opened (only effective when opening tabs with the same name).
### menuVisibleWithForbidden
- Type: `boolean`
- Default value: `false`
Used to configure whether the page can be seen in the menu, but access will be redirected to 403.
### order
- Type: `number`
- Default value: `0`
Used to configure the page's order, for routing to menu sorting.
## Route Refresh
The way to refresh the route is as follows:
```vue
<script setup lang="ts">
import { useRefresh } from '@vben/hooks';
const { refresh } = useRefresh();
// Refresh the current route
refresh();
</script>
```

View File

@ -0,0 +1,347 @@
# Server Interaction and Data Mocking
::: tip Note
This document explains how to use Mock data and interact with the server in a development environment, involving technologies such as:
- [Nitro](https://nitro.unjs.io/) A lightweight backend server that can be deployed anywhere, used as a Mock server in the project.
- [axios](https://axios-http.com/docs/intro) Used to send HTTP requests to interact with the server.
:::
## Interaction in Development Environment
If the frontend application and the backend API server are not running on the same host, you need to proxy the API requests to the API server in the development environment. If they are on the same host, you can directly request the specific API endpoint.
### Local Development CORS Configuration
::: tip Hint
The CORS configuration for local development has already been set up. If you have other requirements, you can add or adjust the configuration as needed.
:::
#### Configuring Local Development API Endpoint
Configure the API endpoint in the `.env.development` file at the project root directory, here it is set to `/api`:
```bash
VITE_GLOB_API_URL=/api
```
#### Configuring Development Server Proxy
In the development environment, if you need to handle CORS, configure the API endpoint in the `vite.config.mts` file under the corresponding application directory:
```ts{8-16}
// apps/web-antd/vite.config.mts
import { defineConfig } from '@vben/vite-config';
export default defineConfig(async () => {
return {
vite: {
server: {
proxy: {// [!code focus:11]
'/api': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
// mock proxy
target: 'http://localhost:5320/api',
ws: true,
},
},
},
},
};
});
```
#### API Requests
Based on the above configuration, we can use `/api` as the prefix for API requests in our frontend project, for example:
```ts
import axios from 'axios';
axios.get('/api/user').then((res) => {
console.log(res);
});
```
At this point, the request will be proxied to `http://localhost:5320/api/user`.
::: warning Note
From the browser's console Network tab, the request appears as `http://localhost:5555/api/user`. This is because the proxy configuration does not change the local request's URL.
:::
### Configuration Without CORS
If there is no CORS issue, you can directly ignore the [Configure Development Server Proxy](./server.md#configure-development-server-proxy) settings and set the API endpoint directly in `VITE_GLOB_API_URL`.
Configure the API endpoint in the `.env.development` file at the project root directory:
```bash
VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
```
## Production Environment Interaction
### API Endpoint Configuration
Configure the API endpoint in the `.env.production` file at the project root directory:
```bash
VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
```
::: tip How to Dynamically Modify API Endpoint in Production
Variables starting with `VITE_GLOB_*` in the `.env` file are injected into the `_app.config.js` file during packaging. After packaging, you can modify the corresponding API addresses in `dist/_app.config.js` and refresh the page to apply the changes. This eliminates the need to package multiple times for different environments, allowing a single package to be deployed across multiple API environments.
:::
### Cross-Origin Resource Sharing (CORS) Handling
In the production environment, if CORS issues arise, you can use `nginx` to proxy the API address or enable `cors` on the backend to handle it (refer to the mock service for examples).
## API Request Configuration
The project comes with a default basic request configuration based on `axios`, provided by the `@vben/request` package. The project does not overly complicate things but simply wraps some common configurations. If there are other requirements, you can add or adjust the configurations as needed. Depending on the app, different component libraries and `store` might be used, so under the `src/api/request.ts` folder in the application directory, there are corresponding request configuration files. For example, in the `web-antd` project, there's a `src/api/request.ts` file where you can configure according to your needs.
### Request Examples
#### GET Request
```ts
import { requestClient } from '#/api/request';
export async function getUserInfoApi() {
return requestClient.get<UserInfo>('/user/info');
}
```
#### POST/PUT Request
```ts
import { requestClient } from '#/api/request';
export async function saveUserApi(user: UserInfo) {
return requestClient.post<UserInfo>('/user', user);
}
export async function saveUserApi(user: UserInfo) {
return requestClient.put<UserInfo>('/user', user);
}
export async function saveUserApi(user: UserInfo) {
const url = user.id ? `/user/${user.id}` : '/user/';
return requestClient.request<UserInfo>(url, {
data: user,
// OR PUT
method: user.id ? 'PUT' : 'POST',
});
}
```
#### DELETE Request
```ts
import { requestClient } from '#/api/request';
export async function deleteUserApi(user: UserInfo) {
return requestClient.delete<boolean>(`/user/${user.id}`, user);
}
```
### Request Configuration
The `src/api/request.ts` within the application can be configured according to the needs of your application:
```ts
/**
* This file can be adjusted according to business logic
*/
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
authenticateResponseInterceptor,
errorMessageResponseInterceptor,
RequestClient,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';
import { message } from 'ant-design-vue';
import { useAuthStore } from '#/store';
import { refreshTokenApi } from './core';
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
function createRequestClient(baseURL: string) {
const client = new RequestClient({
baseURL,
});
/**
* Re-authentication Logic
*/
async function doReAuthenticate() {
console.warn('Access token or refresh token is invalid or expired. ');
const accessStore = useAccessStore();
const authStore = useAuthStore();
accessStore.setAccessToken(null);
if (preferences.app.loginExpiredMode === 'modal') {
accessStore.setLoginExpired(true);
} else {
await authStore.logout();
}
}
/**
* Refresh token Logic
*/
async function doRefreshToken() {
const accessStore = useAccessStore();
const resp = await refreshTokenApi();
const newToken = resp.data;
accessStore.setAccessToken(newToken);
return newToken;
}
function formatToken(token: null | string) {
return token ? `Bearer ${token}` : null;
}
// Request Header Processing
client.addRequestInterceptor({
fulfilled: async (config) => {
const accessStore = useAccessStore();
config.headers.Authorization = formatToken(accessStore.accessToken);
config.headers['Accept-Language'] = preferences.app.locale;
return config;
},
});
// Deal Response Data
client.addResponseInterceptor({
fulfilled: (response) => {
const { data: responseData, status } = response;
const { code, data, message: msg } = responseData;
if (status >= 200 && status < 400 && code === 0) {
return data;
}
throw new Error(`Error ${status}: ${msg}`);
},
});
// Handling Token Expiration
client.addResponseInterceptor(
authenticateResponseInterceptor({
client,
doReAuthenticate,
doRefreshToken,
enableRefreshToken: preferences.app.enableRefreshToken,
formatToken,
}),
);
// Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
);
return client;
}
export const requestClient = createRequestClient(apiURL);
export const baseRequestClient = new RequestClient({ baseURL: apiURL });
```
### Multiple API Endpoints
To handle multiple API endpoints, simply create multiple `requestClient` instances, as follows:
```ts
const { apiURL, otherApiURL } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
);
export const requestClient = createRequestClient(apiURL);
export const otherRequestClient = createRequestClient(otherApiURL);
```
## Refresh Token
The project provides a default logic for refreshing tokens. To enable it, follow the configuration below:
- Ensure the refresh token feature is enabled
Adjust the `preferences.ts` in the corresponding application directory to ensure `enableRefreshToken='true'`.
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
enableRefreshToken: true,
},
});
```
Configure the `doRefreshToken` method in `src/api/request.ts` as follows:
```ts
// Adjust this to your token format
function formatToken(token: null | string) {
return token ? `Bearer ${token}` : null;
}
/**
* Refresh token logic
*/
async function doRefreshToken() {
const accessStore = useAccessStore();
// Adjust this to your refresh token API
const resp = await refreshTokenApi();
const newToken = resp.data;
accessStore.setAccessToken(newToken);
return newToken;
}
```
## Data Mocking
::: tip Production Environment Mock
The new version no longer supports mock in the production environment. Please use real interfaces.
:::
Mock data is an indispensable part of frontend development, serving as a key link in separating frontend and backend development. By agreeing on interfaces with the server side in advance and simulating request data and even logic, frontend development can proceed independently, without being blocked by the backend development process.
The project uses [Nitro](https://nitro.unjs.io/) for local mock data processing. The principle is to start an additional backend service locally, which is a real backend service that can handle requests and return data.
### Using Nitro
The mock service code is located in the `apps/backend-mock` directory. It does not need to be started manually and is already integrated into the project. You only need to run `pnpm dev` in the project root directory. After running successfully, the console will print `http://localhost:5320/api`, and you can access this address to view the mock service.
[Nitro](https://nitro.unjs.io/) syntax is simple, and you can configure and develop according to your needs. For specific configurations, you can refer to the [Nitro documentation](https://nitro.unjs.io/).
## Disabling Mock Service
Since mock is essentially a real backend service, if you do not need the mock service, you can configure `VITE_NITRO_MOCK=false` in the `.env.development` file in the project root directory to disable the mock service.
```bash
# .env.development
VITE_NITRO_MOCK=false
```

View File

@ -0,0 +1,511 @@
# Configuration
## Environment Variable Configuration
The project's environment variable configuration is located in the application directory under `.env`, `.env.development`, `.env.production`.
The rules are consistent with [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html). The format is as follows:
```bash
.env # Loaded in all environments
.env.local # Loaded in all environments, but ignored by git
.env.[mode] # Only loaded in the specified mode
.env.[mode].local # Only loaded in the specified mode, but ignored by git
```
::: tip
- Only variables starting with `VITE_` will be embedded into the client-side package. You can access them in the project code like this:
```ts
console.log(import.meta.env.VITE_PROT);
```
- Variables starting with `VITE_GLOB_*` will be added to the `_app.config.js` configuration file during packaging. :::
:::
## Environment Configuration Description
::: code-group
```bash [.env]
# Application title
VITE_APP_TITLE=Vben Admin
# Application namespace, used as a prefix for caching, store, etc., to ensure isolation
VITE_APP_NAMESPACE=vben-web-antd
```
```bash [.env.development]
# Port Number
VITE_PORT=5555
# Public Path for Resources, must start and end with /
VITE_BASE=/
# API URL
VITE_GLOB_API_URL=/api
# Whether to enable Nitro Mock service, true to enable, false to disable
VITE_NITRO_MOCK=true
# Whether to open devtools, true to open, false to close
VITE_DEVTOOLS=true
# Whether to inject global loading
VITE_INJECT_APP_LOADING=true
```
:::
## Dynamic Configuration in Production Environment
When executing `pnpm build` in the root directory of the monorepo, a `dist/_app.config.js` file will be automatically generated in the corresponding application and inserted into `index.html`.
`_app.config.js` is a dynamic configuration file that allows for modifications to the configuration dynamically based on different environments after the project has been built. The content is as follows:
```ts
window._VBEN_ADMIN_PRO_APP_CONF_ = {
VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api',
};
Object.freeze(window._VBEN_ADMIN_PRO_APP_CONF_);
Object.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', {
configurable: false,
writable: false,
});
```
### Purpose
`_app.config.js` is used for projects that need to dynamically modify configurations after packaging, such as API endpoints. There's no need to repackage; you can simply modify the variables in `/dist/_app.config.js` after packaging, and refresh to update the variables in the code. A `js` file is used to ensure that the configuration file is loaded early in the order.
### Usage
To access the variables inside `_app.config.js`, you need to use the `useAppConfig` method provided by `@vben/hooks`.
```ts
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
```
### Adding New
To add a new dynamically modifiable configuration item, simply follow the steps below:
- First, add the variable that needs to be dynamically configurable in the `.env` file or the corresponding development environment configuration file. The variable must start with `VITE_GLOB_*`, for example:
```bash
VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api
```
- In `packages/types/global.d.ts`, add the corresponding type definition, such as:
```ts
export interface VbenAdminProAppConfigRaw {
VITE_GLOB_API_URL: string;
VITE_GLOB_OTHER_API_URL: string; // [!code ++]
}
export interface ApplicationConfig {
apiURL: string;
otherApiURL: string; // [!code ++]
}
```
At this point, you can use the `useAppConfig` method within the project to access the newly added configuration item.
```ts
const { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
```
::: warning Warning
The `useAppConfig` method should only be used within the application and not be coupled with the internals of a package. The reason for passing `import.meta.env` and `import.meta.env.PROD` is to avoid such coupling. A pure package should avoid using variables specific to a particular build tool.
:::
## Preferences
The project offers a wide range of preference settings for dynamically configuring various features of the project:
![](/guide/preferences.png)
If you cannot find documentation for a setting, you can try configuring it yourself and then click `Copy Preferences` to override the project defaults. The configuration file is located in the application directory under `preferences.ts`, where you can override the framework's default configurations to achieve custom settings.
```ts
import { useAppConfig } from '@vben/hooks';
import { defineOverridesPreferences } from '@vben/preferences';
/**
* @description Project configuration file
* Only a part of the configuration in the project needs to be covered, and unnecessary configurations do not need to be covered. The default configuration will be automatically used
*/
export const overridesPreferences = defineOverridesPreferences({
// overrides
});
```
### Framework default configuration
::: details View the default configuration of the framework
```ts
const defaultPreferences: Preferences = {
app: {
accessMode: 'frontend',
authPageLayout: 'panel-right',
checkUpdatesInterval: 1,
colorGrayMode: false,
colorWeakMode: false,
compact: false,
contentCompact: 'wide',
defaultAvatar:
'https://unpkg.com/@vbenjs/static-source@0.1.6/source/avatar-v1.webp',
dynamicTitle: true,
enableCheckUpdates: true,
enablePreferences: true,
enableRefreshToken: false,
isMobile: false,
layout: 'sidebar-nav',
locale: 'zh-CN',
loginExpiredMode: 'modal',
name: 'Vben Admin',
preferencesButtonPosition: 'fixed',
watermark: false,
},
breadcrumb: {
enable: true,
hideOnlyOne: false,
showHome: false,
showIcon: true,
styleType: 'normal',
},
copyright: {
companyName: 'Vben',
companySiteLink: 'https://www.vben.pro',
date: '2024',
enable: true,
icp: '',
icpLink: '',
},
footer: {
enable: true,
fixed: false,
},
header: {
enable: true,
hidden: false,
mode: 'fixed',
},
logo: {
enable: true,
source: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp',
},
navigation: {
accordion: true,
split: true,
styleType: 'rounded',
},
shortcutKeys: {
enable: true,
globalLockScreen: true,
globalLogout: true,
globalPreferences: true,
globalSearch: true,
},
sidebar: {
collapsed: false,
collapsedShowTitle: false,
enable: true,
expandOnHover: true,
extraCollapse: true,
hidden: false,
width: 230,
},
tabbar: {
dragable: true,
enable: true,
height: 36,
keepAlive: true,
persist: true,
showIcon: true,
showMaximize: true,
showMore: true,
showRefresh: true,
styleType: 'chrome',
},
theme: {
builtinType: 'default',
colorDestructive: 'hsl(348 100% 61%)',
colorPrimary: 'hsl(231 98% 65%)',
colorSuccess: 'hsl(144 57% 58%)',
colorWarning: 'hsl(42 84% 61%)',
mode: 'dark',
radius: '0.5',
semiDarkHeader: false,
semiDarkSidebar: true,
},
transition: {
enable: true,
loading: true,
name: 'fade-slide',
progress: true,
},
widget: {
fullscreen: true,
globalSearch: true,
languageToggle: true,
lockScreen: true,
notification: true,
sidebarToggle: true,
themeToggle: true,
},
};
```
:::
::: details View the default configuration type of the framework
```ts
interface AppPreferences {
/** Permission mode */
accessMode: AccessModeType;
/** Layout of the login/registration page */
authPageLayout: AuthPageLayoutType;
/** Interval for checking updates */
checkUpdatesInterval: number;
/** Whether to enable gray mode */
colorGrayMode: boolean;
/** Whether to enable color weakness mode */
colorWeakMode: boolean;
/** Whether to enable compact mode */
compact: boolean;
/** Whether to enable content compact mode */
contentCompact: ContentCompactType;
// /** Default application avatar */
defaultAvatar: string;
// /** Enable dynamic title */
dynamicTitle: boolean;
/** Whether to enable update checks */
enableCheckUpdates: boolean;
/** Whether to display preferences */
enablePreferences: boolean;
/**
* @zh_CN Whether to enable refreshToken
*/
enableRefreshToken: boolean;
/** Whether it's mobile */
isMobile: boolean;
/** Layout method */
layout: LayoutType;
/** Supported languages */
locale: SupportedLanguagesType;
/** Login expiration mode */
loginExpiredMode: LoginExpiredModeType;
/** Application name */
name: string;
/** Position of the preferences button */
preferencesButtonPosition: PreferencesButtonPositionType;
/**
* @zh_CN Whether to enable watermark
*/
watermark: boolean;
}
interface BreadcrumbPreferences {
/** Whether breadcrumbs are enabled */
enable: boolean;
/** Whether to hide breadcrumbs when there is only one */
hideOnlyOne: boolean;
/** Whether the home icon in breadcrumbs is visible */
showHome: boolean;
/** Whether the icon in breadcrumbs is visible */
showIcon: boolean;
/** Breadcrumb style */
styleType: BreadcrumbStyleType;
}
interface CopyrightPreferences {
/** Copyright company name */
companyName: string;
/** Link to the copyright company's site */
companySiteLink: string;
/** Copyright date */
date: string;
/** Whether copyright is visible */
enable: boolean;
/** ICP number */
icp: string;
/** Link to the ICP */
icpLink: string;
}
interface FooterPreferences {
/** Whether the footer is visible */
enable: boolean;
/** Whether the footer is fixed */
fixed: boolean;
}
interface HeaderPreferences {
/** Whether the header is enabled */
enable: boolean;
/** Whether the header is hidden, css-hidden */
hidden: boolean;
/** Header display mode */
mode: LayoutHeaderModeType;
}
interface LogoPreferences {
/** Whether the logo is visible */
enable: boolean;
/** Logo URL */
source: string;
}
interface NavigationPreferences {
/** Navigation menu accordion mode */
accordion: boolean;
/** Whether the navigation menu is split, only effective in layout=mixed-nav */
split: boolean;
/** Navigation menu style */
styleType: NavigationStyleType;
}
interface SidebarPreferences {
/** Whether the sidebar is collapsed */
collapsed: boolean;
/** Whether to show title when sidebar is collapsed */
collapsedShowTitle: boolean;
/** Whether the sidebar is visible */
enable: boolean;
/** Menu auto-expand state */
expandOnHover: boolean;
/** Whether the sidebar extension area is collapsed */
extraCollapse: boolean;
/** Whether the sidebar is hidden - css */
hidden: boolean;
/** Sidebar width */
width: number;
}
interface ShortcutKeyPreferences {
/** Whether shortcut keys are enabled globally */
enable: boolean;
/** Whether the global lock screen shortcut is enabled */
globalLockScreen: boolean;
/** Whether the global logout shortcut is enabled */
globalLogout: boolean;
/** Whether the global preferences shortcut is enabled */
globalPreferences: boolean;
/** Whether the global search shortcut is enabled */
globalSearch: boolean;
}
interface TabbarPreferences {
/** Whether dragging of multiple tabs is enabled */
dragable: boolean;
/** Whether multiple tabs are enabled */
enable: boolean;
/** Tab height */
height: number;
/** Whether tab caching is enabled */
keepAlive: boolean;
/** Whether tabs are persistent */
persist: boolean;
/** Whether icons in multiple tabs are enabled */
showIcon: boolean;
/** Whether to show the maximize button */
showMaximize: boolean;
/** Whether to show the more button */
showMore: boolean;
/** Whether to show the refresh button */
showRefresh: boolean;
/** Tab style */
styleType: TabsStyleType;
}
interface ThemePreferences {
/** Built-in theme name */
builtinType: BuiltinThemeType;
/** Destructive color */
colorDestructive: string;
/** Primary color */
colorPrimary: string;
/** Success color */
colorSuccess: string;
/** Warning color */
colorWarning: string;
/** Current theme */
mode: ThemeModeType;
/** Radius */
radius: string;
/** Whether to enable semi-dark header (only effective when theme='light') */
semiDarkHeader: boolean;
/** Whether to enable semi-dark sidebar (only effective when theme='light') */
semiDarkSidebar: boolean;
}
interface TransitionPreferences {
/** Whether page transition animations are enabled */
enable: boolean;
// /** Whether page loading loading is enabled */
loading: boolean;
/** Page transition animation */
name: PageTransitionType | string;
/** Whether page loading progress animation is enabled */
progress: boolean;
}
interface WidgetPreferences {
/** Whether fullscreen widgets are enabled */
fullscreen: boolean;
/** Whether global search widget is enabled */
globalSearch: boolean;
/** Whether language switch widget is enabled */
languageToggle: boolean;
/** Whether lock screen functionality is enabled */
lockScreen: boolean;
/** Whether notification widget is displayed */
notification: boolean;
/** Whether sidebar show/hide widget is displayed */
sidebarToggle: boolean;
/** Whether theme switch widget is displayed */
themeToggle: boolean;
}
interface Preferences {
/** Global configuration */
app: AppPreferences;
/** Header configuration */
breadcrumb: BreadcrumbPreferences;
/** Copyright configuration */
copyright: CopyrightPreferences;
/** Footer configuration */
footer: FooterPreferences;
/** Breadcrumb configuration */
header: HeaderPreferences;
/** Logo configuration */
logo: LogoPreferences;
/** Navigation configuration */
navigation: NavigationPreferences;
/** Shortcut key configuration */
shortcutKeys: ShortcutKeyPreferences;
/** Sidebar configuration */
sidebar: SidebarPreferences;
/** Tab bar configuration */
tabbar: TabbarPreferences;
/** Theme configuration */
theme: ThemePreferences;
/** Animation configuration */
transition: TransitionPreferences;
/** Widget configuration */
widget: WidgetPreferences;
}
```
:::
::: warning Warning
- The `overridesPreferences` method only needs to override a part of the configurations in the project. There's no need to override configurations that are not needed; they will automatically use the default settings.
- Any configuration item can be overridden. You just need to override it within the `overridesPreferences` method. Do not modify the default configuration file.
:::

View File

@ -0,0 +1,106 @@
# Styles
::: tip Preface
For Vue projects, the [official documentation](https://vuejs.org/api/sfc-css-features.html#deep-selectors) already provides a detailed introduction to the syntax. Here, we mainly introduce the structure and usage of style files in the project.
:::
## Project Structure
The style files in the project are stored in `@vben/styles`, which includes some global styles, such as reset styles, global variables, etc. It inherits the styles and capabilities of `@vben-core/design` and can be overridden according to project needs.
## Scss
The project uses `scss` as the style preprocessor, allowing the use of `scss` features such as variables, functions, mixins, etc., within the project.
```vue
<style lang="scss" scoped>
$font-size: 30px;
.box {
.title {
color: green;
font-size: $font-size;
}
}
</style>
```
## Postcss
If you're not accustomed to using `scss`, you can also use `postcss`, which is a more powerful style processor that supports a wider range of plugins. The project includes the [postcss-nested](https://github.com/postcss/postcss-nested) plugin and is configured with `Css Variables`, making it a complete substitute for `scss`.
```vue
<style scoped>
.box {
--font-size: 30px;
.title {
color: green;
font-size: var(--font-size);
}
}
</style>
```
## Tailwind CSS
The project integrates [Tailwind CSS](https://tailwindcss.com/), allowing the use of `tailwindcss` class names to quickly build pages.
```vue
<template>
<div class="bg-white p-4">
<p class="text-green">hello world</p>
</div>
</template>
```
## BEM Standard
Another option to avoid style conflicts is to use the `BEM` standard. If you choose `scss`, it is recommended to use the `BEM` naming convention for better style management. The project provides a default `useNamespace` function to easily generate namespaces.
```vue
<script lang="ts" setup>
import { useNamespace } from '@vben/hooks';
const { b, e, is } = useNamespace('menu');
</script>
<template>
<div :class="[b()]">
<div :class="[e('item'), is('active', true)]">item1</div>
</div>
</template>
<style lang="scss" scoped>
// If you use it within the application, this line of code can be omitted as it has already been globally introduced in all applications
@import '@vben/styles/global';
@include b('menu') {
color: black;
@include e('item') {
background-color: black;
@include is('active') {
background-color: red;
}
}
}
</style>
```
## CSS Modules
Another solution to address style conflicts is to use the `CSS Modules` modular approach. The usage method is as follows.
```vue
<template>
<p :class="$style.red">This should be red</p>
</template>
<style module>
.red {
color: red;
}
</style>
```
For more usage, see the [CSS Modules official documentation](https://vuejs.org/api/sfc-css-features.html#css-modules).

View File

@ -0,0 +1,314 @@
---
outline: deep
---
# Access Control
The framework has built-in two types of access control methods:
- Determining whether a menu or button can be accessed based on user roles
- Determining whether a menu or button can be accessed through an API
## Frontend Access Control
**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoutes`, achieving permission filtering.
**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
### Steps
- Ensure the current mode is set to frontend access control
Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='frontend'`.
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
// Default value, optional
accessMode: 'frontend',
},
});
```
- Configure route permissions
#### If not configured, it is visible by default
```ts {3}
{
meta: {
authority: ['super'],
},
},
```
- Ensure the roles returned by the interface match the permissions in the route table
You can look under `src/store/auth` in the application to find the following code:
```ts
// Set the login user information, ensuring that userInfo.roles is an array and contains permissions from the route table
// For example: userInfo.roles=['super', 'admin']
authStore.setUserInfo(userInfo);
```
At this point, the configuration is complete. You need to ensure that the roles returned by the interface after login match the permissions in the route table; otherwise, access will not be possible.
### Menu Visible but Access Forbidden
Sometimes, we need the menu to be visible but access to it forbidden. This can be achieved by setting `menuVisibleWithForbidden` to `true`. In this case, the menu will be visible, but access will be forbidden, redirecting to a 403 page.
```ts
{
meta: {
menuVisibleWithForbidden: true,
},
},
```
## Backend Access Control
**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoutes`, realizing the dynamic generation of permissions.
**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
### Steps
- Ensure the current mode is set to backend access control
Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='backend'`.
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
accessMode: 'backend',
},
});
```
- Ensure the structure of the menu data returned by the interface is correct
You can look under `src/router/access.ts` in the application to find the following code:
```ts
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
return await generateAccessible(preferences.app.accessMode, {
fetchMenuListAsync: async () => {
// This interface is for the menu data returned by the backend
return await getAllMenus();
},
});
}
```
- Interface returns menu data, see comments for explanation
::: details Example of Interface Returning Menu Data
```ts
const dashboardMenus = [
{
// Here, 'BasicLayout' is hardcoded and cannot be changed
component: 'BasicLayout',
meta: {
order: -1,
title: 'page.dashboard.title',
},
name: 'Dashboard',
path: '/',
redirect: '/analytics',
children: [
{
name: 'Analytics',
path: '/analytics',
// Here is the path of the page, need to remove 'views/' and '.vue'
component: '/dashboard/analytics/index',
meta: {
affixTab: true,
title: 'page.dashboard.analytics',
},
},
{
name: 'Workspace',
path: '/workspace',
component: '/dashboard/workspace/index',
meta: {
title: 'page.dashboard.workspace',
},
},
],
},
];
```
:::
At this point, the configuration is complete. You need to ensure that after logging in, the format of the menu returned by the interface is correct; otherwise, access will not be possible.
## Fine-grained Control of Buttons
In some cases, we need to control the display of buttons with fine granularity. We can control the display of buttons through interfaces or roles.
### Permission Code
The permission code is the code returned by the interface. The logic to determine whether a button is displayed is located under `src/store/auth`:
```ts
const [fetchUserInfoResult, accessCodes] = await Promise.all([
fetchUserInfo(),
getAccessCodes(),
]);
userInfo = fetchUserInfoResult;
authStore.setUserInfo(userInfo);
accessStore.setAccessCodes(accessCodes);
```
Locate the `getAccessCodes` corresponding interface, which can be adjusted according to business logic.
The data structure returned by the permission code is an array of strings, for example: `['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
With the permission codes, you can use the `AccessControl` component and API provided by `@vben/access` to show and hide buttons.
#### Component Method
```vue
<script lang="ts" setup>
import { AccessControl, useAccess } from '@vben/access';
const { accessMode, hasAccessByCodes } = useAccess();
</script>
<template>
<!-- You need to specify type="code" -->
<AccessControl :codes="['AC_100100']" type="code">
<Button> Visible to Super account ["AC_1000001"] </Button>
</AccessControl>
<AccessControl :codes="['AC_100030']" type="code">
<Button> Visible to Admin account ["AC_100010"] </Button>
</AccessControl>
<AccessControl :codes="['AC_1000001']" type="code">
<Button> Visible to User account ["AC_1000001"] </Button>
</AccessControl>
<AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
<Button>
Visible to Super & Admin account ["AC_100100","AC_1000001"]
</Button>
</AccessControl>
</template>
```
#### API Method
```vue
<script lang="ts" setup>
import { AccessControl, useAccess } from '@vben/access';
const { hasAccessByCodes } = useAccess();
</script>
<template>
<Button v-if="hasAccessByCodes(['AC_100100'])">
Visible to Super account ["AC_1000001"]
</Button>
<Button v-if="hasAccessByCodes(['AC_100030'])">
Visible to Admin account ["AC_100010"]
</Button>
<Button v-if="hasAccessByCodes(['AC_1000001'])">
Visible to User account ["AC_1000001"]
</Button>
<Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
Visible to Super & Admin account ["AC_100100","AC_1000001"]
</Button>
</template>
```
#### Directive Method
```vue
<template>
<Button class="mr-4" v-access:code="['AC_100100']">
Visible to Super account ["AC_1000001"]
</Button>
<Button class="mr-4" v-access:code="['AC_100030']">
Visible to Admin account ["AC_100010"]
</Button>
<Button class="mr-4" v-access:code="['AC_1000001']">
Visible to User account ["AC_1000001"]
</Button>
<Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
Visible to Super & Admin account ["AC_100100","AC_1000001"]
</Button>
</template>
```
### Roles
The method of determining roles does not require permission codes returned by the interface; it directly determines whether buttons are displayed based on roles.
#### Component Method
```vue
<script lang="ts" setup>
import { AccessControl } from '@vben/access';
</script>
<template>
<AccessControl :codes="['super']">
<Button> Visible to Super account </Button>
</AccessControl>
<AccessControl :codes="['admin']">
<Button> Visible to Admin account </Button>
</AccessControl>
<AccessControl :codes="['user']">
<Button> Visible to User account </Button>
</AccessControl>
<AccessControl :codes="['super', 'admin']">
<Button> Super & Visible to Admin account </Button>
</AccessControl>
</template>
```
#### API Method
```vue
<script lang="ts" setup>
import { useAccess } from '@vben/access';
const { hasAccessByRoles } = useAccess();
</script>
<template>
<Button v-if="hasAccessByRoles(['super'])"> Visible to Super account </Button>
<Button v-if="hasAccessByRoles(['admin'])"> Visible to Admin account </Button>
<Button v-if="hasAccessByRoles(['user'])"> Visible to User account </Button>
<Button v-if="hasAccessByRoles(['super', 'admin'])">
Super & Visible to Admin account
</Button>
</template>
```
#### Directive Method
```vue
<template>
<Button class="mr-4" v-access:role="['super']">
Visible to Super account
</Button>
<Button class="mr-4" v-access:role="['admin']">
Visible to Admin account
</Button>
<Button class="mr-4" v-access:role="['user']">
Visible to User account
</Button>
<Button class="mr-4" v-access:role="['super', 'admin']">
Super & Visible to Admin account
</Button>
</template>
```

View File

@ -0,0 +1,48 @@
# Check Updates
## Introduction
When there are updates to the website, you might need to check for updates. The framework provides this functionality. By periodically checking for updates, you can configure the `checkUpdatesInterval` and `enableCheckUpdates` fields in your application's preferences.ts file to enable and set the interval for checking updates (in minutes).
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
// Whether to enable check for updates
enableCheckUpdates: true,
// The interval for checking updates, in minutes
checkUpdatesInterval: 1,
},
});
```
## Effect
When an update is detected, a prompt will pop up asking the user whether to refresh the page:
![check-updates](/guide/update-notice.png)
## Replacing with Other Update Checking Methods
If you need to check for updates in other ways, such as through an API to more flexibly control the update logic (such as force refresh, display update content, etc.), you can do so by modifying the `src/widgets/check-updates/check-updates.vue` file under `@vben/layouts`.
```ts
// Replace this with your update checking logic
async function getVersionTag() {
try {
const response = await fetch('/', {
cache: 'no-cache',
method: 'HEAD',
});
return (
response.headers.get('etag') || response.headers.get('last-modified')
);
} catch {
console.error('Failed to fetch version tag');
return null;
}
}
```

View File

@ -0,0 +1,84 @@
# Common Features
A collection of some commonly used features.
## Login Authentication Expiry
When the interface returns a `401` status code, the framework will consider the login authentication to have expired. Upon login timeout, it will redirect to the login page or open a login popup. This can be configured in `preferences.ts` in the application directory:
### Redirect to Login Page
Upon login timeout, it will redirect to the login page.
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
loginExpiredMode: 'page',
},
});
```
### Open Login Popup
When login times out, a login popup will open.
![login-expired](/guide/login-expired.png)
Configuration:
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
loginExpiredMode: 'model',
},
});
```
## Dynamic Title
- Default value: `true`
When enabled, the webpage title changes according to the route's `title`. You can enable or disable this in the `preferences.ts` file in your application directory.
```ts
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
dynamicTitle: true,
},
});
```
## Page Watermark
- Default value: `false`
When enabled, the webpage will display a watermark. You can enable or disable this in the `preferences.ts` file in your application directory.
```ts
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
watermark: true,
},
});
```
If you want to update the content of the watermark, you can do so. The parameters can be referred to [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/):
```ts
import { useWatermark } from '@vben/hooks';
const { destroyWatermark, updateWatermark } = useWatermark();
await updateWatermark({
// watermark content
content: 'hello my watermark',
});
```

View File

@ -0,0 +1 @@
# Layout

View File

@ -0,0 +1,44 @@
# Global Loading
Global loading refers to the loading effect that appears when the page is refreshed, usually a spinning icon:
![Global loading spinner](/guide/loading.png)
## Principle
Implemented by the `vite-plugin-inject-app-loading` plugin, the plugin injects a global `loading html` into each application.
## Disable
If you do not need global loading, you can disable it in the `.env` file:
```bash
VITE_INJECT_APP_LOADING=false
```
## Customization
If you want to customize the global loading, you can create a `loading.html` file in the application directory, at the same level as `index.html`. The plugin will automatically read and inject this HTML. You can define the style and animation of this HTML as you wish.
::: tip
- You can use the same syntax as in `index.html`, such as the `VITE_APP_TITLE` variable, to get the application's title.
- You must ensure there is an element with `id="__app-loading__"`.
- Add a `hidden` class to the element with `id="__app-loading__"`.
- You must ensure there is a `style[data-app-loading="inject-css"]` element.
```html{1,4}
<style data-app-loading="inject-css">
#__app-loading__.hidden {
pointer-events: none;
visibility: hidden;
opacity: 0;
transition: all 1s ease-out;
}
/* ... */
</style>
<div id="__app-loading__">
<!-- ... -->
<div class="title"><%= VITE_APP_TITLE %></div>
</div>
```

View File

@ -0,0 +1,227 @@
# Internationalization
The project has integrated [Vue i18n](https://kazupon.github.io/vue-i18n/), and Chinese and English language packs have been configured.
## IDE Plugin
If you are using vscode as your development tool, it is recommended to install the [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) plugin. It can help you manage internationalization copy more conveniently. After installing this plugin, you can see the corresponding language content in your code in real-time:
![](/public/guide/locale.png)
## Configure Default Language
You just need to override the default preferences. In the corresponding application, find the `src/preferences.ts` file and modify the value of `locale`:
```ts {3}
export const overridesPreferences = defineOverridesPreferences({
app: {
locale: 'en-US',
},
});
```
## Dynamic Language Switching
Switching languages consists of two parts:
- Updating preferences
- Loading the corresponding language pack
```ts
import type { SupportedLanguagesType } from '@vben/locales';
import { loadLocaleMessages } from '@vben/locales';
import { updatePreferences } from '@vben/preferences';
async function updateLocale(value: string) {
// 1. Update preferences
const locale = value as SupportedLanguagesType;
updatePreferences({
app: {
locale,
},
});
// 2. Load the corresponding language pack
await loadLocaleMessages(locale);
}
updateLocale('en-US');
```
## Adding Translation Texts
::: warning Attention
- Do not place business translation texts inside `@vben/locales` to better manage business and general translation texts.
- When adding new translation texts and multiple language packs are available, ensure to add the corresponding texts in all language packs.
:::
To add new translation texts, simply find `src/locales/langs/` in the corresponding application and add the texts accordingly, for example:
**src/locales/langs/zh-CN.ts**
````ts
```json
{
"about": {
"desc": "Vben Admin 是一个现代的管理模版。"
}
}
````
**src/locales/langs/en-US.ts**
````ts
```json
{
"about": {
"desc": "Vben Admin is a modern management template."
}
}
````
## Using Translation Texts
With `@vben/locales`, you can easily use translation texts:
### In Code
```vue
<script setup lang="ts">
import { computed } from 'vue';
import { $t } from '@vben/locales';
const items = computed(() => [{ title: $t('about.desc') }]);
</script>
<template>
<div>{{ $t('about.desc') }}</div>
<template v-for="item in items.value">
<div>{{ item.title }}</div>
</template>
</template>
```
## Adding a New Language Pack
If you need to add a new language pack, follow these steps:
- Add the corresponding language pack file in the `packages/locales/langs` directory, for example, `zh-TW.json`, and translate the respective texts.
- In the corresponding application, locate the `src/locales/langs` file and add the new language pack `zh-TW.json`.
- Add the corresponding language in `packages/constants/src/core.ts`:
```ts
export interface LanguageOption {
label: string;
value: 'en-US' | 'zh-CN'; // [!code --]
value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
}
export const SUPPORT_LANGUAGES: LanguageOption[] = [
{
label: '简体中文',
value: 'zh-CN',
},
{
label: 'English',
value: 'en-US',
},
{
label: '繁体中文', // [!code ++]
value: 'zh-TW', // [!code ++]
},
];
```
- In `packages/locales/typing.ts`, add a new TypeScript type:
```ts
export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]
export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
```
At this point, you can use the newly added language pack in the project.
## Interface Language Switching Function
If you want to disable the language switching display button on the interface, in the corresponding application, find the `src/preferences.ts` file and modify the value of `locale` accordingly:
```ts {3}
export const overridesPreferences = defineOverridesPreferences({
widget: {
languageToggle: false,
},
});
```
## Remote Loading of Language Packs
::: tip Tip
When making interface requests through the project's built-in `request` tool, the default request header will include [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), allowing the server to dynamically internationalize data based on the request header.
:::
Each application has an independent language pack that can override the general language configuration. You can remotely load the corresponding language pack by finding the `src/locales/index.ts` file in the corresponding application and modifying the `loadMessages` method accordingly:
```ts {3-4}
async function loadMessages(lang: SupportedLanguagesType) {
const [appLocaleMessages] = await Promise.all([
// Modify here to load data via a remote interface
localesMap[lang](),
loadThirdPartyMessage(lang),
]);
return appLocaleMessages.default;
}
```
## Third-Party Language Packs
Different applications may use third-party component libraries or plugins with varying internationalization methods, so they need to be handled differently. If you need to introduce a third-party language pack, you can find the `src/locales/index.ts` file in the corresponding application and modify the `loadThirdPartyMessage` method accordingly:
```ts
/**
* Load the dayjs language pack
* @param lang
*/
async function loadDayjsLocale(lang: SupportedLanguagesType) {
let locale;
switch (lang) {
case 'zh-CN': {
locale = await import('dayjs/locale/zh-cn');
break;
}
case 'en-US': {
locale = await import('dayjs/locale/en');
break;
}
// Default to using English
default: {
locale = await import('dayjs/locale/en');
}
}
if (locale) {
dayjs.locale(locale);
} else {
console.error(`Failed to load dayjs locale for ${lang}`);
}
}
```
## Removing Internationalization
Firstly, it is not recommended to remove internationalization, as it is a good development practice. However, if you really need to remove it, you can directly use Chinese copy and then retain the project's built-in language pack, which will not affect the overall development experience. The steps to remove internationalization are as follows:
- Hide the language switching button on the interface, see: [Interface Language Switching Function](#interface-language-switching-function)
- Modify the default language, see: [Configure Default Language](#configure-default-language)
- Disable `vue-i18n` warning prompts, in the `src/locales/index.ts` file, modify `missingWarn` to `false`:
```ts
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
await coreSetup(app, {
defaultLocale: preferences.app.locale,
loadMessages,
missingWarn: !import.meta.env.PROD, // [!code --]
missingWarn: false, // [!code ++]
...options,
});
}
```

View File

@ -0,0 +1,131 @@
# Login
This document explains how to customize the login page of your application.
## Login Page Adjustment
If you want to adjust the title, description, icon, and toolbar of the login page, you can do so by configuring the `props` parameter of the `AuthPageLayout` component.
![login](/guide/login.png)
You just need to configure the `props` parameter of `AuthPageLayout` in `src/router/routes/core.ts` within your application:
```ts {4-8}
{
component: AuthPageLayout,
props: {
sloganImage: "xxx/xxx.png",
pageTitle: "开箱即用的大型中后台管理系统",
pageDescription: "工程化、高性能、跨组件库的前端模版",
toolbar: true,
toolbarList: () => ['color', 'language', 'layout', 'theme'],
}
// ...
},
```
::: tip
If these configurations do not meet your needs, you can implement your own login page. Simply implement your own `AuthPageLayout`.
:::
## Login Form Adjustment
If you want to adjust the content of the login form, you can configure the `AuthenticationLogin` component parameters in `src/views/_core/authentication/login.vue` within your application:
```vue
<AuthenticationLogin
:loading="authStore.loginLoading"
password-placeholder="123456"
username-placeholder="vben"
@submit="authStore.authLogin"
/>
```
::: details AuthenticationLogin Component Props
```ts
{
/**
* @en Verification code login path
*/
codeLoginPath?: string;
/**
* @en Forget password path
*/
forgetPasswordPath?: string;
/**
* @en Whether it is in loading state
*/
loading?: boolean;
/**
* @en Password placeholder
*/
passwordPlaceholder?: string;
/**
* @en QR code login path
*/
qrCodeLoginPath?: string;
/**
* @en Registration path
*/
registerPath?: string;
/**
* @en Whether to show verification code login
*/
showCodeLogin?: boolean;
/**
* @en Whether to show forget password
*/
showForgetPassword?: boolean;
/**
* @en Whether to show QR code login
*/
showQrcodeLogin?: boolean;
/**
* @en Whether to show registration button
*/
showRegister?: boolean;
/**
* @en Whether to show remember account
*/
showRememberMe?: boolean;
/**
* @en Whether to show third-party login
*/
showThirdPartyLogin?: boolean;
/**
* @en Login box subtitle
*/
subTitle?: string;
/**
* @en Login box title
*/
title?: string;
/**
* @en Username placeholder
*/
usernamePlaceholder?: string;
}
```
:::
::: tip
If these configurations do not meet your needs, you can implement your own login form and related login logic.
:::

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
# UI Framework Switching
`Vue Admin` supports your freedom to choose the UI framework. The default UI framework for the demo site is `Ant Design Vue`, consistent with the older version. The framework also has built-in versions for `Element Plus` and `Naive UI`, allowing you to choose according to your preference.
## Adding a New UI Framework
If you want to use a different UI framework, you only need to follow these steps:
1. Create a new folder inside `apps`, for example, `apps/web-xxx`.
2. Change the `name` field in `apps/web-xxx/package.json` to `web-xxx`.
3. Remove dependencies and code from other UI frameworks and replace them with your chosen UI framework's logic, which requires minimal changes.
4. Adjust the language files within `locales`.
5. Adjust the components in `app.vue`.
6. Adapt the theme of the UI framework to match `Vben Admin`.
7. Adjust the application name in `.env`.
8. Add a `dev:xxx` script in the root directory of the repository.
9. Run `pnpm install` to install dependencies.

View File

@ -1,3 +0,0 @@
# Guide
TODO

View File

@ -0,0 +1,3 @@
# CHANGE LOG
TODO

View File

@ -0,0 +1,95 @@
---
outline: deep
---
# Quick Start {#quick-start}
## Prerequisites
::: info Environment Requirements
Before starting the project, ensure that your environment meets the following requirements:
- [Node.js](https://nodejs.org/en) version 20 or above. It is recommended to use [fnm](https://github.com/Schniz/fnm) or [nvm](https://github.com/nvm-sh/nvm) for version management.
- [Git](https://git-scm.com/) any version.
To verify if your environment meets the above requirements, you can check the versions using the following commands:
```bash
# Ensure the correct node LTS version is displayed
node -v
# Ensure the correct git version is displayed
git -v
```
:::
## Starting the Project
### Obtain the Source Code
::: code-group
```bash [GitHub]
# Clone the code
git clone https://github.com/vbenjs/vue-vben-admin.git
```
```bash [Gitee]
# Clone the code
# The Gitee repository may not have the latest code
git clone https://gitee.com/annsion/vue-vben-admin.git
```
:::
::: danger Caution
Ensure that the directory where you store the code and all its parent directories do not contain Chinese, Korean, Japanese characters, or spaces, as this may cause errors when installing dependencies and starting the project.
:::
### Install Dependencies
Open a terminal in your code directory and execute the following commands:
```bash
# Enter the project directory
cd vue-vben-admin
# Enable the project-specified version of pnpm
corepack enable
# Install dependencies
pnpm install
```
::: tip Note
The project only supports using `pnpm` for installing dependencies. By default, `corepack` will be used to install the specified version of `pnpm`.
:::
### Run the Project
Execute the following command to run the project:
```bash
# Start the project
pnpm dev
```
You will see an output similar to the following, allowing you to select the project you want to run:
```bash
◆ Select the app you need to run [dev]:
│ ● @vben/web-antd
│ ○ @vben/web-ele
│ ○ @vben/web-naive
│ ○ @vben/docs
│ ○ @vben/playground
```
Now, you can visit `http://localhost:5555` in your browser to view the project.

View File

@ -0,0 +1,3 @@
# Roadmap
TODO:

View File

@ -0,0 +1,67 @@
# Slimmed-Down Version
Starting from version `5.0`, we no longer provide slimmed-down repositories or branches. Our goal is to offer a more consistent development experience while reducing maintenance costs. Heres how we introduce our project, slim down, and remove unnecessary features.
## Application Slimming
First, identify the version of the `UI` component library you need, and then delete the corresponding applications. For example, if you choose to use `Ant Design Vue`, you can delete the other applications. Simply remove the following two folders:
```bash
apps/web-ele
apps/web-native
```
::: tip
If your project doesnt include the `UI` component library you need, you can delete all other applications and create your own new application as needed.
:::
## Demo Code Slimming
If you dont need demo code, you can simply delete the `playground` folder
## Documentation Slimming
If you dont need documentation, you can delete the `docs` folder.
## Remove Mock Service
If you dont need the `Mock` service, you can delete the `apps/backend-mock` folder. Also, remove the `VITE_NITRO_MOCK` variable from the `.env.development` file in your application.
```bash
# Whether to enable Nitro Mock service, true to enable, false to disable
VITE_NITRO_MOCK=false
```
## Installing Dependencies
Now that youve completed the slimming operations, you can install the dependencies and start your project:
```bash
# Run in the root directory
pnpm install
```
## Adjusting Commands
After slimming down, you may need to adjust commands according to your project. In the `package.json` file in the root directory, you can adjust the `scripts` field and remove any commands you dont need.
```json
{
"scripts": {
"build:antd": "pnpm run build --filter=@vben/web-antd",
"build:docs": "pnpm run build --filter=@vben/docs",
"build:ele": "pnpm run build --filter=@vben/web-ele",
"build:naive": "pnpm run build --filter=@vben/web-naive",
"build:play": "pnpm run build --filter=@vben/playground",
"dev:antd": "pnpm -F @vben/web-antd run dev",
"dev:docs": "pnpm -F @vben/docs run dev",
"dev:ele": "pnpm -F @vben/web-ele run dev",
"dev:play": "pnpm -F @vben/playground run dev",
"dev:naive": "pnpm -F @vben/web-naive run dev"
}
}
```

View File

@ -0,0 +1,51 @@
# About Vben Admin
::: info You are reading the documentation for [Vben Admin](https://github.com/vbenjs/vue-vben-admin) version `5.0`!
- Vben Admin 2.x is currently archived and only receives critical fixes.
- The new version is not compatible with the old version. If you are using the old version (v2, v3), please refer to the [Vue Vben Admin 2.x Documentation](https://doc.vvbin.cn).
- If you find any errors in the documentation, feel free to submit an issue to help us improve.
- If you just want to experience it, you can check out the [Quick Start](./quick-start.md).
:::
[Vben Admin](https://github.com/vbenjs/vue-vben-admin) is a backend solution based on [Vue 3.0](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), and [TypeScript](https://www.typescriptlang.org/), aimed at providing an out-of-the-box solution for developing medium to large-scale projects. It includes features like component re-encapsulation, utilities, hooks, dynamic menus, permission validation, multi-theme configurations, and button-level permission control. The project uses the latest frontend technology stack, making it a good starting template for quickly building enterprise-level mid- to backend product prototypes. It can also serve as an example for learning `vue3`, `vite`, `ts`, and other mainstream technologies. The project will continue to follow the latest technologies and apply them within the project.
## Features
- **Latest Technology Stack**: Developed using cutting-edge frontend technologies like `Vue 3`, `Vite`, and `TypeScript`.
- **Internationalization**: Built-in comprehensive internationalization solutions with multi-language support.
- **Permission Validation**: Comprehensive permission validation solutions, including button-level permission control.
- **Multi-Theme**: Built-in multiple theme configurations & dark mode to meet personalized needs.
- **Dynamic Menu**: Supports dynamic menus that can display based on permissions.
- **Mock Data**: High-performance local Mock data solution based on Nitro.
- **Rich Components**: Provides a wide range of components to meet most business needs.
- **Standardization**: Code quality is ensured with tools like `ESLint`, `Prettier`, `Stylelint`, `Publint`, and `CSpell`.
- **Engineering**: Development efficiency is improved with tools like `Pnpm Monorepo`, `TurboRepo`, and `Changeset`.
- **Multi-UI Library Support**: Supports mainstream UI libraries like `Ant Design Vue`, `Element Plus`, and `Vuetify`, without being restricted to a specific framework.
## Browser Support
**Local development** is recommended using the **latest version of Chrome**. **Versions below Chrome 80 are not supported**.
**Production environment** supports modern browsers, IE is not supported.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## Contribution
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) is still being actively updated. Contributions are welcome to help maintain and improve the project, aiming to create a better mid- to backend solution.
- If you wish to join us, you can provide suggestions or submit pull requests. We will invite you to join based on your activity.
::: info Join Us
If you wish to join us, you can start by contributing in the following ways, and we will invite you to join based on your activity:
- Regularly submit `PRs`.
- Provide valuable suggestions.
- Participate in discussions and help resolve some `issues`.
- Help maintain the documentation.
:::

View File

@ -0,0 +1,9 @@
# Why Choose Us?
First of all, we do not compare ourselves with other frameworks. We believe that every framework has its own characteristics and is suited for different scenarios. Our goal is to provide a simple and easy-to-use framework that allows developers to get started quickly and focus on developing business logic. Therefore, we will continue to improve and optimize our framework to offer a better experience.
## Framework History
Starting from Vue Vben Admin version 1.x, the framework has undergone numerous iterations and optimizations. From initially using `Vite 0.x` when there were no ready-made plugins available, we developed many custom plugins to bridge the gap between Webpack and Vite. Although many of these have since been replaced, our original intention has remained the same: to provide a simple and easy-to-use framework.
Although the community maintained the project for a period, we have always closely monitored the development of Vue Vben Admin. We have witnessed many developers use Vben Admin and provide valuable suggestions and feedback. We are very grateful for everyone's support and contributions, which continue to drive us to improve Vben Admin. In the new version, we have continuously collected user feedback, started anew, and optimized the framework to provide a better user experience. Our goal is to enable developers to get started quickly and focus on developing business logic.

View File

@ -0,0 +1,152 @@
# Frequently Asked Questions #{faq}
::: tip Listed are some common questions
If you have a question, you can first look here. If not found, you can search or submit your question on [GitHub Issue](https://github.com/vbenjs/vue-vben-admin/issues), or if it's a discussion-type question, you can go to [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)
:::
## Instructions
If you encounter a problem, you can start looking from the following aspects:
1. Search the corresponding module's GitHub repository [issue](https://github.com/vbenjs/vue-vben-admin/issues)
2. Search for the problem on [Google](https://www.google.com)
3. Search for the problem on [Baidu](https://www.baidu.com)
4. If you can't find the issue in the list below, you can ask in [issues](https://github.com/vbenjs/vue-vben-admin/issues)
5. If it's not a problem type and needs discussion, please go to [discussions](https://github.com/vbenjs/vue-vben-admin/discussions) to discuss
## Dependency Issues
In a `Monorepo` project, it is necessary to develop the habit of executing `pnpm install` every time you `git pull` the code, as new dependency packages are often added. The project has already configured automatic execution of `pnpm install` in `.husky/git-merge`, but sometimes there might be issues. If it does not execute automatically, it is recommended to execute it manually once.
## About Cache Update Issues
The project configuration is by default cached in `localStorage`, so some configurations may not change after a version update.
The solution is to modify the `version` number in `package.json` each time the code is updated. This is because the key for `localStorage` is based on the version number. Therefore, after an update, the configurations from a previous version will become invalid. Simply re-login to apply the new settings.
## About Modifying Configuration Files
When modifying environment files such as `.env` or the `vite.config.ts` file, Vite will automatically restart the service.
There's a chance that automatic restarts may encounter issues. Simply rerunning the project can resolve these problems.
## Errors When Running Locally
Since Vite does not transform code locally and the code uses relatively new syntax such as optional chaining, local development requires using a higher version of the browser (`Chrome 90+`).
## Blank Page After Switching Pages
This issue occurs because route switching animations are enabled, and the corresponding page component has multiple root nodes. Adding a `<div></div>` at the outermost layer of the page can solve this problem.
**Incorrect Example**
```vue
<template>
<!-- Annotations are also considered a node -->
<h1>text h1</h1>
<h2>text h2</h2>
</template>
```
**正确示例**
```vue
<template>
<div>
<h1>text h1</h1>
<h2>text h2</h2>
</div>
</template>
```
::: tip Tip
- If you want to use multiple root tags, you can disable route switching animations.
- Root comment nodes under `template` are also counted as a node.
:::
## My code works locally but not when packaged
The reason for this issue could be one of the following. You can check these reasons, and if there are other possibilities, feel free to add them:
- The variable `ctx` was used, which is not exposed in the instance type. The Vue official documentation also advises against using this property as it is intended for internal use only.
```ts
import { getCurrentInstance } from 'vue';
getCurrentInstance().ctx.xxxx;
```
## Dependency Installation Issues
- If you cannot install dependencies or the startup reports an error, you can try executing `pnpm run reinstall`.
- If you cannot install dependencies or encounter errors, you can try switching to a mobile hotspot for installing dependencies.
- If that still doesn't work, you can configure a domestic mirror for installation.
- You can also create a `.npmrc` file in the project root directory with the following content:
```bash
# .npmrc
registry = https://registry.npmmirror.com/
```
## Package File Too Large
- First, the full version will be larger because it includes many library files. You can use the simplified version for development.
- Secondly, it is recommended to enable gzip, which can reduce the size to about 1/3 of the original. Gzip can be enabled directly by the server. If so, the frontend does not need to build `.gz` format files. If the frontend has built `.gz` files, for example, with nginx, you need to enable the `gzip_static: on` option.
- While enabling gzip, you can also enable `brotli` for better compression than gzip. Both can coexist.
**Note**
- gzip_static: This module requires additional installation in nginx, as the default nginx does not include this module.
- Enabling `brotli` also requires additional nginx module installation.
## Runtime Errors
If you encounter errors similar to the following, please check that the full project path (including all parent paths) does not contain Chinese, Japanese, or Korean characters. Otherwise, you will encounter a 404 error for the path, leading to the following issue:
```ts
[vite] Failed to resolve module import "ant-design-vue/dist/antd.css-vben-adminode_modulesant-design-vuedistantd.css". (imported by /@/setup/ant-design-vue/index.ts)
```
## Console Route Warning Issue
If you see the following warning in the console, and the page `can open normally`, you can ignore this warning.
Future versions of `vue-router` may provide an option to disable this warning.
```ts
[Vue Router warn]: No match found for location with path "xxxx"
```
## Startup Error
If you encounter the following error message, please check if your nodejs version meets the requirements.
```bash
TypeError: str.matchAll is not a function
at Object.extractor (vue-vben-admin-main\node_modules@purge-icons\core\dist\index.js:146:27)
at Extract (vue-vben-admin-main\node_modules@purge-icons\core\dist\index.js:173:54)
```
## nginx Deployment
After deploying to `nginx`you might encounter the following error:
```bash
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.
```
Solution:
```bash
http {
types {
application/javascript js mjs;
}
}
```

View File

@ -0,0 +1,54 @@
# PROJECT UPDATE
## Why Can't It Be Updated Like a npm Plugin
Because the project is a complete project template, not a plugin or a package, it cannot be updated like a plugin. After you use the code, you will develop it further based on business needs, and you need to manually merge and upgrade.
## What Should I Do
The project is managed using a `Monorepo` approach and has abstracted some of the more core code, such as `packages/@core`, `packages/effects`. As long as the business code has not modified this part of the code, you can directly pull the latest code and then merge it into your branch. You only need to handle some conflicts simply. Other folders will only make some minor adjustments, which will not affect the business code.
::: tip Recommendation
It is recommended to follow the repository updates actively and merge them; do not accumulate over a long time, Otherwise, it will lead to too many merge conflicts and increase the difficulty of merging.
:::
## Updating Code Using Git
1. Clone the code
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
2. Add your company's git source address
```bash
# up is the source name, can be set arbitrarily
# gitUrl is the latest open-source code
git remote add up gitUrl;
```
3. Push the code to your company's git
```bash
# Push the code to your company
# main is the branch name, adjust according to your situation
git push up main
# Sync the company's code
# main is the branch name, adjust according to your situation
git pull up main
```
4. How to sync the latest open-source code
```bash
git pull origin main
```
::: tip Tip
When syncing the code, conflicts may occur. Just resolve the conflicts.
:::

View File

@ -0,0 +1,18 @@
# Remove Code
## Remove Code
In the corresponding application's `index.html` file, find the following code and delete it:
```html
<!-- apps/web-antd -->
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement('script');
hm.src = 'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
```

View File

@ -0,0 +1,21 @@
# Changeset
The project has integrated [changeset](https://github.com/changesets/changesets) as a version management tool. Changeset is a version management tool that helps us better manage versions, generate changelogs, and automate releases.
For detailed usage, please refer to the official documentation. If you do not need it, you can ignore it directly.
## Command Line
The changeset command is already built into the project:
### Interactively Add Changesets
```bash
pnpm run changeset
```
### Uniformly Increment Version Numbers
```bash
pnpm run version
```

View File

@ -0,0 +1,123 @@
---
outline: deep
---
# CLI
In the project, some command-line tools are provided for common operations, located in `scripts`.
## vsh
Used for some project operations, such as cleaning the project, checking the project, etc.
### Usage
```bash
pnpm vsh [command] [options]
```
### vsh check-circular
Check for circular references throughout the project. If there are circular references, the modules involved will be output to the console.
#### Usage
```bash
pnpm vsh check-circular
```
#### Options
| Option | Description |
| ---------- | --------------------------------------------------------- |
| `--staged` | Only check files in the git staging area, default `false` |
### vsh check-dep
Check the dependency situation of the entire project and output `unused dependencies`, `uninstalled dependencies` information to the console.
#### Usage
```bash
pnpm vsh check-dep
```
### vsh clean
Delete the project's `node_modules`, `dist`, `.turbo` directories, etc., to clean the project.
#### Usage
```bash
pnpm vsh clean
```
#### Options
| Option | Description |
| --- | --- |
| `-r,--recursive` | Recursively delete the entire project, default `true` |
| `--del-lock` | Whether to delete the `pnpm-lock.yaml` file, default `true` |
### vsh lint
Lint checks the project to see if the code in the project conforms to standards.
#### Usage
```bash
pnpm vsh lint
```
#### Options
| Option | Description |
| ---------- | -------------------------------------------- |
| `--format` | Check and try to fix errors, default `false` |
### vsh publint
Perform package standard checks on `Monorepo` projects to see if the packages in the project conform to standards.
#### Usage
```bash
pnpm vsh publint
```
#### Options
| Option | Description |
| --------- | ------------------------------------ |
| `--check` | Only perform checks, default `false` |
### vsh code-workspace
Generate `vben-admin.code-workspace` file. Currently, it does not need to be executed manually and will be executed automatically when code is committed.
#### Usage
```bash
pnpm vsh code-workspace
```
#### Options
| Option | Description |
| --------------- | --------------------------------------------------------- |
| `--auto-commit` | Automatically commit during `git commit`, default `false` |
| `--spaces` | Indentation format, default `2` spaces |
## turbo-run
Used to quickly execute scripts in the large repository and provide option-based interactive selection.
### Usage
```bash
pnpm turbo-run [command]
```
### turbo-run dev
Quickly execute the `dev` command and provide option-based interactive selection.

View File

@ -0,0 +1,68 @@
# Directory Explanation
The directory uses Monorepo management, and the project structure is as follows:
```bash
.
├── Dockerfile # Docker image build file
├── README.md # Project documentation
├── apps # Project applications directory
│   ├── backend-mock # Backend mock service application
│   ├── web-antd # Frontend application based on Ant Design Vue
│   ├── web-ele # Frontend application based on Element Plus
│   └── web-naive # Frontend application based on Naive UI
├── build-local-docker-image.sh # Script for building Docker images locally
├── cspell.json # CSpell configuration file
├── docs # Project documentation directory
├── eslint.config.mjs # ESLint configuration file
├── internal # Internal tools directory
│   ├── lint-configs # Code linting configurations
│   │   ├── commitlint-config # Commitlint configuration
│   │   ├── eslint-config # ESLint configuration
│   │   ├── prettier-config # Prettier configuration
│   │   └── stylelint-config # Stylelint configuration
│   ├── node-utils # Node.js tools
│   ├── tailwind-config # Tailwind configuration
│   ├── tsconfig # Common tsconfig settings
│   └── vite-config # Common Vite configuration
├── package.json # Project dependency configuration
├── packages # Project packages directory
│   ├── @core # Core package
│   │   ├── base # Base package
│   │   │   ├── design # Design related
│   │   │   ├── icons # Icons
│   │   │   ├── shared # Shared
│   │   │   └── typings # Type definitions
│   │   ├── composables # Composable APIs
│   │   ├── preferences # Preferences
│   │   └── ui-kit # UI component collection
│   │   ├── layout-ui # Layout UI
│   │   ├── menu-ui # Menu UI
│   │   ├── shadcn-ui # shadcn UI
│   │   └── tabs-ui # Tabs UI
│   ├── constants # Constants
│   ├── effects # Effects related packages
│   │   ├── access # Access control
│   │   ├── chart-ui # Chart UI
│   │   ├── common-ui # Common UI
│   │   ├── hooks # Composable APIs
│   │   ├── layouts # Layouts
│   │   └── request # Request
│   ├── icons # Icons
│   ├── locales # Internationalization
│   ├── preferences # Preferences
│   ├── stores # State management
│   ├── styles # Styles
│   ├── types # Type definitions
│   └── utils # Utilities
├── playground # Demo directory
├── pnpm-lock.yaml # pnpm lock file
├── pnpm-workspace.yaml # pnpm workspace configuration file
├── scripts # Scripts directory
│   ├── turbo-run # Turbo run script
│   └── vsh # VSH script
├── stylelint.config.mjs # Stylelint configuration file
├── turbo.json # Turbo configuration file
├── vben-admin.code-workspace # VS Code workspace configuration file
└── vitest.config.ts # Vite configuration file
```

View File

@ -0,0 +1,165 @@
# Standards
::: tip Contributing Code
- If you want to contribute code to the project, please ensure your code complies with the project's coding standards.
- If you are using `vscode`, you need to install the following plugins:
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Script code checking
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatting
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Word syntax checking
- [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - CSS formatting
:::
## Purpose
Students with basic engineering literacy always pay attention to coding standards, and code style checking (Code Linting, simply called Lint) is an important means to ensure the consistency of coding standards.
Following the corresponding coding standards has the following benefits:
- Lower bug error rate
- Efficient development efficiency
- Higher readability
## Tools
The project's configuration files are located in `internal/lint-configs`, where you can modify various lint configurations.
The project integrates the following code verification tools:
- [ESLint](https://eslint.org/) for JavaScript code checking
- [Stylelint](https://stylelint.io/) for CSS style checking
- [Prettier](https://prettier.io/) for code formatting
- [Commitlint](https://commitlint.js.org/) for checking the standard of git commit messages
- [Publint](https://publint.dev/) for checking the standard of npm packages
- [Lint Staged](https://github.com/lint-staged/lint-staged) for running code verification before git commits
- [Cspell](https://cspell.org/) for checking spelling errors
## ESLint
ESLint is a code standard and error checking tool used to identify and report syntax errors in TypeScript code.
### Command
```bash
pnpm eslint .
```
### Configuration
The ESLint configuration file is `eslint.config.mjs`, with its core configuration located in the `internal/lint-configs/eslint-config` directory, which can be modified according to project needs.
## Stylelint
Stylelint is used to check the style of CSS within the project. Coupled with the editor's auto-fix feature, it can effectively unify the CSS style within the project.
### Command
```bash
pnpm stylelint "**/*.{vue,css,less.scss}"
```
### Configuration
The Stylelint configuration file is `stylelint.config.mjs`, with its core configuration located in the `internal/lint-configs/stylelint-config` directory, which can be modified according to project needs.
## Prettier
Prettier Can be used to unify project code style, consistent indentation, single and double quotes, trailing commas, and other styles.
### Command
```bash
pnpm prettier .
```
### Configuration
The Prettier configuration file is `.prettier.mjs`, with its core configuration located in the `internal/lint-configs/prettier-config` directory, which can be modified according to project needs.
## CommitLint
In a team, everyone's git commit messages can vary widely, making it difficult to ensure standardization without a mechanism. How can standardization be achieved? You might think of using git's hook mechanism to write shell scripts to implement this. Of course, this is possible, but actually, JavaScript has a great tool for implementing this template, which is commitlint (used for verifying the standard of git commit messages).
### Configuration
The CommitLint configuration file is `.commitlintrc.mjs`, with its core configuration located in the `internal/lint-configs/commitlint-config` directory, which can be modified according to project needs.
### Git Commit Standards
Refer to [Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)
- `feat` Add new features
- `fix` Fix problems/BUGs
- `style` Code style changes that do not affect the outcome
- `perf` Optimization/performance improvement
- `refactor` Refactoring
- `revert` Revert changes
- `test` Related to tests
- `docs` Documentation/comments
- `chore` Dependency updates/scaffold configuration modifications, etc.
- `workflow` Workflow improvements
- `ci` Continuous integration
- `types` Type modifications
### Disabling Git Commit Standard Checks
If you want to disable Git commit standard checks, there are two ways:
::: code-group
```bash [Temporary disable]
git commit -m 'feat: add home page' --no-verify
```
```bash [Permanent closed]
# Comment out the following code in .husky/commit-msg to disable
pnpm exec commitlint --edit "$1" # [!code --]
```
:::
## Publint
Publint is a tool for checking the standard of npm packages, which can check whether the package version conforms to the standard, whether it conforms to the standard ESM package specification, etc.
### Command
```bash
pnpm vsh publint
```
## Cspell
Cspell is a tool for checking spelling errors, which can check for spelling errors in the code, avoiding bugs caused by spelling errors.
### Command
```bash
pnpm cspell lint \"**/*.ts\" \"**/README.md\" \".changeset/*.md\" --no-progress
```
### Configuration
The cspell configuration file is `cspell.json`, which can be modified according to project needs.
## Git Hook
Git hooks are generally combined with various lints to check code style during git commits. If the check fails, the commit will not proceed. Developers need to modify and resubmit.
### husky
One issue is that the check will verify all code, but we only want to check the code we are committing. This is where husky comes in.
The most effective solution is to perform Lint checks locally before committing. A common practice is to use husky or pre-commit to perform a Lint check before local submission.
The project defines corresponding hooks inside `.husky`.
#### How to Disable Husky
If you want to disable Husky, simply delete the .husky directory.
### lint-staged
Used for automatically fixing style issues of committed files. Its configuration file is `.lintstagedrc.mjs`, which can be modified according to project needs.

View File

@ -0,0 +1,13 @@
# Tailwind CSS
[Tailwind CSS](https://tailwindcss.com/) is a utility-first CSS framework for quickly building custom designs.
## Configuration
The project's configuration file is located in `internal/tailwind-config`, where you can modify the Tailwind CSS configuration.
::: tip Restrictions on using tailwindcss in packages
Tailwind CSS compilation will only be enabled if there is a `tailwind.config.mjs` file present in the corresponding package. Otherwise, Tailwind CSS will not be enabled. If you have a pure SDK package that does not require Tailwind CSS, you do not need to create a `tailwind.config.mjs` file.
:::

View File

@ -0,0 +1,33 @@
# Unit Testing
The project incorporates [Vitest](https://vitest.dev/) as the unit testing tool. Vitest is a test runner based on Vite, offering a simple API for writing test cases.
## Writing Test Cases
Within the project, we follow the convention of naming test files with a `.test.ts` suffix or placing them inside a `__tests__` directory. For example, if you create a `utils.ts` file, then you would create a corresponding `utils.spec.ts` file in the same directory,
```ts
// utils.test.ts
import { expect, test } from 'vitest';
import { sum } from './sum';
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
```
## Running Tests
To run the tests, execute the following command at the root of the monorepo:
```bash
pnpm test:unit
```
## Existing Unit Tests
There are already some unit test cases in the project. You can search for files ending with .test.ts to view them. When you make changes to related code, you can run the unit tests to ensure the correctness of your code. It is recommended to maintain the coverage of unit tests during the development process and to run unit tests as part of the CI/CD process to ensure tests pass before deploying the project.
Existing unit test status:
![](/guide/test.png)

View File

@ -0,0 +1,33 @@
# Vite Config
The project encapsulates a layer of Vite configuration and integrates some plugins for easy reuse across multiple packages and applications. The usage is as follows:
## Application
```ts
// vite.config.mts
import { defineConfig } from '@vben/vite-config';
export default defineConfig(async () => {
return {
application: {},
// Vite configuration, override according to the official Vite documentation
vite: {},
};
});
```
## Package
```ts
// vite.config.mts
import { defineConfig } from '@vben/vite-config';
export default defineConfig(async () => {
return {
library: {},
// Vite configuration, override according to the official Vite documentation
vite: {},
};
});
```

View File

@ -5,85 +5,72 @@ sidebar: false
hero:
name: Vben Admin
text: 企业级管理系统框架
tagline: 全新升级,开箱即用,简单高效
text: Enterprise-Level Management System Framework
tagline: Fully Upgraded, Ready to Use, Simple and Efficient
image:
src: https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp
alt: Vben Admin
actions:
- theme: brand
text: 开始
link: /guide/
text: Get Started ->
link: /en/guide/introduction/vben
- theme: alt
text: 在 GitHub 查看
text: Live Preview
link: https://www.vben.pro
- theme: alt
text: View on GitHub
link: https://github.com/vbenjs/vue-vben-admin
features:
- icon: 🚀
title: 最新技术栈
details: 基于 Vue3、Pinia、Vue Router、TypeScript、等最新技术栈。
title: Latest Technology Stack
details: Based on the latest technology stack, including Vue3, Pinia, Vue Router, TypeScript, etc.
link: /en/guide/introduction/quick-start
linkText: Get Started
- icon: 🦄
title: 丰富的配置
details: 企业级中后台前端解决方案,提供丰富的组件和模板以及 N 种偏好设置组合方案。
# link: /
# linkText: x
title: Rich Configurations
details: An enterprise-level frontend solution for middle and back-end systems, offering a wealth of components, templates, and various preference settings.
link: /en/guide/essentials/settings
linkText: Configuration Documentation
- icon: 🎨
title: 主题定制
details: 通过简单的配置,即可实现各种主题切换,满足个性化需求。
title: Theme Customization
details: Easily switch between various themes through simple configurations, catering to personalized needs.
link: /en/guide/in-depth/theme
linkText: Theme Documentation
- icon: 🌐
title: 国际化
details: 内置国际化方案,支持多语言切换,满足国际化需求。
- icon: 🚀
title: 权限管理
details: 内置权限管理方案,支持多种权限控制方式,满足各种权限需求。
title: Internationalization
details: Built-in internationalization support with multiple languages to meet global needs.
link: /en/guide/in-depth/locale
linkText: Internationalization Documentation
- icon: 🔐
title: Access Control
details: Built-in access control solutions supporting various permission management methods to meet different access requirements.
link: /en/guide/in-depth/access
linkText: Access Documentation
- title: Vite
icon:
src: /logos/vite.svg
details: 现代化的前端构建工具,快速冷启动,瞬间热更新。
details: Modern frontend build tool with fast cold start and instant hot updates.
link: https://vitejs.dev/
linkText: Official Site
- title: Shadcn UI
icon:
src: /logos/shadcn-ui.svg
details: 核心基于 Shadcn UI + Tailwindcss业务可支持任意的 UI 框架。
details: Core built on Shadcn UI + Tailwindcss, with business support for any UI framework.
link: https://www.shadcn-vue.com/
linkText: Official Site
- title: Turbo Repo
icon:
src: /logos/turborepo.svg
details: 规范且标准的大仓架构,使用 pnpm + monorepo + turbo 工程管理模式,提供企业级开发规范。
details: Standardized monorepo architecture using pnpm + monorepo + turbo for enterprise-level development standards.
link: https://turbo.build/
linkText: Official Site
- title: Nitro Mock Server
icon:
src: /logos/nitro.svg
details: 内置 Nitro Mock 服务,让你的 mock 服务更加强大。
details: Built-in Nitro Mock service makes your mock service more powerful.
link: https://nitro.unjs.io/
linkText: Official Site
---
<!-- <script setup>
import {
VPTeamPage,
VPTeamPageTitle,
VPTeamMembers,
VPTeamPageSection
} from 'vitepress/theme';
const members = [
{
avatar: 'https://avatars.githubusercontent.com/u/28132598?v=4',
name: 'Vben',
title: '创建者',
desc: 'Vben Admin以及相关生态的作者负责项目的整体开发。',
links: [
{ icon: 'github', link: 'https://github.com/anncwb' },
]
},
]
</script>
<VPTeamPage>
<VPTeamPageTitle>
<template #title>
核心成员介绍
</template>
</VPTeamPageTitle>
<VPTeamMembers
:members="members"
/>
</VPTeamPage> -->
<VbenContributors />

View File

@ -125,7 +125,7 @@ pnpm run build:analyze
运行之后,在自动打开的页面可以看到具体的体积分布,以分析哪些依赖有问题。
![](/guide/report.png)
![Build analysis report](/guide/report.png)
## 部署

View File

@ -2,7 +2,7 @@
全局 loading 指的是页面刷新时出现的加载效果,通常是一个旋转的图标:
![](/guide/loading.png)
![Global loading spinner](/guide/loading.png)
## 原理