vite icon indicating copy to clipboard operation
vite copied to clipboard

`ResolvedConfig` interface

Open unicornware opened this issue 1 year ago • 2 comments

Description

ResolvedConfig is currently defined as a type, but it should be an interface.

Unlike with UserConfig, this means declaration merging cannot be taken advantage of by plugin developers. As a TypeScript developer, this makes typing resolved plugin options unnecessarily difficult. Sharing those options with other plugin developers is not possible without declaration merging, or alternatively, cumbersome and possibly out-of-date patches.

Suggested solution

// packages/vite/src/node/config.ts

interface ResolvedConfig extends Readonly<
  Omit<
    UserConfig,
    | 'assetsInclude'
    | 'build'
    | 'css'
    | 'optimizeDeps'
    | 'plugins'
    | 'worker'
  > & PluginHookUtils
> {
    readonly appType: AppType
    readonly assetsInclude(file: string): boolean
    readonly base: string
    readonly build: ResolvedBuildOptions
    readonly cacheDir: string
    readonly command: 'build' | 'serve'
    readonly configFile: string | undefined
    readonly configFileDependencies: string[]
    readonly createResolver(
      options?: Partial<InternalResolveOptions>
    ): ResolveFn
    readonly css: ResolvedCSSOptions
    readonly env: Record<string, any>
    readonly envDir: string
    readonly esbuild: ESBuildOptions | false
    readonly experimental: ExperimentalOptions
    readonly inlineConfig: InlineConfig
    readonly isProduction: boolean
    readonly isWorker: boolean
    readonly logger: Logger
    readonly mainConfig: ResolvedConfig | null
    readonly mode: string
    readonly optimizeDeps: DepOptimizationOptions
    readonly packageCache: PackageCache
    readonly plugins: readonly Plugin[]
    readonly preview: ResolvedPreviewOptions
    readonly publicDir: string
    readonly rawBase: string
    readonly resolve: Required<ResolveOptions> & { alias: Alias[] }
    readonly root: string
    readonly server: ResolvedServerOptions
    readonly ssr: ResolvedSSROptions
    readonly worker: ResolvedWorkerOptions
}

Alternative

No response

Additional context

The documentation gives the impression ResolvedConfig is an interface. Given the docs, I wasn't sure if this should be a feature request or bug report :sweat_smile:

Validations

unicornware avatar Dec 31 '23 21:12 unicornware

still looking for this fix.

unicornware avatar Oct 14 '24 18:10 unicornware

While your suggestion seems reasonable, can you elaborate your use case? What I'm wondering is that, since extending UserConfig would also extends ResolveConfig = Readonly<Omit<UserConfig, ..., I suppose you'd like to not extend UserConfig but only ResolveConfig?

As an example, Vitest extends UserConfig to allow defineConfig({ test: ... }) and it also affects ResolvedConfig. https://github.com/vitest-dev/vitest/blob/e03725afddfa9516d2ace1bbe160b6516fc4893c/packages/vitest/src/node/types/vite.ts#L10

hi-ogawa avatar Oct 15 '24 01:10 hi-ogawa

If there's no breaking changes to switching to an interface, I think it'll be nice to do so. I personally tend to prefer interface but it looks like the source code now has a mix of interface and type, so it's not very consistent to side towards a pattern.

bluwy avatar Oct 23 '24 15:10 bluwy

Make ResolvedConfig an interface to allow extending it.

// assume vite custom plugin interface
type CustomContext = Record<string, any>; 
type ResolvedCustomConfig = Record<string, any>;

declare module "vite" {
  export interface UserConfig {
    __customPluginContext?:
      | {
          customPluginConfig?: Partial<ResolvedCustomConfig>;
        }
      | Partial<CustomContext>;
  }

  export interface ResolvedConfig {
    __customPluginContext: CustomContext;
  }
}

export {};

lazuee avatar Jan 16 '25 03:01 lazuee

Why not use an interface? https://github.com/vitejs/vite/blob/v6.0.7/packages/vite/src/node/config.ts#L535

export interface ResolvedConfig extends Readonly<
  Omit<
    UserConfig,
    | 'plugins'
    | 'css'
    | 'json'
    | 'assetsInclude'
    | 'optimizeDeps'
    | 'worker'
    | 'build'
    | 'dev'
    | 'environments'
    | 'server'
    | 'preview'
  > & {
    configFile: string | undefined
    configFileDependencies: string[]
    inlineConfig: InlineConfig
    root: string
    base: string
    /** @internal */
    decodedBase: string
    /** @internal */
    rawBase: string
    publicDir: string
    cacheDir: string
    command: 'build' | 'serve'
    mode: string
    isWorker: boolean
    // in nested worker bundle to find the main config
    /** @internal */
    mainConfig: ResolvedConfig | null
    /** @internal list of bundle entry id. used to detect recursive worker bundle. */
    bundleChain: string[]
    isProduction: boolean
    envDir: string
    env: Record<string, any>
    resolve: Required<ResolveOptions> & {
      alias: Alias[]
    }
    plugins: readonly Plugin[]
    css: ResolvedCSSOptions
    json: Required<JsonOptions>
    esbuild: ESBuildOptions | false
    server: ResolvedServerOptions
    dev: ResolvedDevEnvironmentOptions
    /** @experimental */
    builder: ResolvedBuilderOptions | undefined
    build: ResolvedBuildOptions
    preview: ResolvedPreviewOptions
    ssr: ResolvedSSROptions
    assetsInclude: (file: string) => boolean
    logger: Logger
    createResolver: (options?: Partial<InternalResolveOptions>) => ResolveFn
    optimizeDeps: DepOptimizationOptions
    /** @internal */
    packageCache: PackageCache
    worker: ResolvedWorkerOptions
    appType: AppType
    experimental: ExperimentalOptions
    environments: Record<string, ResolvedEnvironmentOptions>
    /** @internal */
    fsDenyGlob: AnymatchFn
    /** @internal */
    safeModulePaths: Set<string>
  } & PluginHookUtils
> {}

https://www.diffchecker.com/YFxRGZx8/

lazuee avatar Jan 16 '25 04:01 lazuee