feat: refactor Vite plugin loading mechanism and improve plugin management
All checks were successful
CI/CD Pipeline / playwright (push) Successful in 3m3s
CI/CD Pipeline / build-and-deploy (push) Successful in 2m6s

This commit is contained in:
严浩
2025-12-12 00:09:53 +08:00
parent 7f1811098f
commit 9e050306bb
21 changed files with 370 additions and 260 deletions

View File

@@ -1,10 +1,11 @@
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import vueRouter from 'unplugin-vue-router/vite';
import type { ConfigEnv, PluginOption } from 'vite';
import VueMacros from 'vue-macros/vite';
export async function loadPlugin(_configEnv: ConfigEnv): Promise<PluginOption> {
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = async (_pluginLoadOptions) => {
return [
VueMacros({
plugins: {
@@ -24,9 +25,9 @@ export async function loadPlugin(_configEnv: ConfigEnv): Promise<PluginOption> {
route.addToMeta({ _: route.fullPath });
}
},
logs: true,
logs: !true,
}),
},
}),
];
}
};

View File

@@ -1,7 +1,8 @@
import type { ConfigEnv, PluginOption } from 'vite';
import UnoCSS from 'unocss/vite';
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
return [
// https://github.com/antfu/unocss
// see uno.config.ts for config
@@ -9,4 +10,4 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
checkImport: true,
}),
];
}
};

View File

@@ -1,7 +1,8 @@
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
import type { ConfigEnv, PluginOption } from 'vite';
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
return [
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
VueI18nPlugin({
@@ -17,4 +18,4 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
// },
}),
];
}
};

View File

@@ -1,11 +1,12 @@
import type { ConfigEnv, PluginOption } from 'vite';
import Markdown from 'unplugin-vue-markdown/vite';
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
return [
// https://github.com/unplugin/unplugin-vue-markdown
Markdown({
headEnabled: true,
}),
];
}
};

View File

@@ -1,7 +1,8 @@
import type { ConfigEnv, PluginOption } from 'vite';
import MetaLayouts from 'vite-plugin-vue-meta-layouts';
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
return [
// https://github.com/dishait/vite-plugin-vue-meta-layouts
MetaLayouts({
@@ -16,4 +17,4 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
skipTopLevelRouteLayout: true, // 打开修复 https://github.com/JohnCampionJr/vite-plugin-vue-layouts/issues/134默认为 false 关闭
}),
];
}
};

View File

@@ -9,7 +9,6 @@ import Icons from 'unplugin-icons/vite';
import Components from 'unplugin-vue-components/vite';
import { VueRouterAutoImports } from 'unplugin-vue-router';
import { createUtils4uAutoImports } from 'utils4u/auto-imports';
import type { ConfigEnv, PluginOption } from 'vite';
// >>>>>
// eslint-disable-next-line import/no-duplicates
@@ -26,6 +25,8 @@ import { PrimeVueResolver } from '@primevue/auto-import-resolver';
import { VantResolver } from '@vant/auto-import-resolver';
// <<<<<
import type { LoadPluginFunction } from './_loadPlugins';
function _getNaiveUiComponentNames() {
// [dtsTsx](https://github.com/unplugin/unplugin-vue-components/pull/673/files/84e80738885cfe11298f41f070cda94a7a779276)
@@ -55,7 +56,7 @@ function _getNaiveUiComponentNames() {
return [];
}
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
return [
// https://github.com/antfu/unplugin-auto-import
AutoImport({
@@ -141,4 +142,4 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
},
}),
];
}
};

View File

@@ -1,6 +1,7 @@
import { minify as minifyHtml } from 'html-minifier-terser';
import { loadEnv } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import type { PluginOption } from 'vite';
import type { LoadPluginFunction } from './_loadPlugins';
function IndexHtmlPlugin(): PluginOption {
return {
@@ -91,8 +92,14 @@ function ___(): PluginOption {
};
}
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
export const loadPlugin: LoadPluginFunction = (pluginLoadOptions) => {
const { mode, env } = pluginLoadOptions;
// return [___()];
const env = loadEnv(_configEnv.mode, process.cwd());
if (env.VITE_BUILD_MINIFY === 'true') return IndexHtmlPlugin();
}
if (mode !== 'production') {
return { plugins: [], message: '仅在生产模式下启用' };
}
if (env.VITE_BUILD_MINIFY !== 'true') {
return { plugins: [], message: `已通过环境变量禁用: VITE_BUILD_MINIFY=${env.VITE_BUILD_MINIFY}` };
}
return IndexHtmlPlugin();
};

View File

@@ -1,16 +1,16 @@
import { consola } from 'consola';
import type { ConfigEnv, PluginOption } from 'vite';
import { vitePluginFakeServer } from 'vite-plugin-fake-server';
// https://github.com/condorheroblog/vite-plugin-fake-server?tab=readme-ov-file#usage
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
if (_configEnv.mode !== 'development') {
consola.info('fake server plugin is disabled in non-development mode.');
return [];
import type { LoadPluginFunction } from './_loadPlugins';
// https://github.com/condorheroblog/vite-plugin-fake-server?tab=readme-ov-file#usage
export const loadPlugin: LoadPluginFunction = (pluginLoadOptions) => {
const { mode } = pluginLoadOptions;
if (mode !== 'development') {
return { plugins: [], message: '仅在开发模式下启用' };
}
return vitePluginFakeServer({
basename: 'fake-api',
enableProd: true,
include: 'fake',
});
}
};

View File

@@ -1,11 +1,12 @@
import type { ConfigEnv, PluginOption } from 'vite';
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
return [
// https://github.com/FatehAK/vite-plugin-image-optimizer?tab=readme-ov-file#default-configuration
ViteImageOptimizer({
/* pass your config */
}),
];
}
};

View File

@@ -1,23 +1,27 @@
import consola from 'consola';
import type { ConfigEnv, PluginOption } from 'vite';
import vueDevTools from 'vite-plugin-vue-devtools';
export function loadPlugin(configEnv: ConfigEnv): PluginOption {
if (configEnv.mode !== 'development') {
consola.info('vue-devtools 插件仅在开发模式下使用。');
return [];
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
const { mode } = _pluginLoadOptions;
if (mode !== 'development') {
return { plugins: [], message: '仅在开发模式下启用' };
}
let launchEditor = 'code';
let message: string | undefined;
if (process.env.TERM_PROGRAM_VERSION?.toLowerCase()?.includes('insider')) {
consola.info('检测到 VSCode Insiders 环境。');
launchEditor = 'code-insiders';
message = '检测到 VSCode Insiders 环境';
}
return [
vueDevTools({
launchEditor: launchEditor,
}),
];
}
return {
plugins: [
vueDevTools({
launchEditor: launchEditor,
}),
],
message,
};
};

View File

@@ -1,16 +1,17 @@
import { cloudflare } from '@cloudflare/vite-plugin';
import { loadEnv } from 'vite';
import type {ConfigEnv, PluginOption} from 'vite';
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
const env = loadEnv(_configEnv.mode, process.cwd());
if (_configEnv.mode === 'test') {
console.log('cloudflare plugin disabled in test mode');
return [];
import type { LoadPluginFunction } from './_loadPlugins';
export const loadPlugin: LoadPluginFunction = (pluginLoadOptions) => {
const { mode, env } = pluginLoadOptions;
if (mode === 'test') {
return { plugins: [], message: '在测试模式下禁用' };
}
if (env.VITE_CLOUDFLARE_SERVER_ENABLED !== 'true') {
console.log('cloudflare plugin disabled by env');
return [];
return {
plugins: [],
message: `已通过环境变量禁用: VITE_CLOUDFLARE_SERVER_ENABLED=${env.VITE_CLOUDFLARE_SERVER_ENABLED}`,
};
}
return [cloudflare()];
}
};

View File

@@ -1,19 +1,29 @@
import boxen from 'boxen';
import consola from 'consola';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import consola from 'consola';
import { glob } from 'tinyglobby';
import type { ConfigEnv, PluginOption } from 'vite';
import { loadEnv } from 'vite';
export type LoadPluginFunction = (
configEnv: ConfigEnv & {
env: Record<string, string>;
},
) => PluginOption | LoadPluginResult;
export interface LoadPluginResult {
plugins: PluginOption;
message?: string;
}
type LoadPluginFunction = (configEnv: ConfigEnv) => PluginOption;
export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]> {
const plugins: PluginOption[] = [];
consola.start('开始加载 Vite 插件...');
const cwd = path.resolve(import.meta.dirname);
const pluginEntries = await glob('**/*.ts', {
absolute: true,
cwd: path.resolve(import.meta.dirname),
cwd,
ignore: [
'**/*.d.ts',
'**/*.disabled.ts',
@@ -24,7 +34,14 @@ export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]>
],
});
consola.info(`找到 ${pluginEntries.length} 个插件文件`);
const relativeCwd = path.relative(process.cwd(), cwd);
console.time('加载插件');
consola.log(
boxen(`正在加载 Vite 插件... (./${relativeCwd})`, {
borderStyle: 'classic',
borderColor: 'cyan',
}),
);
// 计算最长的文件名长度,用于对齐输出
const maxNameLength = Math.max(...pluginEntries.map((entry) => path.basename(entry).length));
@@ -41,20 +58,33 @@ export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]>
continue;
}
const plugin = loadPlugin(configEnv);
const env = loadEnv(configEnv.mode, process.cwd());
const result = loadPlugin({ ...configEnv, env });
// 判断是否是 LoadPluginResult 对象
const isResultObject = (val: unknown): val is LoadPluginResult =>
typeof val === 'object' && val !== null && 'plugins' in val;
const plugin = isResultObject(result) ? result.plugins : result;
const message = isResultObject(result) ? result.message : undefined;
const pluginArray = Array.isArray(plugin) ? plugin : [plugin];
const validPlugins = pluginArray.filter(Boolean);
const pluginCount = validPlugins.length;
if (pluginCount > 0) {
plugins.push(...validPlugins);
consola.success(`${paddedName} ${pluginCount} 个实例`);
const suffix = message ? ` (${message})` : '';
consola.info(`${paddedName}${pluginCount} 个实例${suffix}`);
} else if (message) {
consola.info(`${paddedName}${message}`);
} else {
consola.info(`${paddedName} 返回了空数组或无效值`);
}
}
consola.success(`✅ 总共加载了 ${plugins.length} 个插件实例`);
consola.success(` ${pluginEntries.length} 个插件文件,已加载 ${plugins.length}实例`);
console.timeEnd('加载插件');
return plugins;
}

View File

@@ -1,13 +1,16 @@
import type { ConfigEnv, PluginOption } from 'vite';
import { loadEnv } from 'vite';
import type { LoadPluginFunction } from './_loadPlugins';
export default [
// ...
] satisfies PluginOption;
export const loadPlugin: LoadPluginFunction = (_pluginLoadOptions) => {
const env = _pluginLoadOptions.env;
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
const env = loadEnv(_configEnv.mode, process.cwd());
console.debug(`env :>> `, env);
// ...
return undefined;
}
// 示例:根据环境变量禁用插件并返回消息
if (env.VITE_DEMO_ENABLED !== 'true') {
return {
plugins: [],
message: `已通过环境变量禁用: VITE_DEMO_ENABLED=${env.VITE_DEMO_ENABLED}`,
};
}
// 正常返回插件
return [];
};

View File

@@ -1,17 +0,0 @@
import type { PluginOption } from 'vite';
export default [
// // 检查是否在VS Code终端中运行
// if (process.env.TERM_PROGRAM === 'vscode' || process.env.VSCODE_PID) {
// // plugins.push(
// // // 构建后自动将dist目录打包成zip文件
// // viteArchiverPlugin({
// // addTimestamp: false, // 是否添加时间戳到输出文件名
// // format: 'zip', // 输出的压缩文件格式
// // outputDir: '', // 输出目录,默认为项目根目录
// // outputFileName: 'dist', // 输出的zip文件名不含扩展名
// // sourceDir: 'dist', // 要打包的源目录
// // }),
// // )
// }
] satisfies PluginOption;