/
index.ts
121 lines (112 loc) 路 3.77 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import mdx from '@astrojs/mdx';
import type {
AstroConfig,
AstroIntegration,
AstroUserConfig,
ViteUserConfig,
} from 'astro';
import { spawn } from 'node:child_process';
import { dirname, relative } from 'node:path';
import { fileURLToPath } from 'node:url';
import { starlightAsides } from './integrations/asides';
import { starlightSitemap } from './integrations/sitemap';
import {
StarlightUserConfig,
StarlightConfig,
StarlightConfigSchema,
} from './utils/user-config';
import { errorMap } from './utils/error-map';
export default function StarlightIntegration(
opts: StarlightUserConfig
): AstroIntegration[] {
const parsedConfig = StarlightConfigSchema.safeParse(opts, { errorMap });
if (!parsedConfig.success) {
throw new Error(
'Invalid config passed to starlight integration\n' +
parsedConfig.error.issues.map((i) => i.message).join('\n')
);
}
const userConfig = parsedConfig.data;
const Starlight: AstroIntegration = {
name: '@astrojs/starlight',
hooks: {
'astro:config:setup': ({ config, injectRoute, updateConfig }) => {
injectRoute({
pattern: '404',
entryPoint: '@astrojs/starlight/404.astro',
});
injectRoute({
pattern: '[...slug]',
entryPoint: '@astrojs/starlight/index.astro',
});
const newConfig: AstroUserConfig = {
vite: {
plugins: [vitePluginStarlightUserConfig(userConfig, config)],
},
markdown: {
remarkPlugins: [...starlightAsides()],
shikiConfig:
// Configure Shiki theme if the user is using the default github-dark theme.
config.markdown.shikiConfig.theme !== 'github-dark'
? {}
: { theme: 'css-variables' },
},
experimental: { assets: true, inlineStylesheets: 'auto' },
};
updateConfig(newConfig);
},
'astro:build:done': ({ dir }) => {
const targetDir = fileURLToPath(dir);
const cwd = dirname(fileURLToPath(import.meta.url));
const relativeDir = relative(cwd, targetDir);
return new Promise<void>((resolve) => {
spawn('npx', ['-y', 'pagefind', '--source', relativeDir], {
stdio: 'inherit',
shell: true,
cwd,
}).on('close', () => resolve());
});
},
},
};
return [starlightSitemap(userConfig), Starlight, mdx()];
}
function resolveVirtualModuleId(id: string) {
return '\0' + id;
}
/** Expose the Starlight user config object via a virtual module. */
function vitePluginStarlightUserConfig(
opts: StarlightConfig,
{ root }: AstroConfig
): NonNullable<ViteUserConfig['plugins']>[number] {
const modules = {
'virtual:starlight/user-config': `export default ${JSON.stringify(opts)}`,
'virtual:starlight/project-context': `export default ${JSON.stringify({
root,
})}`,
'virtual:starlight/user-css': opts.customCss
.map((id) => `import "${id}";`)
.join(''),
'virtual:starlight/user-images': opts.logo
? 'src' in opts.logo
? `import src from "${opts.logo.src}"; export const logos = { dark: src, light: src };`
: `import dark from "${opts.logo.dark}"; import light from "${opts.logo.light}"; export const logos = { dark, light };`
: 'export const logos = {};',
};
const resolutionMap = Object.fromEntries(
(Object.keys(modules) as (keyof typeof modules)[]).map((key) => [
resolveVirtualModuleId(key),
key,
])
);
return {
name: 'vite-plugin-starlight-user-config',
resolveId(id): string | void {
if (id in modules) return resolveVirtualModuleId(id);
},
load(id): string | void {
const resolution = resolutionMap[id];
if (resolution) return modules[resolution];
},
};
}