Skip to content

Commit 5da659d

Browse files
authored
feat: buildApp hook (#19971)
1 parent c4e01dc commit 5da659d

File tree

5 files changed

+57
-12
lines changed

5 files changed

+57
-12
lines changed

docs/guide/api-environment-frameworks.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ export default {
329329
}
330330
```
331331
332+
Plugins can also define a `buildApp` hook. Order `'pre'` and `null'` are executed before the configured `builder.buildApp`, and order `'post'` hooks are executed after it. `environment.isBuilt` can be used to check if an environment has already being build.
333+
332334
## Environment Agnostic Code
333335
334336
Most of the time, the current `environment` instance will be available as part of the context of the code being run so the need to access them through `server.environments` should be rare. For example, inside plugin hooks the environment is exposed as part of the `PluginContext`, so it can be accessed using `this.environment`. See [Environment API for Plugins](./api-environment-plugins.md) to learn about how to build environment aware plugins.

packages/vite/src/node/build.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,7 @@ function areSeparateFolders(a: string, b: string) {
14941494
export class BuildEnvironment extends BaseEnvironment {
14951495
mode = 'build' as const
14961496

1497+
isBuilt = false
14971498
constructor(
14981499
name: string,
14991500
config: ResolvedConfig,
@@ -1548,12 +1549,6 @@ export interface BuilderOptions {
15481549
buildApp?: (builder: ViteBuilder) => Promise<void>
15491550
}
15501551

1551-
async function defaultBuildApp(builder: ViteBuilder): Promise<void> {
1552-
for (const environment of Object.values(builder.environments)) {
1553-
await builder.build(environment)
1554-
}
1555-
}
1556-
15571552
export const builderOptionsDefaults = Object.freeze({
15581553
sharedConfigBuild: false,
15591554
sharedPlugins: false,
@@ -1565,7 +1560,7 @@ export function resolveBuilderOptions(
15651560
): ResolvedBuilderOptions | undefined {
15661561
if (!options) return
15671562
return mergeWithDefaults(
1568-
{ ...builderOptionsDefaults, buildApp: defaultBuildApp },
1563+
{ ...builderOptionsDefaults, buildApp: async () => {} },
15691564
options,
15701565
)
15711566
}
@@ -1602,10 +1597,41 @@ export async function createBuilder(
16021597
environments,
16031598
config,
16041599
async buildApp() {
1605-
return configBuilder.buildApp(builder)
1600+
// order 'pre' and 'normal' hooks are run first, then config.builder.buildApp, then 'post' hooks
1601+
let configBuilderBuildAppCalled = false
1602+
for (const p of config.getSortedPlugins('buildApp')) {
1603+
const hook = p.buildApp
1604+
if (
1605+
!configBuilderBuildAppCalled &&
1606+
typeof hook === 'object' &&
1607+
hook.order === 'post'
1608+
) {
1609+
configBuilderBuildAppCalled = true
1610+
await configBuilder.buildApp(builder)
1611+
}
1612+
const handler = getHookHandler(hook)
1613+
await handler(builder)
1614+
}
1615+
if (!configBuilderBuildAppCalled) {
1616+
await configBuilder.buildApp(builder)
1617+
}
1618+
// fallback to building all environments if no environments have been built
1619+
if (
1620+
Object.values(builder.environments).every(
1621+
(environment) => !environment.isBuilt,
1622+
)
1623+
) {
1624+
for (const environment of Object.values(builder.environments)) {
1625+
await builder.build(environment)
1626+
}
1627+
}
16061628
},
1607-
async build(environment: BuildEnvironment) {
1608-
return buildEnvironment(environment)
1629+
async build(
1630+
environment: BuildEnvironment,
1631+
): Promise<RollupOutput | RollupOutput[] | RollupWatcher> {
1632+
const output = await buildEnvironment(environment)
1633+
environment.isBuilt = true
1634+
return output
16091635
},
16101636
}
16111637

@@ -1667,3 +1693,5 @@ export async function createBuilder(
16671693

16681694
return builder
16691695
}
1696+
1697+
export type BuildAppHook = (this: void, builder: ViteBuilder) => Promise<void>

packages/vite/src/node/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export type {
8787
} from './server'
8888
export type {
8989
ViteBuilder,
90+
BuildAppHook,
9091
BuilderOptions,
9192
BuildOptions,
9293
BuildEnvironmentOptions,

packages/vite/src/node/plugin.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
UserConfig,
1616
} from './config'
1717
import type { ServerHook } from './server'
18+
import type { BuildAppHook } from './build'
1819
import type { IndexHtmlTransform } from './plugins/html'
1920
import type { EnvironmentModuleNode } from './server/moduleGraph'
2021
import type { ModuleNode } from './server/mixedModuleGraph'
@@ -291,7 +292,12 @@ export interface Plugin<A = any> extends RollupPlugin<A> {
291292
* `{ order: 'pre', handler: hook }`
292293
*/
293294
transformIndexHtml?: IndexHtmlTransform
294-
295+
/**
296+
* Build Environments
297+
*
298+
* @experimental
299+
*/
300+
buildApp?: ObjectHook<BuildAppHook>
295301
/**
296302
* Perform custom handling of HMR updates.
297303
* The handler receives a context containing changed filename, timestamp, a

playground/environment-react-ssr/vite.config.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export default defineConfig((env) => ({
2020
Object.assign(globalThis, { __globalServer: server })
2121
},
2222
},
23+
{
24+
name: 'build-client',
25+
async buildApp(builder) {
26+
await builder.build(builder.environments.client)
27+
},
28+
},
2329
],
2430
resolve: {
2531
noExternal: true,
@@ -54,7 +60,9 @@ export default defineConfig((env) => ({
5460

5561
builder: {
5662
async buildApp(builder) {
57-
await builder.build(builder.environments.client)
63+
if (!builder.environments.client.isBuilt) {
64+
throw new Error('Client environment should be built first')
65+
}
5866
await builder.build(builder.environments.ssr)
5967
},
6068
},

0 commit comments

Comments
 (0)