diff --git a/.changeset/rude-gorillas-act.md b/.changeset/rude-gorillas-act.md new file mode 100644 index 0000000..d66d4d6 --- /dev/null +++ b/.changeset/rude-gorillas-act.md @@ -0,0 +1,5 @@ +--- +'@umijs/tnf': patch +--- + +feat: Support for vite bundler diff --git a/README.md b/README.md index 568e331..b5238c2 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ $ pnpm preview Config is loaded from `.tnfrc.ts` by default. - `alias: [string, string][]`: An array of alias pairs. -- `bundler: 'webpack' | 'mako'`: The bundler to use, default is `mako`. - `clickToComponent: { editor?: 'vscode' | 'vscode-insiders' | 'cursor' } | false`: Click the component to open in the editor. +- `bundler: 'webpack' | 'vite' | 'vite' | 'mako'`: The bundler to use, default is `mako`. - `devServer: { port?: number; host?: string; https?: { hosts?: string[] }; ip?: string }`: The development server configuration. - `externals: Record`: An object that maps package names to their corresponding paths. - `less: { modifyVars?: Record; globalVars?: Record; math?: 'always' | 'strict' | 'parens-division' | 'parens' | 'strict-legacy' | number; sourceMap?: any; plugins?: (string | [string, Record])[];}`: The configuration passed to lessLoader. diff --git a/src/build.ts b/src/build.ts index 763f550..5a84ff0 100644 --- a/src/build.ts +++ b/src/build.ts @@ -33,8 +33,12 @@ export async function build({ }); } - // build - const bundler = createBundler({ bundler: BundlerType.MAKO }); + const bundlerType = config.bundler + ? BundlerType[config.bundler.toUpperCase() as keyof typeof BundlerType] + : BundlerType.MAKO; + const bundler = createBundler({ + bundler: bundlerType, + }); await bundler.build({ bundlerConfig: { entry: { diff --git a/src/bundler/bundler.ts b/src/bundler/bundler.ts index d4a6e58..b686d0e 100644 --- a/src/bundler/bundler.ts +++ b/src/bundler/bundler.ts @@ -9,6 +9,7 @@ interface BundlerOpts { export enum BundlerType { MAKO = 'mako', WEBPACK = 'webpack', + VITE = 'vite', } export interface Bundler { @@ -46,6 +47,9 @@ export function createBundler(opts: BundlerOpts): Bundler { } else if (opts.bundler === BundlerType.WEBPACK) { // @ts-expect-error return (await import('./bundler_webpack.js')).default.default; + } else if (opts.bundler === BundlerType.VITE) { + // @ts-expect-error + return (await import('./bundler_vite.js')).default.default; } else { throw new Error(`Unsupported bundler ${opts.bundler}`); } diff --git a/src/bundler/bundler_vite.ts b/src/bundler/bundler_vite.ts new file mode 100644 index 0000000..ae49c32 --- /dev/null +++ b/src/bundler/bundler_vite.ts @@ -0,0 +1,62 @@ +import path from 'path'; +import { pathToFileURL } from 'url'; +import type { Bundler } from './bundler'; + +export default { + build: async (opts) => { + const { bundlerConfig, cwd } = opts; + try { + // 直接定位到 vite 包的 ESM 入口 + const viteModulePath = pathToFileURL( + path.join(cwd, 'node_modules', 'vite', 'dist', 'node', 'index.js'), + ).href; + + const { build } = await import(viteModulePath).catch((e) => { + throw new Error('Failed to import Vite, please install first vite@^6'); + }); + + // 转换 alias 格式 + const aliasConfig: Record = {}; + if (bundlerConfig.alias?.length) { + bundlerConfig.alias.forEach(([key, value]) => { + aliasConfig[key] = value; + }); + } + + await build({ + resolve: { + alias: aliasConfig, + }, + mode: bundlerConfig.mode, + build: { + rollupOptions: { + output: { + entryFileNames: '[name].js', + chunkFileNames: '[name].css', + assetFileNames: (assetInfo: any) => { + if (assetInfo.name && /\.(js|css)$/.test(assetInfo.name)) { + return '[name].[ext]'; + } + return '[name]-[hash].[ext]'; + }, + }, + input: bundlerConfig.entry, + }, + }, + css: { + preprocessorOptions: { + less: bundlerConfig.less, + }, + }, + }); + } catch (err) { + if (err instanceof Error && err.message.includes('Cannot find module')) { + throw new Error('Failed to import Vite, please install first vite@^6'); + } + throw err; + } + }, + configDevServer: async (_opts) => { + throw new Error('Not implemented'); + }, +} as Bundler; diff --git a/src/config/types.ts b/src/config/types.ts index ecf3a9c..cb63e4e 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -30,7 +30,7 @@ const RouterGeneratorConfig = z export const ConfigSchema = z.object({ alias: z.array(z.tuple([z.string(), z.string()])).optional(), - bundler: z.enum(['webpack', 'mako']).optional(), + bundler: z.enum(['webpack', 'mako', 'vite']).optional(), externals: z.record(z.string()).optional(), devServer: z .object({