Skip to content

Commit

Permalink
feat: support config.extends
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Sep 8, 2021
1 parent 2e9264f commit f749b27
Showing 1 changed file with 53 additions and 5 deletions.
58 changes: 53 additions & 5 deletions src/node/config.ts
Expand Up @@ -2,7 +2,11 @@ import path from 'path'
import fs from 'fs-extra'
import chalk from 'chalk'
import globby from 'globby'
import { AliasOptions, UserConfig as ViteConfig } from 'vite'
import {
AliasOptions,
UserConfig as ViteConfig,
mergeConfig as mergeViteConfig
} from 'vite'
import { Options as VuePluginOptions } from '@vitejs/plugin-vue'
import {
SiteData,
Expand Down Expand Up @@ -47,8 +51,15 @@ export interface UserConfig<ThemeConfig = any> {
* @deprecated use `vue` instead
*/
vueOptions?: VuePluginOptions

extends?: RawConfigExports
}

type RawConfigExports =
| UserConfig
| Promise<UserConfig>
| (() => UserConfig | Promise<UserConfig>)

export interface SiteConfig<ThemeConfig = any> {
root: string
srcDir: string
Expand Down Expand Up @@ -122,16 +133,53 @@ export async function resolveUserConfig(root: string): Promise<UserConfig> {
const hasUserConfig = await fs.pathExists(configPath)
// always delete cache first before loading config
delete require.cache[configPath]
const userConfig: UserConfig | (() => UserConfig) = hasUserConfig
? require(configPath)
: {}
const userConfig: RawConfigExports = hasUserConfig ? require(configPath) : {}
if (hasUserConfig) {
debug(`loaded config at ${chalk.yellow(configPath)}`)
} else {
debug(`no config file found.`)
}
return resolveConfigExtends(userConfig)
}

async function resolveConfigExtends(
config: RawConfigExports
): Promise<UserConfig> {
const resolved = await (typeof config === 'function' ? config() : config)
if (resolved.extends) {
const base = await resolveConfigExtends(resolved.extends)
return mergeConfig(base, resolved)
}
return resolved
}

function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) {
const merged: Record<string, any> = { ...a }
for (const key in b) {
const value = b[key as keyof UserConfig]
if (value == null) {
continue
}
const existing = merged[key]
if (Array.isArray(existing) && Array.isArray(value)) {
merged[key] = [...existing, ...value]
continue
}
if (isObject(existing) && isObject(value)) {
if (isRoot && key === 'vite') {
merged[key] = mergeViteConfig(existing, value)
} else {
merged[key] = mergeConfig(existing, value, false)
}
continue
}
merged[key] = value
}
return merged
}

return typeof userConfig === 'function' ? userConfig() : userConfig
function isObject(value: unknown): value is Record<string, any> {
return Object.prototype.toString.call(value) === '[object Object]'
}

export async function resolveSiteData(
Expand Down

0 comments on commit f749b27

Please sign in to comment.