diff --git a/packages/vite/src/node/__tests__/environment.spec.ts b/packages/vite/src/node/__tests__/environment.spec.ts deleted file mode 100644 index cae672513be806..00000000000000 --- a/packages/vite/src/node/__tests__/environment.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { fileURLToPath } from 'node:url' -import path from 'node:path' -import { expect, test } from 'vitest' -import { createServer } from '../server' -import { createServerModuleRunner } from '../ssr/runtime/serverModuleRunner' -import type { ResolveIdFn } from '../idResolver' -import { createBackCompatIdResolver } from '../idResolver' -import { normalizePath } from '../utils' - -const root = fileURLToPath(new URL('./', import.meta.url)) - -async function createDevServer() { - const server = await createServer({ - configFile: false, - root, - logLevel: 'silent', - plugins: [ - (() => { - let idResolver: ResolveIdFn - return { - name: 'environment-alias-test-plugin', - configResolved(config) { - idResolver = createBackCompatIdResolver(config) - }, - async resolveId(id) { - return await idResolver(this.environment, id) - }, - } - })(), - ], - environments: { - client: { - resolve: { - alias: [ - { - find: 'mod', - replacement: '/fixtures/environment-alias/test.client.js', - }, - ], - }, - }, - ssr: { - resolve: { - alias: [ - { - find: 'mod', - replacement: '/fixtures/environment-alias/test.ssr.js', - }, - ], - }, - }, - rsc: { - resolve: { - alias: [ - { - find: 'mod', - replacement: '/fixtures/environment-alias/test.rsc.js', - }, - ], - }, - }, - }, - }) - - const moduleRunner = createServerModuleRunner(server.environments.rsc) - return { server, moduleRunner } -} - -test('alias', async () => { - expect.assertions(7) - const { server, moduleRunner } = await createDevServer() - - const [clientId, ssrId, rscId, clientReq, ssrReq, rscReq, rscMod] = - await Promise.all([ - server.environments.client.pluginContainer.resolveId('mod'), - server.environments.ssr.pluginContainer.resolveId('mod'), - server.environments.rsc.pluginContainer.resolveId('mod'), - server.environments.client.transformRequest('mod'), - server.environments.ssr.transformRequest('mod'), - server.environments.rsc.transformRequest('mod'), - moduleRunner.import('mod'), - ]) - - expect(clientId?.id).toEqual( - normalizePath( - path.join(root, '/fixtures/environment-alias/test.client.js'), - ), - ) - expect(ssrId?.id).toEqual( - normalizePath(path.join(root, '/fixtures/environment-alias/test.ssr.js')), - ) - expect(rscId?.id).toEqual( - normalizePath(path.join(root, '/fixtures/environment-alias/test.rsc.js')), - ) - - expect(clientReq?.code ?? '').toContain('(client)') - expect(ssrReq?.code ?? '').toContain('(ssr)') - expect(rscReq?.code ?? '').toContain('(rsc)') - - expect(rscMod?.msg).toContain('(rsc)') -}) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 1d13e581a252f9..4c2b48a560cb2b 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -29,7 +29,6 @@ import type { } from './plugin' import type { BuildEnvironmentOptions, - BuildOptions, BuilderOptions, RenderBuiltAssetUrl, ResolvedBuildEnvironmentOptions, @@ -73,7 +72,11 @@ import { resolvePlugins, } from './plugins' import type { ESBuildOptions } from './plugins/esbuild' -import type { InternalResolveOptions, ResolveOptions } from './plugins/resolve' +import type { + EnvironmentResolveOptions, + InternalResolveOptions, + ResolveOptions, +} from './plugins/resolve' import { tryNodeResolve } from './plugins/resolve' import type { LogLevel, Logger } from './logger' import { createLogger } from './logger' @@ -224,10 +227,12 @@ function defaultCreateDevEnvironment(name: string, config: ResolvedConfig) { export type ResolvedDevEnvironmentOptions = Required -type EnvironmentResolveOptions = ResolveOptions & { +type AllResolveOptions = ResolveOptions & { alias?: AliasOptions } +type ResolvedAllResolveOptions = Required & { alias: Alias[] } + export interface SharedEnvironmentOptions { /** * Define global variable replacements. @@ -261,12 +266,11 @@ export interface EnvironmentOptions extends SharedEnvironmentOptions { build?: BuildEnvironmentOptions } -export type ResolvedEnvironmentResolveOptions = - Required +export type ResolvedResolveOptions = Required export type ResolvedEnvironmentOptions = { define?: Record - resolve: ResolvedEnvironmentResolveOptions + resolve: ResolvedResolveOptions consumer: 'client' | 'server' webCompatible: boolean dev: ResolvedDevEnvironmentOptions @@ -275,10 +279,9 @@ export type ResolvedEnvironmentOptions = { export type DefaultEnvironmentOptions = Omit< EnvironmentOptions, - 'build' | 'consumer' | 'webCompatible' + 'consumer' | 'webCompatible' | 'resolve' > & { - // Includes lib mode support - build?: BuildOptions + resolve?: AllResolveOptions } export interface UserConfig extends DefaultEnvironmentOptions { @@ -622,12 +625,19 @@ export function resolveDevEnvironmentOptions( function resolveEnvironmentOptions( options: EnvironmentOptions, resolvedRoot: string, + alias: Alias[], + preserveSymlinks: boolean, logger: Logger, environmentName: string, // Backward compatibility skipSsrTransform?: boolean, ): ResolvedEnvironmentOptions { - const resolve = resolveEnvironmentResolveOptions(options.resolve, logger) + const resolve = resolveEnvironmentResolveOptions( + options.resolve, + alias, + preserveSymlinks, + logger, + ) const isClientEnvironment = environmentName === 'client' const consumer = (options.consumer ?? isClientEnvironment) ? 'client' : 'server' @@ -730,16 +740,17 @@ const clientAlias = [ }, ] +/** + * alias and preserveSymlinks are not per-environment options, but they are + * included in the resolved environment options for convenience. + */ function resolveEnvironmentResolveOptions( resolve: EnvironmentResolveOptions | undefined, + alias: Alias[], + preserveSymlinks: boolean, logger: Logger, -): ResolvedConfig['resolve'] { - // resolve alias with internal client alias - const resolvedAlias = normalizeAlias( - mergeAlias(clientAlias, resolve?.alias || []), - ) - - const resolvedResolve: ResolvedConfig['resolve'] = { +): ResolvedAllResolveOptions { + const resolvedResolve: ResolvedAllResolveOptions = { mainFields: resolve?.mainFields ?? DEFAULT_MAIN_FIELDS, conditions: resolve?.conditions ?? [], externalConditions: resolve?.externalConditions ?? [], @@ -747,8 +758,8 @@ function resolveEnvironmentResolveOptions( noExternal: resolve?.noExternal ?? [], extensions: resolve?.extensions ?? DEFAULT_EXTENSIONS, dedupe: resolve?.dedupe ?? [], - preserveSymlinks: resolve?.preserveSymlinks ?? false, - alias: resolvedAlias, + preserveSymlinks, + alias, } if ( @@ -767,6 +778,22 @@ function resolveEnvironmentResolveOptions( return resolvedResolve } +function resolveResolveOptions( + resolve: AllResolveOptions | undefined, + logger: Logger, +): ResolvedAllResolveOptions { + // resolve alias with internal client alias + const alias = normalizeAlias(mergeAlias(clientAlias, resolve?.alias || [])) + const preserveSymlinks = resolve?.preserveSymlinks ?? false + return resolveEnvironmentResolveOptions( + resolve, + alias, + preserveSymlinks, + logger, + ) +} + +// TODO: Introduce ResolvedDepOptimizationOptions function resolveDepOptimizationOptions( optimizeDeps: DepOptimizationOptions | undefined, preserveSymlinks: boolean, @@ -967,22 +994,21 @@ export async function resolveConfig( await runConfigEnvironmentHook(config.environments, userPlugins, configEnv) + const resolvedDefaultResolve = resolveResolveOptions(config.resolve, logger) + const resolvedEnvironments: Record = {} for (const environmentName of Object.keys(config.environments)) { resolvedEnvironments[environmentName] = resolveEnvironmentOptions( config.environments[environmentName], resolvedRoot, + resolvedDefaultResolve.alias, + resolvedDefaultResolve.preserveSymlinks, logger, environmentName, config.experimental?.skipSsrTransform, ) } - const resolvedDefaultEnvironmentResolve = resolveEnvironmentResolveOptions( - config.resolve, - logger, - ) - // Backward compatibility: merge environments.client.dev.optimizeDeps back into optimizeDeps // The same object is assigned back for backward compatibility. The ecosystem is modifying // optimizeDeps in the ResolvedConfig hook, so these changes will be reflected on the @@ -990,11 +1016,9 @@ export async function resolveConfig( const backwardCompatibleOptimizeDeps = resolvedEnvironments.client.dev.optimizeDeps - // TODO: Deprecate and remove resolve, dev and build options at the root level of the resolved config - const resolvedDevEnvironmentOptions = resolveDevEnvironmentOptions( config.dev, - resolvedDefaultEnvironmentResolve.preserveSymlinks, + resolvedDefaultResolve.preserveSymlinks, // default environment options undefined, undefined, @@ -1022,7 +1046,7 @@ export async function resolveConfig( } const ssr = resolveSSROptions( patchedConfigSsr, - resolvedDefaultEnvironmentResolve.preserveSymlinks, + resolvedDefaultResolve.preserveSymlinks, ) // load .env files @@ -1225,8 +1249,7 @@ export async function resolveConfig( optimizeDeps: backwardCompatibleOptimizeDeps, ssr, - // TODO: deprecate and later remove from ResolvedConfig? - resolve: resolvedDefaultEnvironmentResolve, + resolve: resolvedDefaultResolve, dev: resolvedDevEnvironmentOptions, build: resolvedBuildOptions, diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index edf07f81dc377e..2abacbf9d2caea 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -75,7 +75,7 @@ const debug = createDebugger('vite:resolve-details', { onlyWhenFocused: true, }) -export interface ResolveOptions { +export interface EnvironmentResolveOptions { /** * @default ['browser', 'module', 'jsnext:main', 'jsnext'] */ @@ -87,10 +87,6 @@ export interface ResolveOptions { */ extensions?: string[] dedupe?: string[] - /** - * @default false - */ - preserveSymlinks?: boolean /** * external/noExternal logic, this only works for certain environments * Previously this was ssr.external/ssr.noExternal @@ -100,6 +96,13 @@ export interface ResolveOptions { external?: string[] | true } +export interface ResolveOptions extends EnvironmentResolveOptions { + /** + * @default false + */ + preserveSymlinks?: boolean +} + interface ResolvePluginOptions { root: string isBuild: boolean @@ -173,8 +176,6 @@ export interface InternalResolveOptions // Defined ResolveOptions are used to overwrite the values for all environments // It is used when creating custom resolvers (for CSS, scanning, etc) -// TODO: It could be more clear to make the plugin constructor be: -// resolvePlugin(pluginOptions: ResolvePluginOptions, overrideResolveOptions?: ResolveOptions) export interface ResolvePluginOptionsWithOverrides extends ResolveOptions, ResolvePluginOptions {} @@ -183,9 +184,9 @@ export function resolvePlugin( resolveOptions: ResolvePluginOptionsWithOverrides, /** * @internal - * The deprecated config.createResolver creates a pluginContainer before - * environments are created. The resolve plugin is especial as it works without - * environments to enable this use case. It only needs access to the resolve options. + * config.createResolver creates a pluginContainer before environments are created. + * The resolve plugin is especial as it works without environments to enable this use case. + * It only needs access to the resolve options. */ environmentsOptions?: Record, ): Plugin {