@mintlify/previewing 4.0.1588 → 4.0.1590
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/__tests__/dev.test.js +3 -3
- package/dist/__tests__/export-assets.test.js +9 -5
- package/dist/__tests__/export-vite.test.d.ts +1 -0
- package/dist/__tests__/export-vite.test.js +101 -0
- package/dist/__tests__/export.test.js +2 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +2 -2
- package/dist/local-preview/export-assets.d.ts +4 -1
- package/dist/local-preview/export-assets.js +6 -6
- package/dist/local-preview/export-next.d.ts +3 -0
- package/dist/local-preview/export-next.js +68 -0
- package/dist/local-preview/export-pages.d.ts +16 -0
- package/dist/local-preview/export-pages.js +36 -0
- package/dist/local-preview/export-vite.d.ts +9 -0
- package/dist/local-preview/export-vite.js +90 -0
- package/dist/local-preview/export.d.ts +0 -1
- package/dist/local-preview/export.js +24 -89
- package/dist/local-preview/index.js +1 -8
- package/dist/local-preview/setupVite.d.ts +9 -0
- package/dist/local-preview/setupVite.js +15 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/export-scripts/README.classic.md +15 -0
- package/export-scripts/README.md +2 -3
- package/package.json +5 -5
|
@@ -2,32 +2,23 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { getAllPathsInDecoratedNav, getAllPathsInDocsNav } from '@mintlify/common';
|
|
3
3
|
import { prebuild } from '@mintlify/prebuild';
|
|
4
4
|
import AdmZip from 'adm-zip';
|
|
5
|
-
import express from 'express';
|
|
6
5
|
import fse, { pathExists } from 'fs-extra';
|
|
7
|
-
import { createServer } from 'http';
|
|
8
6
|
import os from 'os';
|
|
9
7
|
import path from 'path';
|
|
10
8
|
import { fileURLToPath } from 'url';
|
|
11
|
-
import {
|
|
9
|
+
import { CMD_EXEC_PATH, CONTENT_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, PREVIEW_PATH, configureSharedPreviewPath, } from '../constants.js';
|
|
12
10
|
import { addLog, clearLogs } from '../logging-state.js';
|
|
13
11
|
import { ErrorLog, SpinnerLog, SuccessLog, WarningLog } from '../logs.js';
|
|
14
12
|
import { localizeAssets } from './export-assets.js';
|
|
15
|
-
import {
|
|
13
|
+
import { findBasePathConflict, normalizeExportBasePath } from './export-base-path.js';
|
|
16
14
|
import { generateExportLlmsTxt } from './export-llms.js';
|
|
15
|
+
import { createNextRenderer } from './export-next.js';
|
|
17
16
|
import { writeSearchIndex } from './export-search.js';
|
|
17
|
+
import { createViteRenderer } from './export-vite.js';
|
|
18
18
|
import { getGroupFilteredRoutes } from './getGroupFilteredRoutes.js';
|
|
19
19
|
import { isOnline } from './is-online.js';
|
|
20
|
-
import { setupNext } from './setupNext.js';
|
|
21
20
|
import { silentUpdateClient } from './update.js';
|
|
22
|
-
const CONCURRENCY = 10;
|
|
23
|
-
const RSC_CONTENT_TYPE = 'text/x-component';
|
|
24
|
-
const RSC_PAYLOAD_FILE = 'index.txt';
|
|
25
21
|
const EXPORT_SCRIPTS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'export-scripts');
|
|
26
|
-
function resolveRequestRoute(route, rootRoute) {
|
|
27
|
-
if (route === '/' && rootRoute)
|
|
28
|
-
return rootRoute;
|
|
29
|
-
return route;
|
|
30
|
-
}
|
|
31
22
|
function prepareRoutesForExport(routes, groups) {
|
|
32
23
|
if (!groups?.length || routes.includes('/'))
|
|
33
24
|
return { routes };
|
|
@@ -94,59 +85,6 @@ async function collectRoutes(groups) {
|
|
|
94
85
|
}
|
|
95
86
|
return [...routes];
|
|
96
87
|
}
|
|
97
|
-
export async function generatePages(baseUrl, routes, outputDir, rootRoute) {
|
|
98
|
-
const queue = [...routes];
|
|
99
|
-
let failedPageCount = 0;
|
|
100
|
-
async function worker() {
|
|
101
|
-
while (queue.length > 0) {
|
|
102
|
-
const route = queue.shift();
|
|
103
|
-
try {
|
|
104
|
-
const requestRoute = resolveRequestRoute(route, rootRoute);
|
|
105
|
-
const [res, rscRes] = await Promise.all([
|
|
106
|
-
fetch(`${baseUrl}${requestRoute}`),
|
|
107
|
-
fetch(`${baseUrl}${requestRoute}`, { headers: { RSC: '1' } }),
|
|
108
|
-
]);
|
|
109
|
-
const isRscPayload = rscRes.headers.get('content-type')?.startsWith(RSC_CONTENT_TYPE);
|
|
110
|
-
if (!res.ok || !rscRes.ok || !isRscPayload) {
|
|
111
|
-
failedPageCount += 1;
|
|
112
|
-
addLog(_jsx(ErrorLog, { message: `failed to generate ${route} (status ${res.ok ? rscRes.status : res.status})` }));
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
const pageDir = route === '/' ? outputDir : path.join(outputDir, route);
|
|
116
|
-
await fse.ensureDir(pageDir);
|
|
117
|
-
await Promise.all([
|
|
118
|
-
fse.writeFile(path.join(pageDir, 'index.html'), await res.text(), 'utf8'),
|
|
119
|
-
fse.writeFile(path.join(pageDir, RSC_PAYLOAD_FILE), await rscRes.text(), 'utf8'),
|
|
120
|
-
]);
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
failedPageCount += 1;
|
|
124
|
-
addLog(_jsx(ErrorLog, { message: `failed to generate ${route}: ${err instanceof Error ? err.message : 'unknown error'}` }));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
await Promise.all(Array.from({ length: Math.min(CONCURRENCY, routes.length) }, () => worker()));
|
|
129
|
-
return failedPageCount;
|
|
130
|
-
}
|
|
131
|
-
async function startServer(basePath) {
|
|
132
|
-
const app = express();
|
|
133
|
-
const requestHandler = await setupNext(basePath ? { assetPrefix: basePath } : undefined);
|
|
134
|
-
app.use('/', express.static(NEXT_PUBLIC_PATH));
|
|
135
|
-
app.all('*', (req, res) => requestHandler(req, res));
|
|
136
|
-
const server = createServer(app);
|
|
137
|
-
const port = await new Promise((resolve, reject) => {
|
|
138
|
-
server.once('error', reject);
|
|
139
|
-
server.listen(0, () => {
|
|
140
|
-
const addr = server.address();
|
|
141
|
-
if (!addr || typeof addr === 'string') {
|
|
142
|
-
reject(new Error('failed to determine listening port'));
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
resolve(addr.port);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
return { server, port };
|
|
149
|
-
}
|
|
150
88
|
export async function writeStaticUserInfo(tmpDir, groups) {
|
|
151
89
|
if (!groups?.length)
|
|
152
90
|
return;
|
|
@@ -154,11 +92,8 @@ export async function writeStaticUserInfo(tmpDir, groups) {
|
|
|
154
92
|
user: { groups },
|
|
155
93
|
});
|
|
156
94
|
}
|
|
157
|
-
async function bundleStaticAssets(tmpDir, groups, basePath) {
|
|
158
|
-
|
|
159
|
-
if (await pathExists(nextStaticSrc)) {
|
|
160
|
-
await fse.copy(nextStaticSrc, path.join(tmpDir, '_next', 'static'));
|
|
161
|
-
}
|
|
95
|
+
async function bundleStaticAssets(tmpDir, groups, basePath, renderer) {
|
|
96
|
+
await renderer.copyAssets(tmpDir);
|
|
162
97
|
if (await pathExists(NEXT_PUBLIC_PATH)) {
|
|
163
98
|
const publicFiles = await fse.readdir(NEXT_PUBLIC_PATH);
|
|
164
99
|
for (const file of publicFiles) {
|
|
@@ -170,7 +105,7 @@ async function bundleStaticAssets(tmpDir, groups, basePath) {
|
|
|
170
105
|
await writeStaticUserInfo(tmpDir, groups);
|
|
171
106
|
const serveScript = await fse.readFile(path.join(EXPORT_SCRIPTS_DIR, 'serve.js'), 'utf8');
|
|
172
107
|
await fse.writeFile(path.join(tmpDir, 'serve.js'), serveScript.replace("const BASE_PATH = '';", `const BASE_PATH = ${JSON.stringify(basePath)};`));
|
|
173
|
-
await fse.copy(path.join(EXPORT_SCRIPTS_DIR,
|
|
108
|
+
await fse.copy(path.join(EXPORT_SCRIPTS_DIR, renderer.readme), path.join(tmpDir, 'README.md'));
|
|
174
109
|
await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'start-docs.sh'), path.join(tmpDir, 'Start Docs.command'));
|
|
175
110
|
await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'start-docs.bat'), path.join(tmpDir, 'Start Docs.bat'));
|
|
176
111
|
}
|
|
@@ -184,13 +119,10 @@ export async function writeLlmsTxt(tmpDir, routes, basePath = '') {
|
|
|
184
119
|
]);
|
|
185
120
|
await fse.writeFile(llmsTxtPath, generateExportLlmsTxt(docsConfig, generatedNav, routes, basePath), 'utf8');
|
|
186
121
|
}
|
|
187
|
-
async function
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
async function generateExportArchive(routes, outputPath, groups, basePath) {
|
|
193
|
-
const { server, port } = await startServer(basePath);
|
|
122
|
+
async function generateExportArchive(routes, outputPath, groups, basePath, vite) {
|
|
123
|
+
const renderer = vite
|
|
124
|
+
? await createViteRenderer({ groups, basePath: basePath || undefined })
|
|
125
|
+
: await createNextRenderer(groups, basePath);
|
|
194
126
|
const { routes: preparedRoutes, rootRoute } = prepareRoutesForExport(routes, groups);
|
|
195
127
|
const routesToGenerate = withIndexRouteAliases(preparedRoutes);
|
|
196
128
|
let tmpDir;
|
|
@@ -200,14 +132,13 @@ async function generateExportArchive(routes, outputPath, groups, basePath) {
|
|
|
200
132
|
tmpDir = await fse.mkdtemp(path.join(os.tmpdir(), 'mint-export-'));
|
|
201
133
|
const exportDir = tmpDir;
|
|
202
134
|
const failedPageCount = await withExportConsoleSilenced(async () => {
|
|
203
|
-
return generatePages(
|
|
135
|
+
return renderer.generatePages(routesToGenerate, exportDir, rootRoute);
|
|
204
136
|
});
|
|
205
137
|
if (failedPageCount > 0) {
|
|
206
138
|
throw new Error(`failed to export: ${failedPageCount} page(s) could not be generated.`);
|
|
207
139
|
}
|
|
208
140
|
addLog(_jsx(SpinnerLog, { message: "collecting static assets..." }));
|
|
209
|
-
await bundleStaticAssets(exportDir, groups, basePath);
|
|
210
|
-
await applyBasePathToExport(exportDir, basePath);
|
|
141
|
+
await bundleStaticAssets(exportDir, groups, basePath, renderer);
|
|
211
142
|
await writeLlmsTxt(exportDir, routes, basePath);
|
|
212
143
|
addLog(_jsx(SpinnerLog, { message: "building search index..." }));
|
|
213
144
|
const [docsConfig, generatedNav] = await Promise.all([
|
|
@@ -216,7 +147,11 @@ async function generateExportArchive(routes, outputPath, groups, basePath) {
|
|
|
216
147
|
]);
|
|
217
148
|
await writeSearchIndex(exportDir, { generatedNav, docsConfig, groups });
|
|
218
149
|
addLog(_jsx(SpinnerLog, { message: "bundling external assets..." }));
|
|
219
|
-
const
|
|
150
|
+
const clientAssetFailures = await renderer.bundleAssets(exportDir);
|
|
151
|
+
const { failed: assetFailures } = await localizeAssets(exportDir, {
|
|
152
|
+
stylesheetDir: renderer.stylesheetDir,
|
|
153
|
+
});
|
|
154
|
+
const failed = [...clientAssetFailures, ...assetFailures];
|
|
220
155
|
addLog(_jsx(SpinnerLog, { message: "creating zip archive..." }));
|
|
221
156
|
const zip = new AdmZip();
|
|
222
157
|
zip.addLocalFolder(exportDir);
|
|
@@ -231,11 +166,12 @@ async function generateExportArchive(routes, outputPath, groups, basePath) {
|
|
|
231
166
|
if (tmpDir) {
|
|
232
167
|
await fse.remove(tmpDir);
|
|
233
168
|
}
|
|
234
|
-
await
|
|
169
|
+
await renderer.close();
|
|
235
170
|
}
|
|
236
171
|
}
|
|
237
172
|
export const exportSite = async (argv) => {
|
|
238
|
-
|
|
173
|
+
const vite = argv.classic !== true;
|
|
174
|
+
configureSharedPreviewPath(vite ? 'vite' : 'next');
|
|
239
175
|
const hasInternet = await isOnline();
|
|
240
176
|
const clientVersion = argv['client-version'];
|
|
241
177
|
const localClientVersion = argv['local-client-version'];
|
|
@@ -273,7 +209,8 @@ export const exportSite = async (argv) => {
|
|
|
273
209
|
catch (err) {
|
|
274
210
|
await fatal(err instanceof Error && err.message ? err.message : 'failed to prepare export directories');
|
|
275
211
|
}
|
|
276
|
-
|
|
212
|
+
await fse.ensureDir(CONTENT_PATH);
|
|
213
|
+
process.chdir(CONTENT_PATH);
|
|
277
214
|
addLog(_jsx(SpinnerLog, { message: "running prebuild..." }));
|
|
278
215
|
try {
|
|
279
216
|
await withExportConsoleSilenced(async () => {
|
|
@@ -294,10 +231,8 @@ export const exportSite = async (argv) => {
|
|
|
294
231
|
if (conflictingRoute) {
|
|
295
232
|
await fatal(`--base-path ${basePath} conflicts with the page ${conflictingRoute}. Pages can't start with the base path, so pick a different one.`);
|
|
296
233
|
}
|
|
297
|
-
addLog(_jsx(SpinnerLog, { message: "starting local server..." }));
|
|
298
|
-
process.env.MINT_EXPORT = JSON.stringify({ groups, basePath: basePath || undefined });
|
|
299
234
|
try {
|
|
300
|
-
await generateExportArchive(routes, outputPath, groups, basePath);
|
|
235
|
+
await generateExportArchive(routes, outputPath, groups, basePath, vite);
|
|
301
236
|
}
|
|
302
237
|
catch (err) {
|
|
303
238
|
await fatal(err instanceof Error && err.message ? err.message : 'export failed');
|
|
@@ -43,13 +43,6 @@ const startDev = async (argv) => {
|
|
|
43
43
|
const cliVersion = argv.cliVersion;
|
|
44
44
|
const disableOpenApi = argv.disableOpenapi;
|
|
45
45
|
const disablePrefetch = argv.disablePrefetch;
|
|
46
|
-
const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number);
|
|
47
|
-
if (CLIENT_FRAMEWORK === 'vite' && (nodeMajor < 20 || (nodeMajor === 20 && nodeMinor < 11))) {
|
|
48
|
-
clearLogs();
|
|
49
|
-
addLog(_jsx(ErrorLog, { message: `${packageName} dev --beta needs node 20.11 or newer.` }));
|
|
50
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
46
|
await timeDev('ensure preview directory', () => fse.ensureDir(PREVIEW_PATH));
|
|
54
47
|
if (!localClientVersion && !clientVersion && CLIENT_FRAMEWORK === 'next') {
|
|
55
48
|
timeDevSync('seed preview from shared workspace', () => seedPreviewFromShared());
|
|
@@ -126,7 +119,7 @@ const startDev = async (argv) => {
|
|
|
126
119
|
};
|
|
127
120
|
const dev = async (argv) => {
|
|
128
121
|
const port = Number(argv.port ?? 3000);
|
|
129
|
-
configurePreviewPath(port, argv.
|
|
122
|
+
configurePreviewPath(port, argv.classic === true ? 'next' : 'vite');
|
|
130
123
|
const releasePreviewLock = acquirePreviewLock(port);
|
|
131
124
|
try {
|
|
132
125
|
await startDev(argv);
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
type MintExportConfig = {
|
|
3
|
+
groups?: string[];
|
|
4
|
+
basePath?: string;
|
|
5
|
+
};
|
|
2
6
|
type RequestListener = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
7
|
+
export type ExportFetch = (request: Request) => Promise<Response>;
|
|
3
8
|
export declare const setupVite: () => Promise<RequestListener>;
|
|
9
|
+
export declare const setupViteExport: (mintExport: MintExportConfig) => Promise<{
|
|
10
|
+
fetchPage: ExportFetch;
|
|
11
|
+
assetPrefixes: string[];
|
|
12
|
+
}>;
|
|
4
13
|
export {};
|
|
@@ -2,13 +2,26 @@ import fse from 'fs-extra';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { CLIENT_PATH } from '../constants.js';
|
|
5
|
-
|
|
5
|
+
const loadCliEntry = async () => {
|
|
6
6
|
const entryPath = path.join(CLIENT_PATH, 'dist-cli', 'index.js');
|
|
7
7
|
if (!(await fse.pathExists(entryPath))) {
|
|
8
8
|
throw new Error(`Client not built. Run: cd <path>/apps/client-vite && pnpm build:cli`);
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
return { entry: await import(pathToFileURL(entryPath).href), entryPath };
|
|
11
|
+
};
|
|
12
|
+
export const setupVite = async () => {
|
|
13
|
+
const { entry, entryPath } = await loadCliEntry();
|
|
11
14
|
if (!entry.createCliHandler)
|
|
12
15
|
throw new Error(`${entryPath} does not export createCliHandler`);
|
|
13
16
|
return entry.createCliHandler();
|
|
14
17
|
};
|
|
18
|
+
export const setupViteExport = async (mintExport) => {
|
|
19
|
+
const { entry } = await loadCliEntry();
|
|
20
|
+
if (!entry.createCliExportFetch || !entry.exportAssetPrefixes) {
|
|
21
|
+
throw new Error('this client version is too old to export, rerun online to fetch the latest client or export with --classic');
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
fetchPage: await entry.createCliExportFetch(mintExport),
|
|
25
|
+
assetPrefixes: entry.exportAssetPrefixes,
|
|
26
|
+
};
|
|
27
|
+
};
|