diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..dc3bc09 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 diff --git a/.env b/.env index 0ea8b00..e136e8b 100644 --- a/.env +++ b/.env @@ -1,17 +1,30 @@ -# Whether to open mock -VITE_USE_MOCK=false +# 项目基本地址 +VITE_BASE_URL=/ +# 项目名称 +VITE_APP_NAME=N-Admin +# 项目标题 +VITE_APP_TITLE=N-Admin +# 项目描述 +VITE_APP_DESC=N-Admin-UI -# public path -VITE_PUBLIC_PATH=/ - -VITE_TITLE=N-Admin -VITE_DESCRIPTION=N-Admin-UI template - -# Basic interface address SPA +# API访问地址 VITE_API_URL=/api - -# File upload address, optional +# 上传地址,optional VITE_UPLOAD_URL=/api/upload +# API接口前缀 +VITE_API_URL_PREFIX= -# Interface prefix -VITE_API_URL_PREFIX= \ No newline at end of file +# 是否开启请求代理 +VITE_HTTP_PROXY=false +# 是否开启打包文件大小结果分析 +VITE_VISUALIZER=true +# 是否开启打包压缩 +VITE_COMPRESS=false +# 压缩算法类型 +VITE_COMPRESS_TYPE=gzip +# 是否应用pwa +VITE_PWA=false +# 是否启用Markdown插件 +VITE_MARKDOWN=true +# 是否开启Mock +VITE_USE_MOCK=false \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d4e5bd3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# https://docs.github.com/cn/get-started/getting-started-with-git/configuring-git-to-handle-line-endings + +# Automatically normalize line endings (to LF) for all text-based files. +* text=auto eol=lf + +# Declare files that will always have CRLF line endings on checkout. +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary \ No newline at end of file diff --git a/.gitignore b/.gitignore index cef0d8d..689f001 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,38 @@ -.DS_Store .vite-ssg-dist .vite-ssg-temp -*.local +cypress/downloads + +node_modules +.DS_Store dist dist-ssr -node_modules -.idea/ +.cache +.turbo + +# local files +*.local +# local env files +.env.local +.env.*.local +.eslintcache + +# Log files *.log -cypress/downloads +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +# .vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +package-lock.json +pnpm-lock.yaml + +.history \ No newline at end of file diff --git a/LICENSE b/LICENSE index 670b1b3..964aa53 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-PRESENT Anthony Fu +Copyright (c) 2020-PRESENT NorthLan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/build/index.ts b/build/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/build/plugins/autoimport.ts b/build/plugins/autoimport.ts new file mode 100644 index 0000000..0a8ece9 --- /dev/null +++ b/build/plugins/autoimport.ts @@ -0,0 +1,35 @@ +import AutoImport from 'unplugin-auto-import/vite' +import { NaiveUiResolver } from 'unplugin-vue-components/resolvers' + +export default () => { + // https://github.com/antfu/unplugin-auto-import + return AutoImport({ + imports: [ + 'vue', + 'vue-router', + 'vue-i18n', + 'vue/macros', + '@vueuse/head', + '@vueuse/core', + { + 'naive-ui': [ + 'useDialog', + 'useMessage', + 'useNotification', + 'useLoadingBar', + ], + }, + ], + dts: 'src/auto-imports.d.ts', + dirs: [ + 'src/composables', + 'src/stores', + 'src/types', + 'src/api/**', + ], + vueTemplate: true, + resolvers: [ + NaiveUiResolver(), + ], + }) +} diff --git a/build/plugins/compress.ts b/build/plugins/compress.ts new file mode 100644 index 0000000..6ae4982 --- /dev/null +++ b/build/plugins/compress.ts @@ -0,0 +1,6 @@ +import ViteCompression from 'vite-plugin-compression' + +export default (viteEnv: ImportMetaEnv) => { + const { VITE_COMPRESS_TYPE = 'gzip' } = viteEnv + return ViteCompression({ algorithm: VITE_COMPRESS_TYPE }) +} diff --git a/build/plugins/index.ts b/build/plugins/index.ts new file mode 100644 index 0000000..961404f --- /dev/null +++ b/build/plugins/index.ts @@ -0,0 +1,60 @@ +import type { PluginOption } from 'vite' +import Layouts from 'vite-plugin-vue-layouts' +import Pages from 'vite-plugin-pages' +import WebfontDownload from 'vite-plugin-webfont-dl' +import VueDevTools from 'vite-plugin-vue-devtools' +import Unocss from 'unocss/vite' +import VueI18n from '@intlify/unplugin-vue-i18n/vite' + +// must +import { getRootPath } from 'build/utils' +import vueMacros from './vuemacros' +import autoImport from './autoimport' +import unplugins from './unplugins' + +// select +import visualizer from './visualizer' +import compress from './compress' +import pwa from './pwa' +import markdown from './markdown' + +export function setupVitePlugins(viteEnv: ImportMetaEnv): (PluginOption | PluginOption[])[] { + const plugins = [ + vueMacros(), + autoImport(), + // https://github.com/JohnCampionJr/vite-plugin-vue-layouts + Layouts(), + // https://github.com/hannoeru/vite-plugin-pages + Pages({ + extensions: ['vue', 'md'], + }), + // https://github.com/feat-agency/vite-plugin-webfont-dl + WebfontDownload(), + // https://github.com/webfansplz/vite-plugin-vue-devtools + VueDevTools(), + // https://github.com/antfu/unocss + // see uno.config.ts for config + Unocss(), + // https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n + VueI18n({ + runtimeOnly: true, + compositionOnly: true, + fullInstall: true, + include: [`${getRootPath()}/locales/**`], + }), + ...unplugins(viteEnv), + ] + if (viteEnv.VITE_VISUALIZER) + plugins.push(visualizer as PluginOption) + + if (viteEnv.VITE_COMPRESS) + plugins.push(compress(viteEnv)) + + if (viteEnv.VITE_PWA) + plugins.push(pwa()) + + if (viteEnv.VITE_MARKDOWN) + plugins.push(markdown(viteEnv)) + + return plugins +} diff --git a/build/plugins/markdown.ts b/build/plugins/markdown.ts new file mode 100644 index 0000000..a6c2a0e --- /dev/null +++ b/build/plugins/markdown.ts @@ -0,0 +1,28 @@ +import Markdown from 'vite-plugin-vue-markdown' +import LinkAttributes from 'markdown-it-link-attributes' +import Shiki from 'markdown-it-shiki' + +export default (viteEnv: ImportMetaEnv) => { + // https://github.com/antfu/vite-plugin-vue-markdown + // Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite + return Markdown({ + wrapperClasses: 'prose prose-sm m-auto text-left', + headEnabled: true, + markdownItSetup(md) { + // https://prismjs.com/ + md.use(Shiki, { + theme: { + light: 'vitesse-light', + dark: 'vitesse-dark', + }, + }) + md.use(LinkAttributes, { + matcher: (link: string) => /^https?:\/\//.test(link), + attrs: { + target: '_blank', + rel: 'noopener', + }, + }) + }, + }) +} diff --git a/build/plugins/pwa.ts b/build/plugins/pwa.ts new file mode 100644 index 0000000..e3e7581 --- /dev/null +++ b/build/plugins/pwa.ts @@ -0,0 +1,32 @@ +import { VitePWA } from 'vite-plugin-pwa' + +export default function setupVitePwa() { + // https://github.com/antfu/vite-plugin-pwa + return VitePWA({ + registerType: 'autoUpdate', + includeAssets: ['favicon.svg', 'safari-pinned-tab.svg'], + manifest: { + name: 'N-Admin', + short_name: 'N-Admin', + theme_color: '#ffffff', + icons: [ + { + src: '/pwa-192x192.png', + sizes: '192x192', + type: 'image/png', + }, + { + src: '/pwa-512x512.png', + sizes: '512x512', + type: 'image/png', + }, + { + src: '/pwa-512x512.png', + sizes: '512x512', + type: 'image/png', + purpose: 'any maskable', + }, + ], + }, + }) +} diff --git a/build/plugins/unplugins.ts b/build/plugins/unplugins.ts new file mode 100644 index 0000000..4ec7afa --- /dev/null +++ b/build/plugins/unplugins.ts @@ -0,0 +1,18 @@ +import Components from 'unplugin-vue-components/vite' +import { NaiveUiResolver } from 'unplugin-vue-components/resolvers' + +export default (viteEnv: ImportMetaEnv) => { + return [ + // https://github.com/antfu/unplugin-vue-components + Components({ + // allow auto load markdown components under `./src/components/` + extensions: ['vue', 'md'], + // allow auto import and register components used in markdown + include: [/\.vue$/, /\.vue\?vue/, /\.md$/], + dts: 'src/components.d.ts', + resolvers: [ + NaiveUiResolver(), + ], + }), + ] +} diff --git a/build/plugins/visualizer.ts b/build/plugins/visualizer.ts new file mode 100644 index 0000000..8f0a778 --- /dev/null +++ b/build/plugins/visualizer.ts @@ -0,0 +1,7 @@ +import { visualizer } from 'rollup-plugin-visualizer' + +export default visualizer({ + gzipSize: true, + brotliSize: true, + open: true, +}) diff --git a/build/plugins/vuemacros.ts b/build/plugins/vuemacros.ts new file mode 100644 index 0000000..4556d65 --- /dev/null +++ b/build/plugins/vuemacros.ts @@ -0,0 +1,23 @@ +import { transformShortVmodel } from '@vue-macros/short-vmodel' +import Vue from '@vitejs/plugin-vue' + +// @ts-expect-error failed to resolve types +import VueMacros from 'unplugin-vue-macros/vite' + +export default () => { + return VueMacros({ + plugins: { + vue: Vue({ + include: [/\.vue$/, /\.md$/], + reactivityTransform: true, + template: { + compilerOptions: { + nodeTransforms: [ + transformShortVmodel({ prefix: '::' }), + ], + }, + }, + }), + }, + }) +} diff --git a/build/utils/index.ts b/build/utils/index.ts new file mode 100644 index 0000000..5a4e62a --- /dev/null +++ b/build/utils/index.ts @@ -0,0 +1,16 @@ +import path from 'node:path' +import process from 'node:process' + +/** + * 获取项目根路径,不包括末尾斜杠 + */ +export function getRootPath() { + return path.resolve(process.cwd()) +} + +/** + * 获取项目src路径 + */ +export function getSrcPath(srcName = 'src') { + return `${getRootPath()}/${srcName}` +} diff --git a/index.html b/index.html index 5d00087..6b8e457 100644 --- a/index.html +++ b/index.html @@ -1,11 +1,15 @@ +
+ + +