Skip to content

Commit f749b27

Browse files
committedSep 8, 2021
feat: support config.extends
1 parent 2e9264f commit f749b27

File tree

1 file changed

+53
-5
lines changed

1 file changed

+53
-5
lines changed
 

Diff for: ‎src/node/config.ts

+53-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import path from 'path'
22
import fs from 'fs-extra'
33
import chalk from 'chalk'
44
import globby from 'globby'
5-
import { AliasOptions, UserConfig as ViteConfig } from 'vite'
5+
import {
6+
AliasOptions,
7+
UserConfig as ViteConfig,
8+
mergeConfig as mergeViteConfig
9+
} from 'vite'
610
import { Options as VuePluginOptions } from '@vitejs/plugin-vue'
711
import {
812
SiteData,
@@ -47,8 +51,15 @@ export interface UserConfig<ThemeConfig = any> {
4751
* @deprecated use `vue` instead
4852
*/
4953
vueOptions?: VuePluginOptions
54+
55+
extends?: RawConfigExports
5056
}
5157

58+
type RawConfigExports =
59+
| UserConfig
60+
| Promise<UserConfig>
61+
| (() => UserConfig | Promise<UserConfig>)
62+
5263
export interface SiteConfig<ThemeConfig = any> {
5364
root: string
5465
srcDir: string
@@ -122,16 +133,53 @@ export async function resolveUserConfig(root: string): Promise<UserConfig> {
122133
const hasUserConfig = await fs.pathExists(configPath)
123134
// always delete cache first before loading config
124135
delete require.cache[configPath]
125-
const userConfig: UserConfig | (() => UserConfig) = hasUserConfig
126-
? require(configPath)
127-
: {}
136+
const userConfig: RawConfigExports = hasUserConfig ? require(configPath) : {}
128137
if (hasUserConfig) {
129138
debug(`loaded config at ${chalk.yellow(configPath)}`)
130139
} else {
131140
debug(`no config file found.`)
132141
}
142+
return resolveConfigExtends(userConfig)
143+
}
144+
145+
async function resolveConfigExtends(
146+
config: RawConfigExports
147+
): Promise<UserConfig> {
148+
const resolved = await (typeof config === 'function' ? config() : config)
149+
if (resolved.extends) {
150+
const base = await resolveConfigExtends(resolved.extends)
151+
return mergeConfig(base, resolved)
152+
}
153+
return resolved
154+
}
155+
156+
function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) {
157+
const merged: Record<string, any> = { ...a }
158+
for (const key in b) {
159+
const value = b[key as keyof UserConfig]
160+
if (value == null) {
161+
continue
162+
}
163+
const existing = merged[key]
164+
if (Array.isArray(existing) && Array.isArray(value)) {
165+
merged[key] = [...existing, ...value]
166+
continue
167+
}
168+
if (isObject(existing) && isObject(value)) {
169+
if (isRoot && key === 'vite') {
170+
merged[key] = mergeViteConfig(existing, value)
171+
} else {
172+
merged[key] = mergeConfig(existing, value, false)
173+
}
174+
continue
175+
}
176+
merged[key] = value
177+
}
178+
return merged
179+
}
133180

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

137185
export async function resolveSiteData(

0 commit comments

Comments
 (0)