feat: use simpler nitro instead of nestjs to implement mock service

This commit is contained in:
vben
2024-07-20 08:31:05 +08:00
parent 9ec91ac16d
commit 9987451647
122 changed files with 2556 additions and 2967 deletions

View File

@@ -32,7 +32,7 @@
"@commitlint/config-conventional": "^19.2.2",
"@vben/node-utils": "workspace:*",
"commitlint-plugin-function-rules": "^4.0.0",
"cz-git": "^1.9.3",
"czg": "^1.9.3"
"cz-git": "^1.9.4",
"czg": "^1.9.4"
}
}

View File

@@ -9,6 +9,8 @@ export async function ignores(): Promise<Linter.FlatConfig[]> {
'**/dist-*',
'**/*-dist',
'**/.husky',
'**/.nitro',
'**/.output',
'**/Dockerfile',
'**/package-lock.json',
'**/yarn.lock',

View File

@@ -121,10 +121,17 @@ const customConfig: Linter.FlatConfig[] = [
files: ['apps/backend-mock/**/**'],
rules: {
'@typescript-eslint/no-extraneous-class': 'off',
'n/prefer-global/buffer': 'off',
'no-console': 'off',
'unicorn/prefer-module': 'off',
},
},
{
files: ['internal/**/**'],
rules: {
'no-console': 'off',
},
},
];
export { customConfig };

View File

@@ -31,6 +31,7 @@
"@jspm/generator": "^2.1.2",
"cheerio": "1.0.0-rc.12",
"html-minifier-terser": "^7.2.0",
"nitropack": "^2.9.7",
"resolve.exports": "^2.0.2",
"vite-plugin-lib-inject-css": "^2.1.1",
"vite-plugin-pwa": "^0.20.0",

View File

@@ -33,6 +33,12 @@ function defineApplicationConfig(userConfigPromise: DefineApplicationOptions) {
isBuild,
license: true,
mode,
nitroMock: !isBuild,
nitroMockOptions: {},
print: !isBuild,
printInfoMap: {
'Vben Admin Docs': 'https://docs.vben.pro',
},
pwa: true,
...application,
});

View File

@@ -47,10 +47,8 @@ async function viteExtraAppConfigPlugin({
type: 'asset',
});
// eslint-disable-next-line no-console
console.log(colors.cyan(`✨configuration file is build successfully!`));
} catch (error) {
// eslint-disable-next-line no-console
console.log(
colors.red(
`configuration file configuration file failed to package:\n${error}`,

View File

@@ -70,7 +70,6 @@ async function viteImportMapPlugin(
if (options?.debug) {
(async () => {
for await (const { message, type } of generator.logStream()) {
// eslint-disable-next-line no-console
console.log(`${type}: ${message}`);
}
})();

View File

@@ -23,6 +23,8 @@ import { viteImportMapPlugin } from './importmap';
import { viteInjectAppLoadingPlugin } from './inject-app-loading';
import { viteMetadataPlugin } from './inject-metadata';
import { viteLicensePlugin } from './license';
import { viteNitroMockPlugin } from './nitor-mock';
import { vitePrintPlugin } from './print';
/**
* 获取条件成立的 vite 插件
@@ -99,6 +101,10 @@ async function loadApplicationPlugins(
importmapOptions,
injectAppLoading,
license,
nitroMock,
nitroMockOptions,
print,
printInfoMap,
pwa,
pwaOptions,
...commonOptions
@@ -120,6 +126,18 @@ async function loadApplicationPlugins(
];
},
},
{
condition: print,
plugins: async () => {
return [await vitePrintPlugin({ infoMap: printInfoMap })];
},
},
{
condition: nitroMock,
plugins: async () => {
return [await viteNitroMockPlugin(nitroMockOptions)];
},
},
{
condition: injectAppLoading,
plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)],

View File

@@ -15,6 +15,7 @@ function resolvePackageVersion(
async function resolveMonorepoDependencies() {
const { packages } = await getPackages();
const resultDevDependencies: Record<string, string> = {};
const resultDependencies: Record<string, string> = {};
const pkgsMeta: Record<string, string> = {};

View File

@@ -0,0 +1,89 @@
import type { PluginOption } from 'vite';
import type { NitroMockPluginOptions } from '../typing';
import { colors, consola, getPackage } from '@vben/node-utils';
import { build, createDevServer, createNitro, prepare } from 'nitropack';
const hmrKeyRe = /^runtimeConfig\.|routeRules\./;
export const viteNitroMockPlugin = ({
mockServerPackage = '@vben/backend-mock',
port = 5320,
verbose = true,
}: NitroMockPluginOptions = {}): PluginOption => {
return {
async configureServer(server) {
const pkg = await getPackage(mockServerPackage);
if (!pkg) {
consola.error(`Package ${mockServerPackage} not found.`);
return;
}
runNitroServer(pkg.dir, port, verbose);
const _printUrls = server.printUrls;
server.printUrls = () => {
_printUrls();
consola.log(
` ${colors.green('➜')} ${colors.bold('Nitro Mock Server')}: ${colors.cyan(`http://localhost:${port}/api`)}`,
);
};
},
enforce: 'pre',
name: 'vite:mock-server',
};
};
async function runNitroServer(rootDir: string, port: number, verbose: boolean) {
let nitro: any;
const reload = async () => {
if (nitro) {
consola.info('Restarting dev server...');
if ('unwatch' in nitro.options._c12) {
await nitro.options._c12.unwatch();
}
await nitro.close();
}
nitro = await createNitro(
{
dev: true,
preset: 'nitro-dev',
rootDir,
},
{
c12: {
async onUpdate({ getDiff, newConfig }) {
const diff = getDiff();
if (diff.length === 0) {
return;
}
verbose &&
consola.info(
`Nitro config updated:\n${diff
.map((entry) => ` ${entry.toString()}`)
.join('\n')}`,
);
await (diff.every((e) => hmrKeyRe.test(e.key))
? nitro.updateConfig(newConfig.config)
: reload());
},
},
watch: true,
},
);
nitro.hooks.hookOnce('restart', reload);
const server = createDevServer(nitro);
await server.listen(port, { showURL: false });
await prepare(nitro);
await build(nitro);
if (verbose) {
console.log('');
consola.success(colors.bold(colors.green('Nitro Mock Server started.')));
}
};
await reload();
}

View File

@@ -0,0 +1,28 @@
import type { PluginOption } from 'vite';
import type { PrintPluginOptions } from '../typing';
import { colors } from '@vben/node-utils';
export const vitePrintPlugin = (
options: PrintPluginOptions = {},
): PluginOption => {
const { infoMap = {} } = options;
return {
configureServer(server) {
const _printUrls = server.printUrls;
server.printUrls = () => {
_printUrls();
for (const [key, value] of Object.entries(infoMap)) {
console.log(
` ${colors.green('➜')} ${colors.bold(key)}: ${colors.cyan(value)}`,
);
}
};
},
enforce: 'pre',
name: 'vite:print-info',
};
};

View File

@@ -9,6 +9,29 @@ interface IImportMap {
[scope: string]: Record<string, string>;
};
}
interface PrintPluginOptions {
/**
* 打印的数据
*/
infoMap?: Record<string, string | undefined>;
}
interface NitroMockPluginOptions {
/**
* mock server 包名
*/
mockServerPackage?: string;
/**
* mock 服务端口
*/
port?: number;
/**
* mock 日志是否打印
*/
verbose?: boolean;
}
/**
* importmap 插件配置
@@ -71,6 +94,14 @@ interface ApplicationPluginOptions extends CommonPluginOptions {
injectGlobalScss?: boolean;
/** 是否注入版权信息 */
license?: boolean;
/** 是否开启nitro mock */
nitroMock?: boolean;
/** nitro mock 插件配置 */
nitroMockOptions?: NitroMockPluginOptions;
/** dev是否开启mock服务 */
print?: boolean;
/** 打印插件配置 */
printInfoMap?: PrintPluginOptions['infoMap'];
/** 是否开启pwa */
pwa?: boolean;
/** pwa 插件配置 */
@@ -111,4 +142,6 @@ export type {
IImportMap,
ImportmapPluginOptions,
LibraryPluginOptions,
NitroMockPluginOptions,
PrintPluginOptions,
};

View File

@@ -13,6 +13,7 @@ function getConfFiles() {
const script = process.env.npm_lifecycle_script as string;
const reg = /--mode ([\d_a-z]+)/;
const result = reg.exec(script);
if (result) {
const mode = result[1];
return ['.env', `.env.${mode}`];
@@ -64,10 +65,12 @@ async function loadAndConvertEnv(
const compressTypes = compress
.split(',')
.filter((item) => item === 'brotli' || item === 'gzip');
return {
appTitle: envConfig?.VITE_GLOB_APP_TITLE ?? 'Vben Admin',
compress: !!compress,
compressTypes: compressTypes as ('brotli' | 'gzip')[],
nitroMock: !!envConfig.VITE_NITRO_MOCK,
port: Number(envConfig.VITE_PORT) || 5173,
pwa: !!pwa,
visualizer: !!visualizer,