/
bundle.ts
120 lines (110 loc) · 3.7 KB
/
bundle.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
import ora from 'ora'
import path from 'path'
import fs from 'fs-extra'
import { slash } from '../utils/slash'
import { APP_PATH } from '../alias'
import { SiteConfig } from '../config'
import { RollupOutput } from 'rollup'
import { build, BuildOptions, UserConfig as ViteUserConfig } from 'vite'
import { createVitePressPlugin } from '../plugin'
export const okMark = '\x1b[32m✓\x1b[0m'
export const failMark = '\x1b[31m✖\x1b[0m'
// bundles the VitePress app for both client AND server.
export async function bundle(
config: SiteConfig,
options: BuildOptions
): Promise<[RollupOutput, RollupOutput, Record<string, string>]> {
const { root, srcDir } = config
const pageToHashMap = Object.create(null)
// define custom rollup input
// this is a multi-entry build - every page is considered an entry chunk
// the loading is done via filename conversion rules so that the
// metadata doesn't need to be included in the main chunk.
const input: Record<string, string> = {
app: path.resolve(APP_PATH, 'index.js')
}
config.pages.forEach((file) => {
// page filename conversion
// foo/bar.md -> foo_bar.md
input[slash(file).replace(/\//g, '_')] = path.resolve(srcDir, file)
})
// resolve options to pass to vite
const { rollupOptions } = options
const resolveViteConfig = (ssr: boolean): ViteUserConfig => ({
root: srcDir,
base: config.site.base,
logLevel: 'warn',
plugins: createVitePressPlugin(root, config, ssr, pageToHashMap),
// @ts-ignore
ssr: {
noExternal: ['vitepress']
},
build: {
...options,
emptyOutDir: true,
ssr,
outDir: ssr ? config.tempDir : config.outDir,
cssCodeSplit: false,
rollupOptions: {
...rollupOptions,
input,
// important so that each page chunk and the index export things for each
// other
preserveEntrySignatures: 'allow-extension',
output: {
...rollupOptions?.output,
...(ssr
? {}
: {
chunkFileNames(chunk): string {
if (!chunk.isEntry && /runtime/.test(chunk.name)) {
return `assets/framework.[hash].js`
}
return adComponentRE.test(chunk.name)
? `assets/ui-custom.[hash].js`
: `assets/[name].[hash].js`
}
})
}
},
// minify with esbuild in MPA mode (for CSS)
minify: ssr ? (config.mpa ? 'esbuild' : false) : !process.env.DEBUG
}
})
let clientResult: RollupOutput
let serverResult: RollupOutput
const spinner = ora()
spinner.start('building client + server bundles...')
try {
;[clientResult, serverResult] = await (Promise.all([
config.mpa ? null : build(resolveViteConfig(false)),
build(resolveViteConfig(true))
]) as Promise<[RollupOutput, RollupOutput]>)
} catch (e) {
spinner.stopAndPersist({
symbol: failMark
})
throw e
}
spinner.stopAndPersist({
symbol: okMark
})
if (config.mpa) {
// in MPA mode, we need to copy over the non-js asset files from the
// server build since there is no client-side build.
for (const chunk of serverResult.output) {
if (!chunk.fileName.endsWith('.js')) {
const tempPath = path.resolve(config.tempDir, chunk.fileName)
const outPath = path.resolve(config.outDir, chunk.fileName)
await fs.copy(tempPath, outPath)
}
}
// also copy over public dir
const publicDir = path.resolve(config.srcDir, 'public')
if (fs.existsSync(publicDir)) {
await fs.copy(publicDir, config.outDir)
}
}
return [clientResult, serverResult, pageToHashMap]
}
const adComponentRE = /(?:Carbon|BuySell)Ads/