import { join, resolve } from 'path'; import escapeStringRegexp from 'escape-string-regexp'; import deepmerge from 'deepmerge'; import { isFile, findDefaultEntryFile } from '../utils.js'; import commonjs from '@rollup/plugin-commonjs'; import { nodeResolve } from '@rollup/plugin-node-resolve'; import postcss from 'rollup-plugin-postcss'; import alias from '@rollup/plugin-alias'; import autoprefixer from 'autoprefixer'; import swcPlugin from '../plugins/swc.js'; import dtsPlugin from '../plugins/dts.js'; import minify from '../plugins/minify.js'; import babelPlugin from '../plugins/babel.js'; import { builtinNodeModules } from './builtinModules.js'; import { TaskName } from '../types.js'; import type { Plugin as RollupPlugin, RollupOptions, OutputOptions } from 'rollup'; import type { TaskConfig, PkgContext, UserConfig } from '../types.js'; interface PkgJson { name: string; version?: string; dependencies?: Record<string, string>; peerDependencies?: Record<string, string>; [k: string]: string | Record<string, string>; } const getRollupOutputs = ({ userConfig, pkg, outputDir, isES2017, }: { userConfig: UserConfig; outputDir: string; pkg: PkgJson; isES2017: boolean; }): OutputOptions[] => { const outputs: OutputOptions[] = []; const uncompressedDevelopment = userConfig?.bundle?.development; const outputFormats = (userConfig?.bundle?.formats || []).filter((format) => format !== 'es2017') as Array<'umd' | 'esm'>; const filename = userConfig?.bundle?.filename ?? 'index'; const name = userConfig?.bundle?.name ?? pkg.name; const sourceMaps = userConfig?.sourceMaps ?? false; outputFormats.forEach((format) => { const commonOption = { name, format, sourcemap: sourceMaps, }; const filenamePrefix = `${filename}${format === 'umd' ? '.umd' : ''}${isES2017 ? '.es2017' : ''}`; outputs.push({ ...commonOption, file: join(outputDir, `${filenamePrefix}.production.js`), plugins: [minify({ minifyOption: true, sourceMaps })], }); if (uncompressedDevelopment) { outputs.push({ ...commonOption, file: join(outputDir, `${filenamePrefix}.development.js`), }); } }); return outputs; }; const getExternalsAndGlboals = (userConfig: UserConfig, pkg: PkgJson) => { let externals: string[] = []; let globals: Record<string, string> = {}; const builtinExternals = [ 'react/jsx-runtime', 'core-js', 'regenerator-runtime', ]; const userExternals = userConfig?.bundle?.externals ?? true; switch (userExternals) { case true: externals = [ ...builtinNodeModules, ...builtinExternals, ...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.peerDependencies ?? {}), ]; break; case false: externals = []; break; default: externals = Object.keys(userExternals); globals = userExternals; break; } const externalPredicate = new RegExp(`^(${externals.map(escapeStringRegexp).join('|')})($|/)`); const externalFun = externals.length === 0 ? () => false : (id: string) => externalPredicate.test(id); return [externalFun, globals]; }; export const normalizeRollupConfig = ( cfg: TaskConfig, ctx: PkgContext, taskName: TaskName, ): [RollupPlugin[], RollupOptions] => { const { swcCompileOptions, type, outputDir, rollupPlugins, rollupOptions } = cfg; const { rootDir, userConfig, pkg } = ctx; const commonPlugins = [ userConfig?.alias && alias({ entries: userConfig.alias }), userConfig?.babelPlugins?.length && babelPlugin(userConfig.babelPlugins), swcPlugin({ extraSwcOptions: swcCompileOptions, }), ].filter(Boolean); let resolvedPlugins = rollupPlugins ?? []; if (type === 'transform') { resolvedPlugins = [ // dts plugin should append ahead for obtainig source code. // And dts plugin would never change the contents of file. dtsPlugin(cfg.entry, userConfig?.generateTypesForJs), ...resolvedPlugins, ...commonPlugins, ]; return [resolvedPlugins, rollupOptions]; } if (type === 'bundle') { resolvedPlugins = [ ...resolvedPlugins, ...commonPlugins, postcss({ plugins: [autoprefixer()], extract: resolve(rootDir, outputDir, 'index.css'), autoModules: true, minimize: true, sourceMap: userConfig?.sourceMaps, }), nodeResolve(), // To locates modules using the node resolution algorithm, commonjs(), // To convert commonjs to import, make it capabile for rollup to bundle ]; const entry = isFile(cfg.entry) ? cfg.entry : findDefaultEntryFile(cfg.entry); if (!entry) { throw new Error( 'Failed to resolve entry for current project.\n' + 'This is most likely that \'src/index\' is not exist.\n' + 'Whereas @ice/pkg treats it as the default option.', ); } const [external, globals] = getExternalsAndGlboals(userConfig, pkg as PkgJson); const resolvedRollupOptions = deepmerge.all([ { input: entry, external, globals, output: getRollupOutputs({ userConfig, pkg: pkg as PkgJson, outputDir: cfg.outputDir, isES2017: taskName === TaskName.BUNDLE_ES2017, }), }, cfg.rollupOptions || {}, { plugins: [ // Custom plugins will add ahead ...(cfg?.rollupOptions?.plugins || []), ...resolvedPlugins, ], }, ]); return [resolvedPlugins, resolvedRollupOptions]; } };