Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: resolved createEnvironment #17791

Merged
merged 5 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions docs/guide/api-vite-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ One of the goals of this feature is to provide a customizable API to process and
```ts
import { DevEnvironment, RemoteEnvironmentTransport } from 'vite'

function createWorkerdDevEnvironment(name: string, config: ResolvedConfig, options?: DevEnvironmentOptions) {
function createWorkerdDevEnvironment(name: string, config: ResolvedConfig, context: DevEnvironmentContext) {
const hot = /* ... */
const connection = /* ... */
const transport = new RemoteEnvironmentTransport({
Expand All @@ -317,7 +317,7 @@ function createWorkerdDevEnvironment(name: string, config: ResolvedConfig, optio
const workerdDevEnvironment = new DevEnvironment(name, config, {
options: {
resolve: { conditions: ['custom'] },
...options,
...context.options,
},
hot,
runner: {
Expand All @@ -336,7 +336,7 @@ const ssrEnvironment = createWorkerdEnvironment('ssr', config)

## Environment Configuration

Environments are explicitely configured with the `environments` config option.
Environments are explicitly configured with the `environments` config option.

```js
export default {
Expand Down Expand Up @@ -403,9 +403,12 @@ export default {
environments: {
rsc: {
dev: {
createEnvironment(name, config) {
createEnvironment(name, config, { watcher }) {
// Called with 'rsc' and the resolved config during dev
return createNodeDevEnvironment(name, config)
return createNodeDevEnvironment(name, config, {
hot: customHotChannel(),
watcher
})
}
},
build: {
Expand Down Expand Up @@ -434,8 +437,11 @@ function createWorkedEnvironment(userConfig) {
],
},
dev: {
createEnvironment(name, config) {
return createWorkerdDevEnvironment(name, config)
createEnvironment(name, config, { watcher }) {
return createWorkerdDevEnvironment(name, config, {
hot: customHotChannel(),
watcher,
})
},
},
build: {
Expand Down Expand Up @@ -782,9 +788,10 @@ const runner = new ModuleRunner(
import { BroadcastChannel } from 'node:worker_threads'
import { createServer, RemoteEnvironmentTransport, DevEnvironment } from 'vite'

function createWorkerEnvironment(name, config) {
function createWorkerEnvironment(name, config, context) {
const worker = new Worker('./worker.js')
return new DevEnvironment(name, config, {
hot: /* custom hot channel */,
runner: {
transport: new RemoteEnvironmentTransport({
send: (data) => worker.postMessage(data),
Expand Down
26 changes: 9 additions & 17 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ export function resolveBuildEnvironmentOptions(
reportCompressedSize: true,
chunkSizeWarningLimit: 500,
watch: null,
createEnvironment: (name, config) => new BuildEnvironment(name, config),
}

const userBuildEnvironmentOptions = raw
Expand Down Expand Up @@ -517,8 +518,10 @@ export async function build(
const config = await resolveConfigToBuild(inlineConfig)
const environmentName =
config.build.lib || !config.build.ssr ? 'client' : 'ssr'
const createEnvironment = getBuildCreateEnvironment(config, environmentName)
const environment = await createEnvironment(environmentName, config)
const environment = await config.build.createEnvironment(
environmentName,
config,
)
await environment.init()
return buildEnvironment(config, environment, config.build.lib)
}
Expand Down Expand Up @@ -1510,18 +1513,6 @@ export function resolveBuilderOptions(
}
}

// TODO: Move createEnvironment resolving during build and dev to config stage
function getBuildCreateEnvironment(
config: ResolvedConfig,
environmentName: string,
) {
return (
config.environments[environmentName].build?.createEnvironment ??
((name: string, config: ResolvedConfig) =>
new BuildEnvironment(name, config))
)
}

export type ResolvedBuilderOptions = Required<BuilderOptions>

export async function createBuilder(
Expand All @@ -1548,8 +1539,6 @@ export async function createBuilder(
}

for (const name of Object.keys(config.environments)) {
const createEnvironment = getBuildCreateEnvironment(config, 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
Expand Down Expand Up @@ -1598,7 +1587,10 @@ export async function createBuilder(
)
}

const environment = await createEnvironment(name, environmentConfig)
const environment = await environmentConfig.build.createEnvironment(
name,
environmentConfig,
)

await environment.init()

Expand Down
51 changes: 39 additions & 12 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ import {
} from './build'
import type { ResolvedServerOptions, ServerOptions } from './server'
import { resolveServerOptions } from './server'
import type { DevEnvironment } from './server/environment'
import { DevEnvironment } from './server/environment'
import { createNodeDevEnvironment } from './server/environments/nodeEnvironment'
import { createServerHotChannel } from './server/hmr'
import type { WebSocketServer } from './server/ws'
import type { PreviewOptions, ResolvedPreviewOptions } from './preview'
import { resolvePreviewOptions } from './preview'
import {
Expand Down Expand Up @@ -137,6 +140,10 @@ export function defineConfig(config: UserConfigExport): UserConfigExport {
return config
}

export interface CreateDevEnvironmentContext {
ws: WebSocketServer
}

export interface DevEnvironmentOptions {
/**
* Files to be pre-transformed. Supports glob patterns.
Expand Down Expand Up @@ -176,6 +183,7 @@ export interface DevEnvironmentOptions {
createEnvironment?: (
name: string,
config: ResolvedConfig,
context: CreateDevEnvironmentContext,
) => Promise<DevEnvironment> | DevEnvironment

/**
Expand Down Expand Up @@ -205,18 +213,37 @@ export interface DevEnvironmentOptions {
// fs: { strict?: boolean, allow, deny }
}

export type ResolvedDevEnvironmentOptions = Required<
Omit<DevEnvironmentOptions, 'createEnvironment'>
> & {
// TODO: Should we set the default at config time? For now, it is defined on server init
createEnvironment:
| ((
name: string,
config: ResolvedConfig,
) => Promise<DevEnvironment> | DevEnvironment)
| undefined
function createDefaultClientDevEnvironment(
name: string,
config: ResolvedConfig,
context: CreateDevEnvironmentContext,
) {
return new DevEnvironment(name, config, {
hot: context.ws,
})
}

function createDefaultSsrDevEnvironment(
name: string,
config: ResolvedConfig,
): DevEnvironment {
return createNodeDevEnvironment(name, config, {
hot: createServerHotChannel(),
})
patak-dev marked this conversation as resolved.
Show resolved Hide resolved
}

function createDefaultDevEnvironment(
name: string,
config: ResolvedConfig,
context: CreateDevEnvironmentContext,
): DevEnvironment {
return config.environments[name].consumer === 'client'
? createDefaultClientDevEnvironment(name, config, context)
: createDefaultSsrDevEnvironment(name, config)
}

export type ResolvedDevEnvironmentOptions = Required<DevEnvironmentOptions>

type EnvironmentResolveOptions = ResolveOptions & {
alias?: AliasOptions
}
Expand Down Expand Up @@ -603,7 +630,7 @@ export function resolveDevEnvironmentOptions(
preserverSymlinks,
environmentName,
),
createEnvironment: dev?.createEnvironment,
createEnvironment: dev?.createEnvironment ?? createDefaultDevEnvironment,
recoverable: dev?.recoverable ?? environmentName === 'client',
moduleRunnerTransform:
dev?.moduleRunnerTransform ??
Expand Down
5 changes: 4 additions & 1 deletion packages/vite/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export { buildErrorMessage } from './server/middlewares/error'

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

export { fetchModule, type FetchModuleOptions } from './ssr/fetchModule'
Expand Down
8 changes: 6 additions & 2 deletions packages/vite/src/node/plugins/loadFallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ export function loadFallbackPlugin(config: ResolvedConfig): Plugin {
throw e
}
}
if (code != null && environment.watcher) {
ensureWatchedFile(environment.watcher, file, config.root)
if (code != null && environment.pluginContainer.watcher) {
ensureWatchedFile(
environment.pluginContainer.watcher,
file,
config.root,
)
}
}
if (code) {
Expand Down
26 changes: 12 additions & 14 deletions packages/vite/src/node/server/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ import {
} from './pluginContainer'
import type { RemoteEnvironmentTransport } from './environmentTransport'

export interface DevEnvironmentSetup {
export interface DevEnvironmentContext {
hot: false | HotChannel
watcher?: FSWatcher
options?: EnvironmentOptions
runner?: FetchModuleOptions & {
transport?: RemoteEnvironmentTransport
Expand All @@ -45,7 +44,6 @@ export class DevEnvironment extends BaseEnvironment {
mode = 'dev' as const // TODO: should this be 'serve'?
moduleGraph: EnvironmentModuleGraph

watcher?: FSWatcher
depsOptimizer?: DepsOptimizer
/**
* @internal
Expand Down Expand Up @@ -100,14 +98,14 @@ export class DevEnvironment extends BaseEnvironment {
constructor(
name: string,
config: ResolvedConfig,
setup: DevEnvironmentSetup,
context: DevEnvironmentContext,
) {
let options =
config.environments[name] ?? getDefaultResolvedEnvironmentOptions(config)
if (setup.options) {
if (context.options) {
options = mergeConfig(
options,
setup.options,
context.options,
) as ResolvedEnvironmentOptions
}
super(name, config, options)
Expand All @@ -118,16 +116,15 @@ export class DevEnvironment extends BaseEnvironment {
this.pluginContainer!.resolveId(url, undefined),
)

this.hot = setup.hot || createNoopHotChannel()
this.watcher = setup.watcher
this.hot = context.hot || createNoopHotChannel()

this._onCrawlEndCallbacks = []
this._crawlEndFinder = setupOnCrawlEnd(() => {
this._onCrawlEndCallbacks.forEach((cb) => cb())
})

this._ssrRunnerOptions = setup.runner || {}
setup.runner?.transport?.register(this)
this._ssrRunnerOptions = context?.runner ?? {}
patak-dev marked this conversation as resolved.
Show resolved Hide resolved
context?.runner?.transport?.register(this)

this.hot.on('vite:invalidate', async ({ path, message }) => {
invalidateModule(this, {
Expand All @@ -137,16 +134,16 @@ export class DevEnvironment extends BaseEnvironment {
})

const { optimizeDeps } = this.config.dev
if (setup.depsOptimizer) {
this.depsOptimizer = setup.depsOptimizer
if (context?.depsOptimizer) {
this.depsOptimizer = context.depsOptimizer
} else if (isDepOptimizationDisabled(optimizeDeps)) {
this.depsOptimizer = undefined
} else {
// We only support auto-discovery for the client environment, for all other
// environments `noDiscovery` has no effect and a simpler explicit deps
// optimizer is used that only optimizes explicitly included dependencies
// so it doesn't need to reload the environment. Now that we have proper HMR
// and full reload for general environments, we can enable autodiscovery for
// and full reload for general environments, we can enable auto-discovery for
// them in the future
this.depsOptimizer = (
optimizeDeps.noDiscovery || name !== 'client'
Expand All @@ -156,7 +153,7 @@ export class DevEnvironment extends BaseEnvironment {
}
}

async init(): Promise<void> {
async init(options?: { watcher?: FSWatcher }): Promise<void> {
if (this._initiated) {
return
}
Expand All @@ -165,6 +162,7 @@ export class DevEnvironment extends BaseEnvironment {
this._pluginContainer = await createEnvironmentPluginContainer(
this,
this._plugins,
options?.watcher,
)

// TODO: Should buildStart be called here? It break backward compatibility if we do,
Expand Down
8 changes: 4 additions & 4 deletions packages/vite/src/node/server/environments/nodeEnvironment.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import type { ResolvedConfig } from '../../config'
import type { DevEnvironmentSetup } from '../environment'
import type { DevEnvironmentContext } from '../environment'
import { DevEnvironment } from '../environment'
import { asyncFunctionDeclarationPaddingLineCount } from '../../../shared/utils'

export function createNodeDevEnvironment(
name: string,
config: ResolvedConfig,
options: DevEnvironmentSetup,
context: DevEnvironmentContext,
): DevEnvironment {
return new DevEnvironment(name, config, {
...options,
...context,
runner: {
processSourceMap(map) {
// this assumes that "new AsyncFunction" is used to create the module
Expand All @@ -18,7 +18,7 @@ export function createNodeDevEnvironment(
';'.repeat(asyncFunctionDeclarationPaddingLineCount) + map.mappings,
})
},
...options?.runner,
...context.runner,
},
})
}
Loading
Loading