UNPKG

@naiable/rollup-config

Version:

Use rollup like tsup, but opinionated my way.

227 lines (208 loc) 8.76 kB
import { dirname, join } from "node:path"; import fs from "node:fs"; import { cwd } from "node:process"; import { defu } from "defu"; import type { ExternalOption, InputOption, InputPluginOption, OutputOptions, RollupOptions } from "rollup"; import type { RollupAliasOptions } from "@rollup/plugin-alias"; import alias from "@rollup/plugin-alias"; import type { RollupCommonJSOptions } from "@rollup/plugin-commonjs"; import commonjs from "@rollup/plugin-commonjs"; import type { RollupNodeResolveOptions } from "@rollup/plugin-node-resolve"; import resolve from "@rollup/plugin-node-resolve"; import swc from "@rollup/plugin-swc"; import type { Options as RollupDTSOptions } from "rollup-plugin-dts"; import dts from "rollup-plugin-dts"; import type { FilterPattern } from "@rollup/pluginutils"; import type { RollupTypescriptOptions } from "@rollup/plugin-typescript"; import typescript from "@rollup/plugin-typescript"; import vue from "unplugin-vue/rollup"; import esbuild from "rollup-plugin-esbuild"; import type { RollupBabelInputPluginOptions, RollupBabelOutputPluginOptions } from "@rollup/plugin-babel"; import babel, { getBabelOutputPlugin } from "@rollup/plugin-babel"; import terser from "@rollup/plugin-terser"; export function writeFile(path: string, content: string): void { // 创建文件夹 const dir = dirname(path); if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); // 删除已存在的文件 if (fs.existsSync(path)) fs.unlinkSync(path); // 写入文件 fs.writeFileSync(path, content); } export interface INaiableRollupCompileTypeScriptConfig { /** Use `@rollup/plugin-typescript`! */ type: "@rollup/plugin-typescript"; /** TypeScript Options. */ typescript?: RollupTypescriptOptions; } export interface INaiableRollupCompileSWCConfig { /** Use `@rollup/plugin-swc`! */ type: "@rollup/plugin-swc"; /** SWC Options */ swc?: Parameters<typeof swc>[0]; /** Include and exclude files. */ include?: FilterPattern; /** Include and exclude files. */ exclude?: FilterPattern; } export interface INaiableRollupComplieEsbuildConfig { /** Use `rollup-plugin-esbuild`! */ type: "rollup-plugin-esbuild"; /** Esbuild Options. */ esbuild?: Parameters<typeof esbuild>[0]; } export type INaiableRollupCompileConfig = INaiableRollupCompileTypeScriptConfig | INaiableRollupCompileSWCConfig | INaiableRollupComplieEsbuildConfig; export interface INaiableBabelOptions { inputOptions?: RollupBabelInputPluginOptions | false; outputOptions?: RollupBabelOutputPluginOptions | false; } export interface INaiableRollupConfig { /** The input file. @default 'src/index.ts' */ input?: InputOption; /** The output format. @default ['cjs', 'esm'] */ output?: ("cjs" | "esm")[]; /** The output directory. @default 'dist' */ dir?: string; /** The `@rollup/plugin-alias` options. Default alias `@` to `src`. */ alias?: RollupAliasOptions | false; /** The `@rollup/plugin-commonjs` options. */ commonjs?: RollupCommonJSOptions | false; /** The `@rollup/plugin-node-resolve` options. Default extensions include `.ts`, `.tsx`, `.cjs`, `.jsx`, `.mts`, `.cts`. */ resolve?: RollupNodeResolveOptions | false; /** Use `@rollup/plugin-typescript` or `@rollup/plugin-swc` or `rollup-plugin-esbuild` ? */ compile?: INaiableRollupCompileConfig | false; /** The `d.ts` build options. */ dts?: RollupDTSOptions | false; /** The `unplugin-vue` options. */ vue?: Parameters<typeof vue>[0] | false; /** The `@rollup/plugin-babel` options. */ babel?: INaiableBabelOptions | false; /** The `@rollup/plugin-terser` options. */ terser?: Parameters<typeof terser>[0] | false; /** Use strict. @default true */ strict?: boolean; /** Source map. @default inline */ sourcemap?: boolean | "inline" | "hidden"; /** Free override rollup config */ overrides?: { /** The `Build` options. */ buildOptions?: RollupOptions; /** The `d.ts` build options. */ dtsOptions?: RollupOptions; }; /** Generate a snapshot json file when builded. */ snapshot?: { /** Enable snapshot. @default false */ enable: boolean; /** The snapshot file path. @default `rollup.config.snapshot-${new Date().toISOString()}.json` */ path?: string; }; /** Preserve modules. @default true */ preserveModules?: boolean; /** External dependencies. @default [/node_modules/] */ external?: ExternalOption; } export default function naiup(config: INaiableRollupConfig = {}): RollupOptions[] { const defaults: INaiableRollupConfig = { input: "src/index.ts", output: ["cjs", "esm"], strict: true, sourcemap: "inline", dir: "dist", alias: { entries: [{ find: "@", replacement: join(cwd(), "src") }], }, commonjs: {}, resolve: { extensions: [".mjs", ".js", ".json", ".node", /* 附加 */ ".ts", ".tsx", ".cjs", ".jsx", ".mts", ".cts"], }, compile: { type: "@rollup/plugin-typescript", typescript: {}, }, vue: { include: /\.vue$/, sourceMap: true, }, babel: false, terser: false, overrides: { buildOptions: {}, dtsOptions: {}, }, snapshot: { enable: false, path: `rollup.config.snapshot-${new Date().toISOString()}.json`, }, preserveModules: true, external: [/node_modules/], }; const finalConfig = defu(config, defaults); if (config && config.output && Array.isArray(config.output)) finalConfig.output = config.output; const finalPlugins: InputPluginOption[] = []; const finalOutputPlugins = []; if (finalConfig.alias !== false) finalPlugins.push(alias(finalConfig.alias)); if (finalConfig.commonjs !== false) finalPlugins.push(commonjs(finalConfig.commonjs)); if (finalConfig.resolve !== false) finalPlugins.push(resolve(finalConfig.resolve)); if (finalConfig.vue !== false) finalPlugins.push(vue(finalConfig.vue)); if (finalConfig.babel !== false) { if (finalConfig.babel.inputOptions !== false) finalPlugins.push(babel(finalConfig.babel.inputOptions)); if (finalConfig.babel.outputOptions !== false) finalOutputPlugins.push(getBabelOutputPlugin(finalConfig.babel.outputOptions)); } if (finalConfig.compile !== false) { const complieOptions = finalConfig.compile as INaiableRollupCompileConfig; if (complieOptions.type === "@rollup/plugin-swc") finalPlugins.push(swc(complieOptions.swc)); else if (complieOptions.type === "@rollup/plugin-typescript") finalPlugins.push(typescript(complieOptions.typescript)); else if (complieOptions.type === "rollup-plugin-esbuild") finalPlugins.push(esbuild(complieOptions.esbuild)); } if (finalConfig.terser !== false) finalOutputPlugins.push(terser(finalConfig.terser)); const defaultComputedBuildOptions: RollupOptions = { input: finalConfig.input, external: finalConfig.external, plugins: [...finalPlugins], output: [...new Set(finalConfig.output)].map((format) => ({ format, dir: join(finalConfig.dir, format), entryFileNames: `[name].${format === "cjs" ? "cjs" : "mjs"}`, strict: finalConfig.strict, sourcemap: finalConfig.sourcemap, preserveModules: finalConfig.preserveModules, plugins: [...finalOutputPlugins], })), }; let defaultComputedDtsOptions: RollupOptions | undefined; if (finalConfig.dts !== false) { defaultComputedDtsOptions = { input: finalConfig.input, external: finalConfig.external, plugins: [...finalPlugins, dts(finalConfig.dts)], output: [ ...[...new Set(finalConfig.output)].map( (format) => ({ format, dir: join(finalConfig.dir, format), entryFileNames: `[name].d.${format === "cjs" ? "cts" : "mts"}`, strict: finalConfig.strict, sourcemap: finalConfig.sourcemap, preserveModules: finalConfig.preserveModules, } as OutputOptions) ), { dir: join(finalConfig.dir, "types"), entryFileNames: "[name].d.ts", strict: finalConfig.strict, sourcemap: finalConfig.sourcemap, preserveModules: finalConfig.preserveModules, } as OutputOptions, ], }; } const finalBuildOptions = defu(finalConfig.overrides.buildOptions, defaultComputedBuildOptions); const finalDtsOptions = defaultComputedDtsOptions ? defu(finalConfig.overrides.dtsOptions, defaultComputedDtsOptions) : undefined; const returns = finalDtsOptions ? [finalBuildOptions, finalDtsOptions] : [finalBuildOptions]; if (finalConfig.snapshot.enable && finalConfig.snapshot.path) writeFile(finalConfig.snapshot.path, JSON.stringify(returns)); return returns; } export * from "./preset-app"; export * from "./preset-lib";