4.3 KiB
4.3 KiB
API 设计模式
Options 模式
面向用户的选项及其内部解析后的版本:
export interface Options {
verbose?: boolean
include?: string[]
exclude?: string[]
}
export interface ResolvedOptions extends Required<Options> {
root: string
}
function resolveOptions(options: Options = {}): ResolvedOptions {
return {
verbose: options.verbose ?? false,
include: options.include ?? ['**/*'],
exclude: options.exclude ?? ['node_modules'],
root: process.cwd(),
}
}
工厂函数
创建配置好的实例:
export function createContext(options: Options = {}) {
const resolved = resolveOptions(options)
const filter = createFilter(resolved.include, resolved.exclude)
return {
options: resolved,
filter,
transform(code: string, id: string) { /* ... */ },
async scanDirs() { /* ... */ },
}
}
// 用法
const ctx = createContext({ verbose: true })
await ctx.scanDirs()
Builder 模式
支持类型累积的可链式调用 API:
export function createBuilder<TContext = unknown>() {
return {
context<T>(): Builder<T, unknown, unknown> {
return this as any
},
input<T>(schema: T): Builder<TContext, T, unknown> {
return this as any
},
output<T>(schema: T): Builder<TContext, unknown, T> {
return this as any
},
build(): Procedure<TContext> { /* ... */ },
}
}
// 用法 - 类型在链中传递
const procedure = createBuilder()
.context<{ user: User }>()
.input(z.object({ id: z.string() }))
.build()
插件模式(unplugin)
从单一实现生成通用插件:
import { createUnplugin } from 'unplugin'
export default createUnplugin<Options>((options) => {
const ctx = createContext(options)
return {
name: 'my-plugin',
enforce: 'pre',
transformInclude(id) {
return ctx.filter(id)
},
transform(code, id) {
return ctx.transform(code, id)
},
// 特定于打包工具的钩子
vite: {
configResolved(config) { /* Vite 特有 */ },
},
webpack(compiler) {
compiler.hooks.watchRun.tap('my-plugin', () => { /* ... */ })
},
}
})
按打包工具分别导出入口:
// src/vite.ts
import unplugin from '.'
export default unplugin.vite
// src/webpack.ts
import unplugin from '.'
export default unplugin.webpack
惰性 Getter(Tree-shaking)
将特定于打包工具的代码延迟到被访问时才加载:
export function createPlugin<T>(factory: PluginFactory<T>) {
return {
get vite() { return getVitePlugin(factory) },
get webpack() { return getWebpackPlugin(factory) },
get rollup() { return getRollupPlugin(factory) },
}
}
只有被访问的 getter 会执行,其余部分被 tree-shaking 移除。
智能默认值
检测环境而非要求配置:
import { isPackageExists } from 'local-pkg'
function resolveOptions(options: Options) {
return {
vue: options.vue ?? isPackageExists('vue'),
react: options.react ?? isPackageExists('react'),
typescript: options.typescript ?? isPackageExists('typescript'),
}
}
Resolver 模式
通过函数或对象实现灵活解析:
export type Resolver = ResolverFunction | ResolverObject
export type ResolverFunction = (name: string) => ResolveResult | undefined
export interface ResolverObject {
type: 'component' | 'directive'
resolve: ResolverFunction
}
export function ElementPlusResolver(): Resolver[] {
return [
{ type: 'component', resolve: (name) => resolveComponent(name) },
{ type: 'directive', resolve: (name) => resolveDirective(name) },
]
}
Fluent API(验证)
通过克隆实现不可变性的方法链:
class Schema<T> {
private _def: SchemaDef
min(value: number): Schema<T> {
return new Schema({ ...this._def, min: value })
}
max(value: number): Schema<T> {
return new Schema({ ...this._def, max: value })
}
optional(): Schema<T | undefined> {
return new Schema({ ...this._def, optional: true })
}
}
// 用法
const schema = z.string().min(5).max(10).optional()
Barrel 导出
简洁的公开 API:
// src/index.ts
export * from './config'
export * from './types'
export { createContext } from './context'
export { default } from './plugin'