Skip to content

Commit

Permalink
refactor: base environment.config + environment.options
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev committed Mar 28, 2024
1 parent 72fe84e commit c7e4da2
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 125 deletions.
88 changes: 41 additions & 47 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ import {
VERSION,
} from './constants'
import type {
BuildEnvironmentConfig,
EnvironmentOptions,
InlineConfig,
ResolvedConfig,
ResolvedEnvironmentOptions,
} from './config'
import { resolveConfig } from './config'
import { getDefaultResolvedEnvironmentOptions, resolveConfig } from './config'
import { buildReporterPlugin } from './plugins/reporter'
import { buildEsbuildPlugin } from './plugins/esbuild'
import { type TerserOptions, terserPlugin } from './plugins/terser'
Expand Down Expand Up @@ -1322,20 +1323,31 @@ function areSeparateFolders(a: string, b: string) {
export class BuildEnvironment extends Environment {
mode = 'build' as const
builder: ViteBuilder
config: BuildEnvironmentConfig

constructor(
builder: ViteBuilder,
name: string,
options?: { config?: BuildEnvironmentConfig },
setup?: {
options?: EnvironmentOptions
},
) {
super(name)
let options =
builder.config.environments[name] ??
getDefaultResolvedEnvironmentOptions(builder.config)
if (setup?.options) {
options = mergeConfig(
options,
setup?.options,
) as ResolvedEnvironmentOptions
}
super(name, builder.config, options)
this.builder = builder
this.config = options?.config ?? { build: {} }
}
}

export interface ViteBuilder {
environments: Record<string, BuildEnvironment>
config: ResolvedConfig
build(): Promise<void>
buildEnvironment(environment: BuildEnvironment): Promise<void>
}
Expand Down Expand Up @@ -1383,27 +1395,21 @@ export async function createViteBuilder(
): Promise<ViteBuilder> {
// Plugins passed to the Builder inline config needs to be created
// from a factory to ensure each build has their own instances
const getDefaultInlineConfig = (): InlineConfig => {
const resolveConfig = (): Promise<ResolvedConfig> => {
const { plugins } = defaultBuilderInlineConfig
return plugins
const defaultInlineConfig = plugins
? {
...defaultBuilderInlineConfig,
plugins: plugins(),
}
: (defaultBuilderInlineConfig as InlineConfig)
}

// TODO: defineEnvironments -> config
// We resolve the whole config including plugins here but later on we
// need to refactor resolveConfig to only resolve the environments config
return resolveConfigToBuild(defaultInlineConfig)
}

// We resolve the whole config including plugins here but later on we
// need to refactor resolveConfig to only resolve the environments config
const defaultInlineConfig = getDefaultInlineConfig()
const defaultConfig = await resolveConfig(
defaultInlineConfig,
'build',
'production',
'production',
)
const defaultConfig = await resolveConfig()

if (defaultConfig.build.lib) {
throw new Error('Library mode is not supported in ViteBuilder')
Expand All @@ -1414,37 +1420,17 @@ export async function createViteBuilder(

const environments: Record<string, BuildEnvironment> = {}

async function resolveEnvironmentConfig(environment: BuildEnvironment) {
// We need to resolve the config again so we can properly merge options
// and get a new set of plugins for each build environment. The ecosystem
// expects plugins to be run for the same environment once they are created
// and to process a single bundle at a time (contrary to dev mode where
// plugins are built to handle multiple environments concurrently).

let userConfig = getDefaultInlineConfig()
const inlineConfigEnvironmentOverrides =
userConfig.environments?.[environment.name]
if (inlineConfigEnvironmentOverrides) {
userConfig = mergeConfig(userConfig, inlineConfigEnvironmentOverrides)
}
if (environment.config) {
userConfig = mergeConfig(userConfig, environment.config)
}

return await resolveConfigToBuild(userConfig)
}

const builder: ViteBuilder = {
environments,
config: defaultConfig,
async build() {
const buildTasks = []
for (const environment of Object.values(environments)) {
const config = await resolveEnvironmentConfig(environment)
const buildTask = {
environment,
config,
config: environment.config,
run: async () => {
await buildEnvironment(config, environment)
await buildEnvironment(environment.config, environment)
},
cancel: () => {}, // TODO, maybe not needed
}
Expand All @@ -1453,18 +1439,26 @@ export async function createViteBuilder(
await defaultConfig.builder.runBuildTasks(builder, buildTasks)
},
async buildEnvironment(environment: BuildEnvironment) {
const config = await resolveEnvironmentConfig(environment)
await buildEnvironment(config, environment)
await buildEnvironment(environment.config, environment)
},
}

for (const name of Object.keys(defaultConfig.environments)) {
const environmentConfig = defaultConfig.environments[name]
const environmentOptions = defaultConfig.environments[name]
const createEnvironment =
environmentConfig.build?.createEnvironment ??
environmentOptions.build?.createEnvironment ??
((builder: ViteBuilder, name: string) =>
new BuildEnvironment(builder, name))
const environment = createEnvironment(builder, name)

// We need to resolve the config again so we can properly merge options
// and get a new set of plugins for each build environment. The ecosystem
// expects plugins to be run for the same environment once they are created
// and to process a single bundle at a time (contrary to dev mode where
// plugins are built to handle multiple environments concurrently).
const environmentConfig = await resolveConfig()
const environmentBuilder = { ...builder, config: environmentConfig }

const environment = createEnvironment(environmentBuilder, name)
environments[name] = environment
}

Expand Down
60 changes: 20 additions & 40 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,14 @@ type EnvironmentResolveOptions = ResolveOptions & {
alias?: AliasOptions
}

export interface SharedEnvironmentConfig {
export interface SharedEnvironmentOptions {
/**
* Configure resolver
*/
resolve?: EnvironmentResolveOptions
}

export interface EnvironmentConfig extends SharedEnvironmentConfig {
export interface EnvironmentOptions extends SharedEnvironmentOptions {
/**
* Dev specific options
*/
Expand All @@ -205,21 +205,9 @@ export interface EnvironmentConfig extends SharedEnvironmentConfig {
build?: BuildOptions
}

export type ResolvedEnvironmentConfig = Required<EnvironmentConfig>
export type ResolvedEnvironmentOptions = Required<EnvironmentOptions>

export interface DevEnvironmentConfig extends SharedEnvironmentConfig {
dev?: DevOptions
}

export type ResolvedDevEnvironmentConfig = Required<DevEnvironmentConfig>

export interface BuildEnvironmentConfig extends SharedEnvironmentConfig {
build?: BuildOptions
}

export type ResolvedBuildEnvironmentConfig = Required<BuildEnvironmentConfig>

export interface UserConfig extends EnvironmentConfig {
export interface UserConfig extends EnvironmentOptions {
/**
* Project root directory. Can be an absolute path, or a path relative from
* the location of the config file itself.
Expand Down Expand Up @@ -365,14 +353,14 @@ export interface UserConfig extends EnvironmentConfig {
optimizeDeps?: DepOptimizationOptions
/**
* SSR specific options
* We could make SSROptions be a EnvironmentConfig if we can abstract
* We could make SSROptions be a EnvironmentOptions if we can abstract
* external/noExternal for environments in general.
*/
ssr?: SSROptions
/**
* Environment overrides
*/
environments?: Record<string, EnvironmentConfig>
environments?: Record<string, EnvironmentOptions>
/**
* Whether your application is a Single Page Application (SPA),
* a Multi-Page Application (MPA), or Custom Application (SSR
Expand Down Expand Up @@ -500,7 +488,7 @@ export type ResolvedConfig = Readonly<
worker: ResolvedWorkerOptions
appType: AppType
experimental: ExperimentalOptions
environments: Record<string, ResolvedEnvironmentConfig>
environments: Record<string, ResolvedEnvironmentOptions>
} & PluginHookUtils
>

Expand All @@ -526,11 +514,11 @@ export function resolveDevOptions(
}
}

function resolveEnvironmentConfig(
config: EnvironmentConfig,
function resolveEnvironmentOptions(
config: EnvironmentOptions,
resolvedRoot: string,
logger: Logger,
): ResolvedEnvironmentConfig {
): ResolvedEnvironmentOptions {
const resolve = resolveEnvironmentResolveOptions(config.resolve, logger)
return {
resolve,
Expand All @@ -539,30 +527,22 @@ function resolveEnvironmentConfig(
}
}

export function getDefaultEnvironmentConfig(
export function getDefaultEnvironmentOptions(
config: UserConfig,
): EnvironmentConfig {
): EnvironmentOptions {
return {
resolve: config.resolve,
dev: config.dev,
build: config.build,
}
}

export function getDefaultResolvedDevEnvironmentConfig(
export function getDefaultResolvedEnvironmentOptions(
config: ResolvedConfig,
): ResolvedDevEnvironmentConfig {
): ResolvedEnvironmentOptions {
return {
resolve: config.resolve,
dev: config.dev,
}
}

export function getDefaultResolvedBuildEnvironmentConfig(
config: ResolvedConfig,
): ResolvedBuildEnvironmentConfig {
return {
resolve: config.resolve,
build: config.build,
}
}
Expand Down Expand Up @@ -782,7 +762,7 @@ export async function resolveConfig(
checkBadCharactersInPath(resolvedRoot, logger)

// Backward compatibility: merge optimizeDeps into environments.client.dev.optimizeDeps as defaults
// TODO: should entries and force be in EnvironmentConfig?
// TODO: should entries and force be in EnvironmentOptions?
const { entries, force, ...deprecatedClientOptimizeDepsConfig } =
config.optimizeDeps ?? {}
let configEnvironmentsClient = config.environments!.client!
Expand Down Expand Up @@ -820,19 +800,19 @@ export async function resolveConfig(
}

// Merge default environment config values
const defaultEnvironmentConfig = getDefaultEnvironmentConfig(config)
const defaultEnvironmentOptions = getDefaultEnvironmentOptions(config)
for (const name of Object.keys(config.environments)) {
config.environments[name] = mergeConfig(
defaultEnvironmentConfig,
defaultEnvironmentOptions,
config.environments[name],
)
}

await runConfigEnvironmentHook(config.environments, userPlugins, configEnv)

const resolvedEnvironments: Record<string, ResolvedEnvironmentConfig> = {}
const resolvedEnvironments: Record<string, ResolvedEnvironmentOptions> = {}
for (const name of Object.keys(config.environments)) {
resolvedEnvironments[name] = resolveEnvironmentConfig(
resolvedEnvironments[name] = resolveEnvironmentOptions(
config.environments[name],
resolvedRoot,
logger,
Expand Down Expand Up @@ -1593,7 +1573,7 @@ async function runConfigHook(
}

async function runConfigEnvironmentHook(
environments: Record<string, EnvironmentConfig>,
environments: Record<string, EnvironmentOptions>,
plugins: Plugin[],
configEnv: ConfigEnv,
): Promise<void> {
Expand Down
18 changes: 14 additions & 4 deletions packages/vite/src/node/environment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
// We are using command: 'serve' | 'build' to aling with the command flag passed to hooks.
// It would be better if we would use 'dev' here but can tackle that if we managed to modify
// command at the hooks level. There could also be Preview environments later on.
import type { Logger } from './logger'
import type { ResolvedConfig, ResolvedEnvironmentOptions } from './config'

export class Environment {
name: string
constructor(name: string) {
config: ResolvedConfig
options: ResolvedEnvironmentOptions
get logger(): Logger {
return this.config.logger
}
constructor(
name: string,
config: ResolvedConfig,
options: ResolvedEnvironmentOptions,
) {
this.name = name
this.config = config
this.options = options
}
}
7 changes: 2 additions & 5 deletions packages/vite/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ export { transformWithEsbuild } from './plugins/esbuild'
export { buildErrorMessage } from './server/middlewares/error'

export { RemoteEnvironmentTransport } from './server/environmentTransport'
export { createNodeEnvironment } from './server/environments/nodeEnvironment'
export {
DevEnvironment,
type DevEnvironmentOptions,
} from './server/environment'
export { createNodeDevEnvironment } from './server/environments/nodeEnvironment'
export { DevEnvironment, type DevEnvironmentSetup } from './server/environment'
export { BuildEnvironment } from './build'

export { fetchModule, type FetchModuleOptions } from './ssr/fetchModule'
Expand Down
8 changes: 4 additions & 4 deletions packages/vite/src/node/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
} from 'rollup'
import type {
ConfigEnv,
EnvironmentConfig,
EnvironmentOptions,
ResolvedConfig,
UserConfig,
} from './config'
Expand Down Expand Up @@ -111,13 +111,13 @@ export interface Plugin<A = any> extends RollupPlugin<A> {
(
this: void,
name: string,
config: EnvironmentConfig,
config: EnvironmentOptions,
env: ConfigEnv,
) =>
| EnvironmentConfig
| EnvironmentOptions
| null
| void
| Promise<EnvironmentConfig | null | void>
| Promise<EnvironmentOptions | null | void>
>
/**
* Use this hook to read and store the final resolved vite config.
Expand Down

0 comments on commit c7e4da2

Please sign in to comment.