@lukoweb/apitogo 0.2.60 → 0.2.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cli.js +893 -527
- package/docs/cli/commands.md +6 -6
- package/docs/cli/go-live.md +12 -12
- package/docs/cli/overview.md +26 -27
- package/docs/cli/setup.md +38 -46
- package/docs/cli/shape.md +32 -35
- package/docs/cli/walkthrough.md +19 -19
- package/docs/components/slot.mdx +116 -116
- package/docs/configuration/api-reference.md +1 -1
- package/docs/configuration/authentication.md +3 -3
- package/docs/configuration/footer.mdx +89 -89
- package/docs/configuration/gateway.md +8 -8
- package/docs/configuration/make-config.mdx +20 -10
- package/docs/configuration/overview.md +3 -3
- package/docs/configuration/plans.md +5 -5
- package/docs/configuration/portal.md +36 -0
- package/docs/customization/colors-theme.mdx +255 -255
- package/docs/customization/fonts.md +105 -105
- package/docs/customization/landing-page.md +1 -1
- package/docs/deploy/apitogo.md +3 -3
- package/docs/deployment.md +3 -3
- package/docs/guides/custom-pages.md +3 -3
- package/docs/guides/customer-account.md +1 -1
- package/docs/guides/stripe-setup.mdx +9 -9
- package/docs/markdown/frontmatter.md +2 -2
- package/docs/mcp/go-live.md +7 -7
- package/docs/mcp/overview.md +58 -58
- package/docs/mcp/setup.md +6 -6
- package/docs/mcp/shape.md +2 -2
- package/docs/mcp/tools.md +57 -57
- package/docs/quickstart.md +6 -4
- package/docs/writing.mdx +68 -68
- package/package.json +1 -1
- package/src/config/apitogo-config-core.ts +11 -1
- package/src/config/v2/resolve.ts +19 -0
- package/src/config/v2/rules.ts +88 -0
- package/src/config/v2/schema.ts +28 -0
- package/src/config/v2/wrapper.ts +76 -13
- package/src/vite/config.ts +278 -273
- package/src/vite/markdown-output-path.ts +48 -0
- package/src/vite/plugin-markdown-export.ts +210 -214
- package/src/vite/prerender/prerender.ts +4 -4
- package/src/vite/watch-ignore.ts +19 -0
package/src/vite/config.ts
CHANGED
|
@@ -1,273 +1,278 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import dotenv from "dotenv";
|
|
3
|
-
import colors from "picocolors";
|
|
4
|
-
import {
|
|
5
|
-
type ConfigEnv,
|
|
6
|
-
type InlineConfig,
|
|
7
|
-
type LogLevel,
|
|
8
|
-
loadConfigFromFile,
|
|
9
|
-
mergeConfig,
|
|
10
|
-
} from "vite";
|
|
11
|
-
import packageJson from "../../package.json" with { type: "json" };
|
|
12
|
-
import { ZuploEnv } from "../app/env.js";
|
|
13
|
-
import { logger } from "../cli/common/logger.js";
|
|
14
|
-
import { getZudokuRootDir } from "../cli/common/package-json.js";
|
|
15
|
-
import { loadZudokuConfig } from "../config/loader.js";
|
|
16
|
-
import { CdnUrlSchema } from "../config/validators/ZudokuConfig.js";
|
|
17
|
-
import { joinUrl } from "../lib/util/joinUrl.js";
|
|
18
|
-
import { loadDevPortalViteDefines } from "./dev-portal-env.js";
|
|
19
|
-
import { findPackageRoot } from "./package-root.js";
|
|
20
|
-
import { ensurePagefindDevStub } from "./pagefind-dev-stub.js";
|
|
21
|
-
import vitePlugin from "./plugin.js";
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
`${
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
},
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
"@lukoweb/apitogo
|
|
212
|
-
|
|
213
|
-
],
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
import colors from "picocolors";
|
|
4
|
+
import {
|
|
5
|
+
type ConfigEnv,
|
|
6
|
+
type InlineConfig,
|
|
7
|
+
type LogLevel,
|
|
8
|
+
loadConfigFromFile,
|
|
9
|
+
mergeConfig,
|
|
10
|
+
} from "vite";
|
|
11
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
12
|
+
import { ZuploEnv } from "../app/env.js";
|
|
13
|
+
import { logger } from "../cli/common/logger.js";
|
|
14
|
+
import { getZudokuRootDir } from "../cli/common/package-json.js";
|
|
15
|
+
import { loadZudokuConfig } from "../config/loader.js";
|
|
16
|
+
import { CdnUrlSchema } from "../config/validators/ZudokuConfig.js";
|
|
17
|
+
import { joinUrl } from "../lib/util/joinUrl.js";
|
|
18
|
+
import { loadDevPortalViteDefines } from "./dev-portal-env.js";
|
|
19
|
+
import { findPackageRoot } from "./package-root.js";
|
|
20
|
+
import { ensurePagefindDevStub } from "./pagefind-dev-stub.js";
|
|
21
|
+
import vitePlugin from "./plugin.js";
|
|
22
|
+
import {
|
|
23
|
+
devServerAllow,
|
|
24
|
+
nestedStateIgnore,
|
|
25
|
+
stateIgnore,
|
|
26
|
+
} from "./watch-ignore.js";
|
|
27
|
+
import { getZuploSystemConfigurations } from "./zuplo.js";
|
|
28
|
+
|
|
29
|
+
/** Resolved absolute public directory (Vite default: `<root>/public`). */
|
|
30
|
+
const resolveMergedPublicDir = (
|
|
31
|
+
rootDir: string,
|
|
32
|
+
merged: InlineConfig,
|
|
33
|
+
): string | undefined => {
|
|
34
|
+
if (merged.publicDir === false) return undefined;
|
|
35
|
+
const rel =
|
|
36
|
+
typeof merged.publicDir === "string" ? merged.publicDir : "public";
|
|
37
|
+
return path.resolve(rootDir, rel);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type ZudokuConfigEnv = ConfigEnv & {
|
|
41
|
+
mode: "development" | "production";
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const getAppClientEntryPath = () =>
|
|
45
|
+
path.posix.join(getZudokuRootDir(), "src/app/entry.client.tsx");
|
|
46
|
+
|
|
47
|
+
export const getAppServerEntryPath = () =>
|
|
48
|
+
path.posix.join(getZudokuRootDir(), "src/app/entry.server.tsx");
|
|
49
|
+
|
|
50
|
+
// the vite config gets loaded multiple times, so we only log the CDN info once
|
|
51
|
+
let hasLoggedCdnInfo = false;
|
|
52
|
+
const MEDIA_REGEX =
|
|
53
|
+
/\.(a?png|jpe?g|gif|bmp|svg|webp|tiff|ico|webm|ogg|mp3|wav|m4a|avif|mp4)/i;
|
|
54
|
+
|
|
55
|
+
const defineEnvVars = (vars: string[]) =>
|
|
56
|
+
Object.fromEntries(
|
|
57
|
+
vars.flatMap((v) => [
|
|
58
|
+
[`process.env.${v}`, JSON.stringify(process.env[v])],
|
|
59
|
+
[`import.meta.env.${v}`, JSON.stringify(process.env[v])],
|
|
60
|
+
]),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export async function getViteConfig(
|
|
64
|
+
dir: string,
|
|
65
|
+
configEnv: ZudokuConfigEnv,
|
|
66
|
+
): Promise<InlineConfig> {
|
|
67
|
+
const { config, publicEnv, envPrefix } = await loadZudokuConfig(
|
|
68
|
+
configEnv,
|
|
69
|
+
dir,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const cdnUrl = CdnUrlSchema.parse(config.cdnUrl);
|
|
73
|
+
|
|
74
|
+
const base = cdnUrl?.base
|
|
75
|
+
? joinUrl(cdnUrl.base, config.basePath)
|
|
76
|
+
: config.basePath;
|
|
77
|
+
|
|
78
|
+
if (cdnUrl && !hasLoggedCdnInfo) {
|
|
79
|
+
logger.info(colors.blue(`Using CDN URL:`));
|
|
80
|
+
logger.info(colors.blue(` base: `) + colors.dim(cdnUrl.base));
|
|
81
|
+
logger.info(colors.blue(` media: `) + colors.dim(cdnUrl.media));
|
|
82
|
+
hasLoggedCdnInfo = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// We define public env vars as `process.env` vars because Vite only exposes them as `import.meta.env` vars
|
|
86
|
+
const publicVarsProcessEnvDefine = Object.fromEntries(
|
|
87
|
+
Object.entries(publicEnv).map(([key, value]) => [
|
|
88
|
+
`process.env.${key}`,
|
|
89
|
+
value,
|
|
90
|
+
]),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// The workspace of a config version 2 portal links back to its own project; the watcher must not follow that.
|
|
94
|
+
const ignoreState = stateIgnore(dir);
|
|
95
|
+
|
|
96
|
+
if (ZuploEnv.isZuplo) {
|
|
97
|
+
dotenv.config({
|
|
98
|
+
path: path.resolve(config.__meta.rootDir, "../.env.zuplo"),
|
|
99
|
+
quiet: true,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const deploymentName =
|
|
104
|
+
ZuploEnv.buildConfig?.deploymentName ||
|
|
105
|
+
getZuploSystemConfigurations(process.env.ZUPLO_SYSTEM_CONFIGURATIONS)
|
|
106
|
+
?.__ZUPLO_DEPLOYMENT_NAME;
|
|
107
|
+
|
|
108
|
+
const devPortalDefines = await loadDevPortalViteDefines(dir, configEnv.mode);
|
|
109
|
+
|
|
110
|
+
const viteConfig: InlineConfig = {
|
|
111
|
+
root: dir,
|
|
112
|
+
base,
|
|
113
|
+
appType: "custom",
|
|
114
|
+
configFile: false,
|
|
115
|
+
clearScreen: false,
|
|
116
|
+
logLevel: (process.env.LOG_LEVEL ?? "info") as LogLevel,
|
|
117
|
+
customLogger: logger,
|
|
118
|
+
envPrefix,
|
|
119
|
+
resolve: {
|
|
120
|
+
dedupe: ["react", "react-dom"],
|
|
121
|
+
alias: {
|
|
122
|
+
"@mdx-js/react": import.meta.resolve("@mdx-js/react"),
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
define: {
|
|
126
|
+
"process.env.ZUDOKU_VERSION": JSON.stringify(packageJson.version),
|
|
127
|
+
"process.env.IS_ZUPLO": ZuploEnv.isZuplo,
|
|
128
|
+
"import.meta.env.IS_ZUPLO": ZuploEnv.isZuplo,
|
|
129
|
+
"import.meta.env.ZUPLO_PUBLIC_DEPLOYMENT_NAME":
|
|
130
|
+
JSON.stringify(deploymentName),
|
|
131
|
+
...defineEnvVars([
|
|
132
|
+
"SENTRY_DSN",
|
|
133
|
+
"ZUPLO_BUILD_ID",
|
|
134
|
+
"ZUPLO_BUILD_CONFIG",
|
|
135
|
+
"ZUPLO_ENVIRONMENT_TYPE",
|
|
136
|
+
"ZUPLO_SERVER_URL",
|
|
137
|
+
"ZUPLO_GATEWAY_SERVICE_URL",
|
|
138
|
+
]),
|
|
139
|
+
...publicVarsProcessEnvDefine,
|
|
140
|
+
...devPortalDefines,
|
|
141
|
+
},
|
|
142
|
+
ssr: {
|
|
143
|
+
target: "node",
|
|
144
|
+
noExternal: [/apitogo/, "@mdx-js/react"],
|
|
145
|
+
external: ["@shikijs/themes", "@shikijs/langs"],
|
|
146
|
+
},
|
|
147
|
+
server: {
|
|
148
|
+
middlewareMode: true,
|
|
149
|
+
open: true,
|
|
150
|
+
fs: {
|
|
151
|
+
allow: devServerAllow(dir, config.__meta.moduleDir),
|
|
152
|
+
},
|
|
153
|
+
watch: {
|
|
154
|
+
ignored: [
|
|
155
|
+
`${dir}/dist`,
|
|
156
|
+
`${dir}/lib`,
|
|
157
|
+
`${dir}/.git`,
|
|
158
|
+
`${config.__meta.moduleDir}/src/vite`,
|
|
159
|
+
`${config.__meta.moduleDir}/src/cli`,
|
|
160
|
+
nestedStateIgnore(dir),
|
|
161
|
+
...(ignoreState ? [ignoreState] : []),
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
build: {
|
|
166
|
+
ssr: configEnv.isSsrBuild,
|
|
167
|
+
sourcemap: true,
|
|
168
|
+
target: "es2022",
|
|
169
|
+
outDir: path.resolve(
|
|
170
|
+
path.join(
|
|
171
|
+
dir,
|
|
172
|
+
"dist",
|
|
173
|
+
config.basePath ?? "",
|
|
174
|
+
configEnv.isSsrBuild ? "server" : "",
|
|
175
|
+
),
|
|
176
|
+
),
|
|
177
|
+
emptyOutDir: true,
|
|
178
|
+
rollupOptions: {
|
|
179
|
+
input:
|
|
180
|
+
configEnv.command === "build"
|
|
181
|
+
? configEnv.isSsrBuild
|
|
182
|
+
? [
|
|
183
|
+
"@lukoweb/apitogo/app/entry.server.tsx",
|
|
184
|
+
config.__meta.configPath,
|
|
185
|
+
]
|
|
186
|
+
: "@lukoweb/apitogo/app/entry.client.tsx"
|
|
187
|
+
: undefined,
|
|
188
|
+
external: [joinUrl(config.basePath, "/pagefind/pagefind.js")],
|
|
189
|
+
},
|
|
190
|
+
chunkSizeWarningLimit: 1500,
|
|
191
|
+
},
|
|
192
|
+
experimental: {
|
|
193
|
+
renderBuiltUrl(filename) {
|
|
194
|
+
if (cdnUrl?.base && [".js", ".css"].includes(path.extname(filename))) {
|
|
195
|
+
return joinUrl(cdnUrl.base, filename);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (cdnUrl?.media && MEDIA_REGEX.test(filename)) {
|
|
199
|
+
return joinUrl(cdnUrl.media, filename);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { relative: true };
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
optimizeDeps: {
|
|
206
|
+
esbuildOptions: {
|
|
207
|
+
target: "es2022",
|
|
208
|
+
},
|
|
209
|
+
entries: [path.posix.join(getZudokuRootDir(), "src/{app,lib}/**")],
|
|
210
|
+
exclude: [
|
|
211
|
+
"@lukoweb/apitogo",
|
|
212
|
+
"@lukoweb/apitogo-plugin-dev-portal-billing",
|
|
213
|
+
],
|
|
214
|
+
include: [
|
|
215
|
+
"react-dom/client",
|
|
216
|
+
"@lukoweb/apitogo/icons",
|
|
217
|
+
...(process.env.SENTRY_DSN ? ["@sentry/react"] : []),
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
assetsInclude: [
|
|
221
|
+
// Workaround for Pre-transform error for "virtual" file: https://github.com/vitejs/vite/issues/15374
|
|
222
|
+
"/__z/entry.client.tsx",
|
|
223
|
+
"**/pagefind.js",
|
|
224
|
+
],
|
|
225
|
+
plugins: [vitePlugin()],
|
|
226
|
+
future: {
|
|
227
|
+
removeServerModuleGraph: "warn",
|
|
228
|
+
removeSsrLoadModule: "warn",
|
|
229
|
+
removeServerTransformRequest: "warn",
|
|
230
|
+
removePluginHookHandleHotUpdate: "warn",
|
|
231
|
+
removePluginHookSsrArgument: "warn",
|
|
232
|
+
removeServerHot: "warn",
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// Merge vite configs from plugin directories and user's project
|
|
237
|
+
const configRoots = await Promise.all(
|
|
238
|
+
(config.__pluginDirs ?? []).map(findPackageRoot),
|
|
239
|
+
);
|
|
240
|
+
configRoots.push(dir);
|
|
241
|
+
|
|
242
|
+
let mergedViteConfig = viteConfig;
|
|
243
|
+
|
|
244
|
+
for (const root of configRoots) {
|
|
245
|
+
if (!root) continue;
|
|
246
|
+
const loaded = await loadConfigFromFile(
|
|
247
|
+
configEnv,
|
|
248
|
+
undefined,
|
|
249
|
+
root,
|
|
250
|
+
undefined,
|
|
251
|
+
undefined,
|
|
252
|
+
"runner",
|
|
253
|
+
);
|
|
254
|
+
if (!loaded) continue;
|
|
255
|
+
|
|
256
|
+
mergedViteConfig = mergeConfig(mergedViteConfig, loaded.config, true);
|
|
257
|
+
|
|
258
|
+
if (root === dir) {
|
|
259
|
+
logger.info(colors.blue(`merged with custom user Vite config`), {
|
|
260
|
+
timestamp: true,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Create pagefind stub before Vite starts. In development, `optimizeDeps.entries` crawls all of
|
|
266
|
+
// `src/lib/**`, which includes PagefindSearch's dev import of `/pagefind/pagefind.js`; esbuild
|
|
267
|
+
// must be able to open that path even when search is not configured. Pagefind users still get
|
|
268
|
+
// the stub until a real index is written (dev index or production prerender).
|
|
269
|
+
const publicDir = resolveMergedPublicDir(dir, mergedViteConfig);
|
|
270
|
+
if (
|
|
271
|
+
publicDir &&
|
|
272
|
+
(configEnv.mode === "development" || config.search?.type === "pagefind")
|
|
273
|
+
) {
|
|
274
|
+
await ensurePagefindDevStub(publicDir);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return mergedViteConfig;
|
|
278
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Where the build writes the exported Markdown copy of the page at `routePath`: `<distDir>/<route>.md`, or
|
|
6
|
+
* `<distDir>/index.md` for `/`. The markdown export plugin writes it and prerender removes it again when the copies
|
|
7
|
+
* were only made for llms.txt, so both must use this one function.
|
|
8
|
+
*/
|
|
9
|
+
export const markdownOutputPath = (
|
|
10
|
+
distDir: string,
|
|
11
|
+
routePath: string,
|
|
12
|
+
): string => {
|
|
13
|
+
const segments =
|
|
14
|
+
routePath === "/" ? ["index"] : routePath.split("/").filter(Boolean);
|
|
15
|
+
return `${path.join(distDir, ...segments)}.md`;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The exported copy to remove after the build, or `undefined` when the path would leave `distDir` (a route with
|
|
20
|
+
* `..` in it, say). Prerender must only ever delete what the build wrote, never a source page.
|
|
21
|
+
*/
|
|
22
|
+
export const removableMarkdownOutput = (
|
|
23
|
+
distDir: string,
|
|
24
|
+
routePath: string,
|
|
25
|
+
): string | undefined => {
|
|
26
|
+
const output = path.resolve(markdownOutputPath(distDir, routePath));
|
|
27
|
+
const relative = path.relative(path.resolve(distDir), output);
|
|
28
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return output;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Remove the exported `.md` copies of these pages from `distDir`. Only the route decides what is removed; the source
|
|
36
|
+
* file (`filePath` in markdown-info.json) is never touched.
|
|
37
|
+
*/
|
|
38
|
+
export const removeExportedMarkdown = async (
|
|
39
|
+
distDir: string,
|
|
40
|
+
pages: ReadonlyArray<{ routePath: string }>,
|
|
41
|
+
): Promise<void> => {
|
|
42
|
+
await Promise.all(
|
|
43
|
+
pages
|
|
44
|
+
.map((page) => removableMarkdownOutput(distDir, page.routePath))
|
|
45
|
+
.filter((output) => output !== undefined)
|
|
46
|
+
.map((output) => rm(output, { force: true }).catch(() => {})),
|
|
47
|
+
);
|
|
48
|
+
};
|