From 70731ceb2e8df708fe172b5f8ef9b84760525334 Mon Sep 17 00:00:00 2001 From: patak-dev Date: Mon, 8 Apr 2024 15:33:33 +0200 Subject: [PATCH] refactor: lib options --- packages/vite/src/node/__tests__/dev.spec.ts | 2 +- packages/vite/src/node/build.ts | 118 ++++++++++++------- packages/vite/src/node/cli.ts | 6 +- packages/vite/src/node/config.ts | 67 +++++------ packages/vite/src/node/index.ts | 4 +- 5 files changed, 115 insertions(+), 82 deletions(-) diff --git a/packages/vite/src/node/__tests__/dev.spec.ts b/packages/vite/src/node/__tests__/dev.spec.ts index 1ade6c0adde9ea..346bebd2aac42e 100644 --- a/packages/vite/src/node/__tests__/dev.spec.ts +++ b/packages/vite/src/node/__tests__/dev.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from 'vitest' import { resolveConfig } from '..' -describe('resolveBuildOptions in dev', () => { +describe('resolveBuildEnvironmentOptions in dev', () => { test('build.rollupOptions should not have input in lib', async () => { const config = await resolveConfig( { diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index e909e4e31c01b4..a1fbadd9b0f234 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -65,7 +65,7 @@ import { webWorkerPostPlugin } from './plugins/worker' import { getHookHandler } from './plugins' import { Environment } from './environment' -export interface BuildOptions { +export interface BuildEnvironmentOptions { /** * Compatibility transform target. The transform is performed with esbuild * and the lowest supported target is es2015/es6. Note this only handles @@ -210,13 +210,6 @@ export interface BuildOptions { * @default false */ manifest?: boolean | string - /** - * Build in library mode. The value should be the global name of the lib in - * UMD mode. This will produce esm + cjs + umd bundle formats with default - * configurations that are suitable for distributing libraries. - * @default false - */ - lib?: LibraryOptions | false /** * Produce SSR oriented build. Note this requires specifying SSR entry via * `rollupOptions.input`. @@ -265,6 +258,16 @@ export interface BuildOptions { createEnvironment?: (builder: ViteBuilder, name: string) => BuildEnvironment } +export interface BuildOptions extends BuildEnvironmentOptions { + /** + * Build in library mode. The value should be the global name of the lib in + * UMD mode. This will produce esm + cjs + umd bundle formats with default + * configurations that are suitable for distributing libraries. + * @default false + */ + lib?: LibraryOptions | false +} + export interface LibraryOptions { /** * Path of library entry @@ -317,53 +320,72 @@ export type ResolveModulePreloadDependenciesFn = ( }, ) => string[] +export interface ResolvedBuildEnvironmentOptions + extends Required> { + modulePreload: false | ResolvedModulePreloadOptions +} + export interface ResolvedBuildOptions extends Required> { modulePreload: false | ResolvedModulePreloadOptions } export function resolveBuildOptions( - raw: BuildOptions | undefined, + raw: BuildOptions, logger: Logger, root: string, - environmentName: string | undefined, ): ResolvedBuildOptions { + const libMode = raw.lib ?? false + const buildOptions = resolveBuildEnvironmentOptions( + raw, + logger, + root, + undefined, + libMode, + ) + return { ...buildOptions, lib: libMode } +} + +export function resolveBuildEnvironmentOptions( + raw: BuildEnvironmentOptions, + logger: Logger, + root: string, + environmentName: string | undefined, + libMode: false | LibraryOptions = false, +): ResolvedBuildEnvironmentOptions { const deprecatedPolyfillModulePreload = raw?.polyfillModulePreload - if (raw) { - const { polyfillModulePreload, ...rest } = raw - raw = rest - if (deprecatedPolyfillModulePreload !== undefined) { - logger.warn( - 'polyfillModulePreload is deprecated. Use modulePreload.polyfill instead.', - ) - } - if ( - deprecatedPolyfillModulePreload === false && - raw.modulePreload === undefined - ) { - raw.modulePreload = { polyfill: false } - } + const { polyfillModulePreload, ...rest } = raw + raw = rest + if (deprecatedPolyfillModulePreload !== undefined) { + logger.warn( + 'polyfillModulePreload is deprecated. Use modulePreload.polyfill instead.', + ) + } + if ( + deprecatedPolyfillModulePreload === false && + raw.modulePreload === undefined + ) { + raw.modulePreload = { polyfill: false } } - const modulePreload = raw?.modulePreload + const modulePreload = raw.modulePreload const defaultModulePreload = { polyfill: true, } - const defaultBuildOptions: BuildOptions = { + const defaultBuildEnvironmentOptions: BuildEnvironmentOptions = { outDir: 'dist', assetsDir: 'assets', assetsInlineLimit: DEFAULT_ASSETS_INLINE_LIMIT, - cssCodeSplit: !raw?.lib, + cssCodeSplit: !libMode, sourcemap: false, rollupOptions: {}, - minify: raw?.ssr ? false : 'esbuild', + minify: raw.ssr ? false : 'esbuild', terserOptions: {}, write: true, emptyOutDir: null, copyPublicDir: true, manifest: false, - lib: false, ssr: false, ssrManifest: false, ssrEmitAssets: false, @@ -373,24 +395,24 @@ export function resolveBuildOptions( watch: null, } - const userBuildOptions = raw - ? mergeConfig(defaultBuildOptions, raw) - : defaultBuildOptions + const userBuildEnvironmentOptions = raw + ? mergeConfig(defaultBuildEnvironmentOptions, raw) + : defaultBuildEnvironmentOptions // @ts-expect-error Fallback options instead of merging - const resolved: ResolvedBuildOptions = { + const resolved: ResolvedBuildEnvironmentOptions = { target: 'modules', cssTarget: false, - ...userBuildOptions, + ...userBuildEnvironmentOptions, commonjsOptions: { include: [/node_modules/], extensions: ['.js', '.cjs'], - ...userBuildOptions.commonjsOptions, + ...userBuildEnvironmentOptions.commonjsOptions, }, dynamicImportVarsOptions: { warnOnError: true, exclude: [/node_modules/], - ...userBuildOptions.dynamicImportVarsOptions, + ...userBuildEnvironmentOptions.dynamicImportVarsOptions, }, // Resolve to false | object modulePreload: @@ -489,22 +511,37 @@ export async function build( {}, { ...inlineConfig, plugins: () => inlineConfig.plugins ?? [] }, ) - const ssr = !!builder.config.build.ssr - const environment = builder.environments[ssr ? 'ssr' : 'client'] - return builder.build(environment) + + if (builder.config.build.lib) { + // TODO: temporal workaround. Should we support `libraries: Record` + // to build multiple libraries and be able to target different environments (for example for a Svelte components + // library generating both client and SSR builds)? + return buildEnvironment( + builder.config, + builder.environments.client, + builder.config.build.lib, + ) + } else { + const ssr = !!builder.config.build.ssr + const environment = builder.environments[ssr ? 'ssr' : 'client'] + return builder.build(environment) + } } function resolveConfigToBuild(inlineConfig: InlineConfig = {}) { return resolveConfig(inlineConfig, 'build', 'production', 'production') } +/** + * Build an App environment, or a App library (if librayOptions is provided) + **/ export async function buildEnvironment( config: ResolvedConfig, environment: BuildEnvironment, + libOptions: LibraryOptions | false = false, ): Promise { const options = config.build const ssr = environment.name !== 'client' - const libOptions = options.lib config.logger.info( colors.cyan( @@ -623,6 +660,7 @@ export async function buildEnvironment( } /** + * TODO: * if (ssr.target === 'webworker') { * build.rollupOptions.entryFileNames = '[name].js' * build.rollupOptions.inlineDynamicImports = (typeof input === 'string' || Object.keys(input).length === 1)) diff --git a/packages/vite/src/node/cli.ts b/packages/vite/src/node/cli.ts index 45e4af19e4f9a5..2389a0472c2500 100644 --- a/packages/vite/src/node/cli.ts +++ b/packages/vite/src/node/cli.ts @@ -4,7 +4,7 @@ import { performance } from 'node:perf_hooks' import { cac } from 'cac' import colors from 'picocolors' import { VERSION } from './constants' -import type { BuildOptions } from './build' +import type { BuildEnvironmentOptions } from './build' import type { ServerOptions } from './server' import type { CLIShortcut } from './shortcuts' import type { LogLevel } from './logger' @@ -287,12 +287,12 @@ cli .action( async ( root: string, - options: BuildOptions & BuilderCLIOptions & GlobalCLIOptions, + options: BuildEnvironmentOptions & BuilderCLIOptions & GlobalCLIOptions, ) => { filterDuplicateOptions(options) const { build, createViteBuilder } = await import('./build') - const buildOptions: BuildOptions = cleanGlobalCLIOptions( + const buildOptions: BuildEnvironmentOptions = cleanGlobalCLIOptions( cleanBuilderCLIOptions(options), ) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index f7291c03b01c91..23b776025128f8 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -22,13 +22,19 @@ import { } from './constants' import type { HookHandler, Plugin, PluginWithRequiredHook } from './plugin' import type { + BuildEnvironmentOptions, BuildOptions, BuilderOptions, RenderBuiltAssetUrl, + ResolvedBuildEnvironmentOptions, ResolvedBuildOptions, ResolvedBuilderOptions, } from './build' -import { resolveBuildOptions, resolveBuilderOptions } from './build' +import { + resolveBuildEnvironmentOptions, + resolveBuildOptions, + resolveBuilderOptions, +} from './build' import type { ResolvedServerOptions, ServerOptions, @@ -135,7 +141,7 @@ export type PluginOption = | PluginOption[] | Promise -export interface DevOptions { +export interface DevEnvironmentOptions { /** * The files to be pre-transformed. Supports glob patterns. */ @@ -193,8 +199,8 @@ export interface DevOptions { // fs: { strict?: boolean, allow, deny } } -export type ResolvedDevOptions = Required< - Omit +export type ResolvedDevEnvironmentOptions = Required< + Omit > & { // TODO: Should we set the default at config time? For now, it is defined on server init createEnvironment: @@ -223,11 +229,11 @@ export interface EnvironmentOptions extends SharedEnvironmentOptions { /** * Dev specific options */ - dev?: DevOptions + dev?: DevEnvironmentOptions /** * Build specific options */ - build?: BuildOptions + build?: BuildEnvironmentOptions } export type ResolvedEnvironmentResolveOptions = @@ -237,14 +243,17 @@ export type ResolvedEnvironmentOptions = { resolve: ResolvedEnvironmentResolveOptions nodeCompatible: boolean webCompatible: boolean - dev: ResolvedDevOptions - build: ResolvedBuildOptions + dev: ResolvedDevEnvironmentOptions + build: ResolvedBuildEnvironmentOptions } export type DefaultEnvironmentOptions = Omit< EnvironmentOptions, - 'nodeCompatible' | 'webCompatible' -> + 'build' | 'nodeCompatible' | 'webCompatible' +> & { + // Includes lib mode support + build?: BuildOptions +} export interface UserConfig extends DefaultEnvironmentOptions { /** @@ -513,7 +522,7 @@ export type ResolvedConfig = Readonly< css: ResolvedCSSOptions esbuild: ESBuildOptions | false server: ResolvedServerOptions - dev: ResolvedDevOptions + dev: ResolvedDevEnvironmentOptions builder: ResolvedBuilderOptions build: ResolvedBuildOptions preview: ResolvedPreviewOptions @@ -531,11 +540,11 @@ export type ResolvedConfig = Readonly< } & PluginHookUtils > -export function resolveDevOptions( - dev: DevOptions | undefined, +export function resolveDevEnvironmentOptions( + dev: DevEnvironmentOptions | undefined, preserverSymlinks: boolean, environmentName: string | undefined, -): ResolvedDevOptions { +): ResolvedDevEnvironmentOptions { return { sourcemap: dev?.sourcemap ?? { js: true }, sourcemapIgnoreList: @@ -566,13 +575,13 @@ function resolveEnvironmentOptions( resolve, nodeCompatible: config.nodeCompatible ?? environmentName !== 'client', webCompatible: config.webCompatible ?? environmentName === 'client', - dev: resolveDevOptions( + dev: resolveDevEnvironmentOptions( config.dev, resolve.preserveSymlinks, environmentName, ), - build: resolveBuildOptions( - config.build, + build: resolveBuildEnvironmentOptions( + config.build ?? {}, logger, resolvedRoot, environmentName, @@ -906,17 +915,16 @@ export async function resolveConfig( // TODO: Deprecate and remove resolve, dev and build options at the root level of the resolved config - const resolvedDevOptions = resolveDevOptions( + const resolvedDevEnvironmentOptions = resolveDevEnvironmentOptions( config.dev, resolvedDefaultEnvironmentResolve.preserveSymlinks, undefined, // default environment ) const resolvedBuildOptions = resolveBuildOptions( - config.build, + config.build ?? {}, logger, resolvedRoot, - undefined, // default environment ) // Backward compatibility: merge config.environments.ssr back into config.ssr @@ -1134,12 +1142,13 @@ export async function resolveConfig( // Backward compatibility, users should use environment.config.dev.optimizeDeps optimizeDeps: backwardCompatibleOptimizeDeps, + ssr, + // TODO: deprecate and later remove from ResolvedConfig? resolve: resolvedDefaultEnvironmentResolve, - dev: resolvedDevOptions, + dev: resolvedDevEnvironmentOptions, build: resolvedBuildOptions, - ssr, environments: resolvedEnvironments, getSortedPlugins: undefined!, @@ -1239,20 +1248,6 @@ export async function resolveConfig( // validate config - if ( - config.build?.terserOptions && - config.build.minify && - config.build.minify !== 'terser' - ) { - logger.warn( - colors.yellow( - `build.terserOptions is specified but build.minify is not set to use Terser. ` + - `Note Vite now defaults to use esbuild for minification. If you still ` + - `prefer Terser, set build.minify to "terser".`, - ), - ) - } - // Check if all assetFileNames have the same reference. // If not, display a warn for user. const outputOption = config.build?.rollupOptions?.output ?? [] diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 1b42fa6fb91239..109bc9a8f2124d 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -57,11 +57,11 @@ export type { ResolvedServerUrls, } from './server' export type { - BuildOptions, + BuildEnvironmentOptions, LibraryOptions, LibraryFormats, RenderBuiltAssetUrl, - ResolvedBuildOptions, + ResolvedBuildEnvironmentOptions, ModulePreloadOptions, ResolvedModulePreloadOptions, ResolveModulePreloadDependenciesFn,