diff --git a/package.json b/package.json index 88a6496..ee9074a 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "unplugin-vue-router": "^0.7.0", "vite": "^5.0.10", "vite-auto-import-resolvers": "^3.2.0", + "vite-layers": "^0.4.0", "vite-plugin-compression": "^0.5.1", "vite-plugin-env-types": "^0.1.3", "vite-plugin-mock": "2.9.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 14c621d..ca3bd02 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,9 @@ devDependencies: vite-auto-import-resolvers: specifier: ^3.2.0 version: 3.2.0(unplugin-auto-import@0.17.3)(vite@5.0.10) + vite-layers: + specifier: ^0.4.0 + version: 0.4.0(vite@5.0.10) vite-plugin-compression: specifier: ^0.5.1 version: 0.5.1(vite@5.0.10) @@ -8110,6 +8113,19 @@ packages: vite: 5.0.10(@types/node@20.10.6)(lightningcss@1.22.1)(terser@5.26.0) dev: true + /vite-layers@0.4.0(vite@5.0.10): + resolution: {integrity: sha512-TJT3dpOCsSmtQeK4i8VaW4ckBWqeKDdTMJwuPHlYqHcO/+HLjmKXKyNDXt0wlr0EZPBiCIqBkQOlhmdp4LvJMA==} + peerDependencies: + vite: '>=3.0.0' + dependencies: + consola: 3.2.3 + defu: 6.1.3 + jiti: 1.21.0 + kolorist: 1.8.0 + m-type-tools: 0.4.1 + vite: 5.0.10(@types/node@20.10.6)(lightningcss@1.22.1)(terser@5.26.0) + dev: true + /vite-node@1.1.0(@types/node@20.10.6)(lightningcss@1.22.1)(terser@5.26.0): resolution: {integrity: sha512-jV48DDUxGLEBdHCQvxL1mEh7+naVy+nhUUUaPAZLd3FJgXuxQiewHcfeZebbJ6onDqNGkP4r3MhQ342PRlG81Q==} engines: {node: ^18.0.0 || >=20.0.0} diff --git a/presets/index.ts b/presets/index.ts index f47504d..e412432 100644 --- a/presets/index.ts +++ b/presets/index.ts @@ -1,6 +1,4 @@ -import { isPackageExists } from 'local-pkg' import Prism from 'markdown-it-prism' -import { argv } from 'process' import UnoCss from 'unocss/vite' import AutoImport from 'unplugin-auto-import/vite' import { @@ -26,7 +24,7 @@ import Components from 'unplugin-vue-components/vite' import Markdown from 'unplugin-vue-markdown/vite' import { VueRouterAutoImports } from 'unplugin-vue-router' import Router from 'unplugin-vue-router/vite' -import { loadEnv } from 'vite' + import { AutoGenerateImports, vue3Presets } from 'vite-auto-import-resolvers' import Compression from 'vite-plugin-compression' import EnvTypes from 'vite-plugin-env-types' @@ -41,18 +39,18 @@ import Legacy from '@vitejs/plugin-legacy' import Vue from '@vitejs/plugin-vue' import Jsx from '@vitejs/plugin-vue-jsx' -import type { ComponentResolver } from 'unplugin-vue-components/types' - // 内置插件 -import { Alias, Restart, Warmup, Lightningcss } from './plugins' +import { Alias, Lightningcss, Restart, Warmup } from './plugins' +import { defaultBuildTargets, detectResolvers, useEnv } from './shared/detect' import { r } from './shared/path' -import { defaultBuildTargets } from './shared/detect' +import type { PluginOption } from 'vite' export default function () { const env = useEnv() const safelist = 'prose px-2 sm:px-0 md:prose-lg lg:prose-lg dark:prose-invert text-left w-screen prose-slate prose-img:rounded-xl prose-headings:underline prose-a:text-blue-600' - const plugins = [ + + const plugins: PluginOption[] = [ /** * 兼容不支持 esmModule 的浏览器 * https://www.npmjs.com/package/@vitejs/plugin-legacy @@ -107,11 +105,6 @@ export default function () { Layouts({ skipTopLevelRouteLayout: true, }), - /** - * 开发面板 - * https://github.com/webfansplz/vite-plugin-vue-devtools - */ - env.VITE_APP_DEV_TOOLS && VueDevTools(), /** * mock 服务 * https://github.com/vbenjs/vite-plugin-mock @@ -134,7 +127,7 @@ export default function () { names: ['RouterLink', 'RouterView'], }, ], - resolvers: normalizeResolvers({ + resolvers: detectResolvers({ onlyExist: [ [VantResolver(), 'vant'], [QuasarResolver(), 'quasar'], @@ -178,11 +171,6 @@ export default function () { // @ts-ignore algorithm: env.VITE_APP_COMPRESSINON_ALGORITHM, }), - /** - * 生产环境下移除 console.log, console.warn, console.error - * https://github.com/dishait/vite-plugin-removelog - */ - process.env.NODE_ENV !== 'debug' && Removelog(), /** * 别名插件 (内置) * 支持 `~` 和 `@` 别名到 `src` @@ -193,16 +181,53 @@ export default function () { * 如果 package.json 或 pnpm-lock.yaml 更新的话,强制重启 */ Restart(), + /** + * css 原子引擎 + * https://github.com/unocss/unocss + */ + UnoCss({ + safelist: env.VITE_APP_MARKDOWN ? safelist.split(' ') : undefined, + }), ] + /** + * 开发面板 + * https://github.com/webfansplz/vite-plugin-vue-devtools + */ + if (env.VITE_APP_DEV_TOOLS) { + plugins.push(VueDevTools()) + } + /** + * 生产环境下移除 console.log, console.warn, console.error + * https://github.com/dishait/vite-plugin-removelog + */ + if (process.env.NODE_ENV !== 'debug') { + plugins.push(Removelog()) + } + + /** + * markdown 渲染插件 + * https://github.com/mdit-vue/unplugin-vue-markdown + */ + if (env.VITE_APP_MARKDOWN) { + plugins.push( + Markdown({ + wrapperClasses: safelist, + markdownItSetup(md) { + md.use(Prism) + }, + }), + ) + } + + /** + * api 自动按需引入 + * https://github.com/antfu/unplugin-auto-import + */ if (env.VITE_APP_API_AUTO_IMPORT) { const dirs = env.VITE_APP_DIR_API_AUTO_IMPORT ? ['src/stores/**', 'src/composables/**', 'src/api/**'] : [] - /** - * api 自动按需引入 - * https://github.com/antfu/unplugin-auto-import - */ plugins.push( AutoImport({ dirs, @@ -215,7 +240,7 @@ export default function () { }), VueRouterAutoImports, ], - resolvers: normalizeResolvers({ + resolvers: detectResolvers({ onlyExist: [ [ElementPlusResolver(), 'element-plus'], [TDesignResolver({ library: 'vue-next' }), 'tdesign-vue-next'], @@ -230,94 +255,5 @@ export default function () { ) } - if (env.VITE_APP_MARKDOWN) { - /** - * markdown 渲染插件 - * https://github.com/mdit-vue/unplugin-vue-markdown - */ - plugins.push( - Markdown({ - wrapperClasses: safelist, - markdownItSetup(md) { - md.use(Prism) - }, - }), - ) - } - /** - * css 原子引擎 - * https://github.com/unocss/unocss - */ - plugins.push( - UnoCss({ - safelist: env.VITE_APP_MARKDOWN ? safelist.split(' ') : undefined, - }), - ) - return plugins } - -// 获取环境变量 -function useEnv() { - function detectMode() { - const { NODE_ENV } = process.env - const hasModeIndex = argv.findIndex((a) => a === '--mode' || a === '-m') - if (hasModeIndex !== -1) { - return argv[hasModeIndex + 1] - } - return NODE_ENV || 'development' - } - - function stringToBoolean(v: string) { - return Boolean(v === 'true' || false) - } - - const { - VITE_APP_TITLE, - VITE_APP_DEV_TOOLS, - VITE_APP_MARKDOWN, - VITE_APP_API_AUTO_IMPORT, - VITE_APP_MOCK_IN_PRODUCTION, - VITE_APP_DIR_API_AUTO_IMPORT, - VITE_APP_COMPRESSINON_ALGORITHM, - } = loadEnv(detectMode(), '.') - - return { - VITE_APP_TITLE, - VITE_APP_COMPRESSINON_ALGORITHM, - VITE_APP_DEV_TOOLS: stringToBoolean(VITE_APP_DEV_TOOLS), - VITE_APP_MARKDOWN: stringToBoolean(VITE_APP_MARKDOWN), - VITE_APP_API_AUTO_IMPORT: stringToBoolean(VITE_APP_API_AUTO_IMPORT), - VITE_APP_MOCK_IN_PRODUCTION: stringToBoolean(VITE_APP_MOCK_IN_PRODUCTION), - VITE_APP_DIR_API_AUTO_IMPORT: stringToBoolean(VITE_APP_DIR_API_AUTO_IMPORT), - } -} - -type Arrayable = T | Array - -interface Options { - onlyExist?: [Arrayable, string][] - include?: ComponentResolver[] -} - -/** - * 规范化 resolvers - */ -export function normalizeResolvers(options: Options = {}) { - const { onlyExist = [], include = [] } = options - - const existedResolvers = [] - for (let i = 0; i < onlyExist.length; i++) { - const [resolver, packageName] = onlyExist[i] - if ( - isPackageExists(packageName, { - paths: [r('./')], - }) - ) { - existedResolvers.push(resolver) - } - } - existedResolvers.push(...include) - - return existedResolvers -} diff --git a/presets/shared/detect.ts b/presets/shared/detect.ts index a44ddc4..9af4cde 100644 --- a/presets/shared/detect.ts +++ b/presets/shared/detect.ts @@ -4,7 +4,11 @@ */ import { r } from './path' +import { loadEnv } from 'vite' import browserslist from 'browserslist' +import { detectMode } from 'vite-layers' +import { isPackageExists } from 'local-pkg' +import type { ComponentResolver } from 'unplugin-vue-components' const { loadConfig: browserslistLoadConfig } = browserslist @@ -14,3 +18,59 @@ const { loadConfig: browserslistLoadConfig } = browserslist export const defaultBuildTargets = browserslistLoadConfig({ path: r('./'), }) || ['last 2 versions and not dead, > 0.3%, Firefox ESR'] + +type Arrayable = T | Array + +interface Options { + onlyExist?: [Arrayable, string][] + include?: ComponentResolver[] +} + +/** + * 发现 resolvers + */ +export function detectResolvers(options: Options = {}) { + const { onlyExist = [], include = [] } = options + + const existedResolvers = [] + for (let i = 0; i < onlyExist.length; i++) { + const [resolver, packageName] = onlyExist[i] + if ( + isPackageExists(packageName, { + paths: [r('./')], + }) + ) { + existedResolvers.push(resolver) + } + } + existedResolvers.push(...include) + + return existedResolvers +} + +// 获取环境变量 +export function useEnv() { + function stringToBoolean(v: string) { + return Boolean(v === 'true' || false) + } + + const { + VITE_APP_TITLE, + VITE_APP_DEV_TOOLS, + VITE_APP_MARKDOWN, + VITE_APP_API_AUTO_IMPORT, + VITE_APP_MOCK_IN_PRODUCTION, + VITE_APP_DIR_API_AUTO_IMPORT, + VITE_APP_COMPRESSINON_ALGORITHM, + } = loadEnv(detectMode(), '.') + + return { + VITE_APP_TITLE, + VITE_APP_COMPRESSINON_ALGORITHM, + VITE_APP_DEV_TOOLS: stringToBoolean(VITE_APP_DEV_TOOLS), + VITE_APP_MARKDOWN: stringToBoolean(VITE_APP_MARKDOWN), + VITE_APP_API_AUTO_IMPORT: stringToBoolean(VITE_APP_API_AUTO_IMPORT), + VITE_APP_MOCK_IN_PRODUCTION: stringToBoolean(VITE_APP_MOCK_IN_PRODUCTION), + VITE_APP_DIR_API_AUTO_IMPORT: stringToBoolean(VITE_APP_DIR_API_AUTO_IMPORT), + } +}