@mintlify/previewing 4.0.527 → 4.0.529
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.d.ts +1 -0
- package/dist/__tests__/dev.test.js +125 -0
- package/dist/__tests__/downloadTargetMint.test.d.ts +1 -0
- package/dist/__tests__/downloadTargetMint.test.js +220 -0
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +3 -2
- package/dist/local-preview/client.d.ts +5 -3
- package/dist/local-preview/client.js +40 -57
- package/dist/local-preview/index.js +18 -107
- package/dist/local-preview/listener/generate.js +15 -21
- package/dist/local-preview/listener/generateDependentSnippets.js +23 -26
- package/dist/local-preview/listener/generatePagesWithImports.js +11 -20
- package/dist/local-preview/listener/getDocsState.js +10 -19
- package/dist/local-preview/listener/getSnippets.js +6 -15
- package/dist/local-preview/listener/index.js +45 -54
- package/dist/local-preview/listener/resolveAllImports.js +4 -13
- package/dist/local-preview/listener/update.js +14 -23
- package/dist/local-preview/listener/utils.js +6 -15
- package/dist/local-preview/run.d.ts +2 -0
- package/dist/local-preview/run.js +47 -0
- package/dist/local-preview/setupNext.d.ts +22 -0
- package/dist/local-preview/setupNext.js +41 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/util.d.ts +2 -0
- package/dist/util.js +11 -0
- package/package.json +6 -3
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { findAndRemoveImports, hasImports, getFileCategory, openApiCheck, stringifyTree, } from '@mintlify/common';
|
|
11
2
|
import { createPage, MintConfigUpdater, DocsConfigUpdater, preparseMdxTree, } from '@mintlify/prebuild';
|
|
12
3
|
import Chalk from 'chalk';
|
|
@@ -35,9 +26,9 @@ const listener = (callback) => {
|
|
|
35
26
|
.on('change', (filename) => onChangeEvent(filename, callback))
|
|
36
27
|
.on('unlink', onUnlinkEvent);
|
|
37
28
|
};
|
|
38
|
-
const onAddEvent = (filename, callback) =>
|
|
29
|
+
const onAddEvent = async (filename, callback) => {
|
|
39
30
|
try {
|
|
40
|
-
const category =
|
|
31
|
+
const category = await onUpdateEvent(filename, callback);
|
|
41
32
|
switch (category) {
|
|
42
33
|
case 'page':
|
|
43
34
|
console.log('New page detected: ', filename);
|
|
@@ -67,10 +58,10 @@ const onAddEvent = (filename, callback) => __awaiter(void 0, void 0, void 0, fun
|
|
|
67
58
|
catch (error) {
|
|
68
59
|
console.error(error.message);
|
|
69
60
|
}
|
|
70
|
-
}
|
|
71
|
-
const onChangeEvent = (filename, callback) =>
|
|
61
|
+
};
|
|
62
|
+
const onChangeEvent = async (filename, callback) => {
|
|
72
63
|
try {
|
|
73
|
-
const category =
|
|
64
|
+
const category = await onUpdateEvent(filename, callback);
|
|
74
65
|
switch (category) {
|
|
75
66
|
case 'page':
|
|
76
67
|
console.log('Page edited: ', filename);
|
|
@@ -100,8 +91,8 @@ const onChangeEvent = (filename, callback) => __awaiter(void 0, void 0, void 0,
|
|
|
100
91
|
catch (error) {
|
|
101
92
|
console.error(error.message);
|
|
102
93
|
}
|
|
103
|
-
}
|
|
104
|
-
const onUnlinkEvent = (filename) =>
|
|
94
|
+
};
|
|
95
|
+
const onUnlinkEvent = async (filename) => {
|
|
105
96
|
try {
|
|
106
97
|
const potentialCategory = getFileCategory(filename);
|
|
107
98
|
const targetPath = getTargetPath(potentialCategory, filename);
|
|
@@ -113,7 +104,7 @@ const onUnlinkEvent = (filename) => __awaiter(void 0, void 0, void 0, function*
|
|
|
113
104
|
potentialCategory === 'snippet-v2' ||
|
|
114
105
|
potentialCategory === 'css' ||
|
|
115
106
|
potentialCategory === 'js') {
|
|
116
|
-
|
|
107
|
+
await fse.remove(targetPath);
|
|
117
108
|
}
|
|
118
109
|
switch (potentialCategory) {
|
|
119
110
|
case 'page':
|
|
@@ -125,16 +116,16 @@ const onUnlinkEvent = (filename) => __awaiter(void 0, void 0, void 0, function*
|
|
|
125
116
|
break;
|
|
126
117
|
case 'mintConfig':
|
|
127
118
|
console.error('⚠️ mint.json has been deleted.');
|
|
128
|
-
|
|
119
|
+
await validateConfigFiles();
|
|
129
120
|
break;
|
|
130
121
|
case 'docsConfig':
|
|
131
122
|
console.error('⚠️ docs.json has been deleted.');
|
|
132
|
-
|
|
123
|
+
await validateConfigFiles();
|
|
133
124
|
break;
|
|
134
125
|
case 'potentialJsonOpenApiSpec':
|
|
135
126
|
case 'potentialYamlOpenApiSpec':
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
await updateOpenApiFiles();
|
|
128
|
+
await updateGeneratedNav();
|
|
138
129
|
break;
|
|
139
130
|
case 'css':
|
|
140
131
|
console.log(`CSS file deleted: ${filename}`);
|
|
@@ -150,7 +141,7 @@ const onUnlinkEvent = (filename) => __awaiter(void 0, void 0, void 0, function*
|
|
|
150
141
|
catch (error) {
|
|
151
142
|
console.error(error.message);
|
|
152
143
|
}
|
|
153
|
-
}
|
|
144
|
+
};
|
|
154
145
|
const getTargetPath = (potentialCategory, filePath) => {
|
|
155
146
|
switch (potentialCategory) {
|
|
156
147
|
case 'page':
|
|
@@ -172,12 +163,12 @@ const getTargetPath = (potentialCategory, filePath) => {
|
|
|
172
163
|
throw new Error('Invalid category');
|
|
173
164
|
}
|
|
174
165
|
};
|
|
175
|
-
const validateConfigFiles = () =>
|
|
166
|
+
const validateConfigFiles = async () => {
|
|
176
167
|
try {
|
|
177
168
|
const mintConfigPath = pathUtil.join(CMD_EXEC_PATH, 'mint.json');
|
|
178
169
|
const docsConfigPath = pathUtil.join(CMD_EXEC_PATH, 'docs.json');
|
|
179
|
-
const mintConfigExists =
|
|
180
|
-
const docsConfigExists =
|
|
170
|
+
const mintConfigExists = await fse.pathExists(mintConfigPath);
|
|
171
|
+
const docsConfigExists = await fse.pathExists(docsConfigPath);
|
|
181
172
|
if (!mintConfigExists && !docsConfigExists) {
|
|
182
173
|
console.error('⚠️ Error: Neither mint.json nor docs.json found in the directory');
|
|
183
174
|
process.exit(1);
|
|
@@ -186,13 +177,13 @@ const validateConfigFiles = () => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
186
177
|
catch (error) {
|
|
187
178
|
console.error('⚠️ Error validating configuration files:', error);
|
|
188
179
|
}
|
|
189
|
-
}
|
|
180
|
+
};
|
|
190
181
|
/**
|
|
191
182
|
* This function is called when a file is added or changed
|
|
192
183
|
* @param filename
|
|
193
184
|
* @returns FileCategory
|
|
194
185
|
*/
|
|
195
|
-
const onUpdateEvent = (filename, callback) =>
|
|
186
|
+
const onUpdateEvent = async (filename, callback) => {
|
|
196
187
|
const filePath = pathUtil.join(CMD_EXEC_PATH, filename);
|
|
197
188
|
const potentialCategory = getFileCategory(filename);
|
|
198
189
|
const targetPath = getTargetPath(potentialCategory, filename);
|
|
@@ -204,46 +195,46 @@ const onUpdateEvent = (filename, callback) => __awaiter(void 0, void 0, void 0,
|
|
|
204
195
|
switch (potentialCategory) {
|
|
205
196
|
case 'page': {
|
|
206
197
|
regenerateNav = true;
|
|
207
|
-
let contentStr = (
|
|
208
|
-
const tree =
|
|
209
|
-
const importsResponse =
|
|
198
|
+
let contentStr = (await readFile(filePath)).toString();
|
|
199
|
+
const tree = await preparseMdxTree(contentStr, CMD_EXEC_PATH, filePath);
|
|
200
|
+
const importsResponse = await findAndRemoveImports(tree);
|
|
210
201
|
if (hasImports(importsResponse)) {
|
|
211
|
-
contentStr = stringifyTree(
|
|
202
|
+
contentStr = stringifyTree(await resolveAllImports({ ...importsResponse, filename }));
|
|
212
203
|
}
|
|
213
|
-
const { pageContent } =
|
|
214
|
-
|
|
204
|
+
const { pageContent } = await createPage(filename, contentStr, CMD_EXEC_PATH, [], []);
|
|
205
|
+
await fse.outputFile(targetPath, pageContent, {
|
|
215
206
|
flag: 'w',
|
|
216
207
|
});
|
|
217
208
|
break;
|
|
218
209
|
}
|
|
219
210
|
case 'snippet': {
|
|
220
|
-
|
|
211
|
+
await fse.copy(filePath, targetPath);
|
|
221
212
|
break;
|
|
222
213
|
}
|
|
223
214
|
case 'snippet-v2': {
|
|
224
|
-
let contentStr = (
|
|
225
|
-
const tree =
|
|
226
|
-
const importsResponse =
|
|
215
|
+
let contentStr = (await readFile(filePath)).toString();
|
|
216
|
+
const tree = await preparseMdxTree(contentStr, CMD_EXEC_PATH, filePath);
|
|
217
|
+
const importsResponse = await findAndRemoveImports(tree);
|
|
227
218
|
if (hasImports(importsResponse)) {
|
|
228
|
-
contentStr = stringifyTree(
|
|
219
|
+
contentStr = stringifyTree(await resolveAllImports({ ...importsResponse, filename }));
|
|
229
220
|
}
|
|
230
|
-
|
|
221
|
+
await fse.outputFile(targetPath, contentStr, {
|
|
231
222
|
flag: 'w',
|
|
232
223
|
});
|
|
233
|
-
const updatedSnippets =
|
|
234
|
-
|
|
224
|
+
const updatedSnippets = await generateDependentSnippets(filename, importsResponse);
|
|
225
|
+
await generatePagesWithImports(new Set(updatedSnippets));
|
|
235
226
|
break;
|
|
236
227
|
}
|
|
237
228
|
case 'mintConfig':
|
|
238
229
|
case 'docsConfig': {
|
|
239
230
|
regenerateNav = true;
|
|
240
231
|
try {
|
|
241
|
-
const { mintConfig, openApiFiles, docsConfig } =
|
|
232
|
+
const { mintConfig, openApiFiles, docsConfig } = await getDocsState();
|
|
242
233
|
if (mintConfig) {
|
|
243
|
-
|
|
234
|
+
await MintConfigUpdater.writeConfigFile(mintConfig, CLIENT_PATH);
|
|
244
235
|
}
|
|
245
|
-
|
|
246
|
-
|
|
236
|
+
await DocsConfigUpdater.writeConfigFile(docsConfig, CLIENT_PATH);
|
|
237
|
+
await updateOpenApiFiles(openApiFiles);
|
|
247
238
|
}
|
|
248
239
|
catch (err) {
|
|
249
240
|
console.error(err);
|
|
@@ -254,19 +245,19 @@ const onUpdateEvent = (filename, callback) => __awaiter(void 0, void 0, void 0,
|
|
|
254
245
|
case 'potentialJsonOpenApiSpec': {
|
|
255
246
|
let doc;
|
|
256
247
|
try {
|
|
257
|
-
const file =
|
|
258
|
-
doc =
|
|
248
|
+
const file = await fs.readFile(filePath, 'utf-8');
|
|
249
|
+
doc = await openApiCheck(yaml.load(file));
|
|
259
250
|
}
|
|
260
|
-
catch
|
|
251
|
+
catch {
|
|
261
252
|
doc = undefined;
|
|
262
253
|
}
|
|
263
254
|
if (doc) {
|
|
264
|
-
|
|
255
|
+
await upsertOpenApiFile({
|
|
265
256
|
filename: pathUtil.parse(filename).name,
|
|
266
257
|
originalFileLocation: '/' + filename,
|
|
267
258
|
spec: doc,
|
|
268
259
|
});
|
|
269
|
-
|
|
260
|
+
await updateOpenApiFiles();
|
|
270
261
|
regenerateNav = true;
|
|
271
262
|
category = 'openApi';
|
|
272
263
|
}
|
|
@@ -275,8 +266,8 @@ const onUpdateEvent = (filename, callback) => __awaiter(void 0, void 0, void 0,
|
|
|
275
266
|
case 'css':
|
|
276
267
|
case 'js':
|
|
277
268
|
case 'staticFile': {
|
|
278
|
-
if (
|
|
279
|
-
|
|
269
|
+
if (await isFileSizeValid(filePath, 5)) {
|
|
270
|
+
await fse.copy(filePath, targetPath);
|
|
280
271
|
}
|
|
281
272
|
else {
|
|
282
273
|
console.error(Chalk.red(`🚨 The file at ${filename} is too big. The maximum file size is 5 mb.`));
|
|
@@ -286,9 +277,9 @@ const onUpdateEvent = (filename, callback) => __awaiter(void 0, void 0, void 0,
|
|
|
286
277
|
}
|
|
287
278
|
if (regenerateNav) {
|
|
288
279
|
// TODO: Instead of re-generating the entire nav, optimize by just updating the specific page that changed.
|
|
289
|
-
|
|
280
|
+
await updateGeneratedNav();
|
|
290
281
|
}
|
|
291
282
|
callback();
|
|
292
283
|
return category;
|
|
293
|
-
}
|
|
284
|
+
};
|
|
294
285
|
export default listener;
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { resolveAllImports as baseResolveAllImports } from '@mintlify/common';
|
|
11
2
|
import { getProcessedSnippets } from './getSnippets.js';
|
|
12
|
-
export const resolveAllImports = (fileWithImports) =>
|
|
13
|
-
const snippets =
|
|
14
|
-
return
|
|
3
|
+
export const resolveAllImports = async (fileWithImports) => {
|
|
4
|
+
const snippets = await getProcessedSnippets();
|
|
5
|
+
return await baseResolveAllImports({
|
|
15
6
|
snippets,
|
|
16
7
|
fileWithImports,
|
|
17
8
|
});
|
|
18
|
-
}
|
|
9
|
+
};
|
|
@@ -1,43 +1,34 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import fse from 'fs-extra';
|
|
11
2
|
import { join } from 'path';
|
|
12
3
|
import { NEXT_PROPS_PATH } from '../../constants.js';
|
|
13
4
|
import { generateNav } from './generate.js';
|
|
14
5
|
import { getDocsState } from './getDocsState.js';
|
|
15
6
|
import { readJsonFile } from './utils.js';
|
|
16
|
-
export const updateGeneratedNav = () =>
|
|
17
|
-
const { pagesAcc, docsConfig } =
|
|
18
|
-
const generatedDocsNav =
|
|
7
|
+
export const updateGeneratedNav = async () => {
|
|
8
|
+
const { pagesAcc, docsConfig } = await getDocsState();
|
|
9
|
+
const generatedDocsNav = await generateNav(pagesAcc, docsConfig);
|
|
19
10
|
const targetDocsPath = join(NEXT_PROPS_PATH, 'generatedDocsNav.json');
|
|
20
|
-
|
|
11
|
+
await fse.outputFile(targetDocsPath, JSON.stringify(generatedDocsNav, null, 2), {
|
|
21
12
|
flag: 'w',
|
|
22
13
|
});
|
|
23
|
-
}
|
|
24
|
-
export const updateOpenApiFiles = (providedOpenApiFiles) =>
|
|
14
|
+
};
|
|
15
|
+
export const updateOpenApiFiles = async (providedOpenApiFiles) => {
|
|
25
16
|
if (providedOpenApiFiles == undefined) {
|
|
26
|
-
const { openApiFiles } =
|
|
17
|
+
const { openApiFiles } = await getDocsState();
|
|
27
18
|
providedOpenApiFiles = openApiFiles;
|
|
28
19
|
}
|
|
29
20
|
const targetPath = join(NEXT_PROPS_PATH, 'openApiFiles.json');
|
|
30
|
-
|
|
21
|
+
await fse.outputFile(targetPath, JSON.stringify(providedOpenApiFiles, null, 2), {
|
|
31
22
|
flag: 'w',
|
|
32
23
|
});
|
|
33
|
-
}
|
|
34
|
-
export const upsertOpenApiFile = (openApiFile) =>
|
|
24
|
+
};
|
|
25
|
+
export const upsertOpenApiFile = async (openApiFile) => {
|
|
35
26
|
const sourcePath = join(NEXT_PROPS_PATH, 'openApiFiles.json');
|
|
36
27
|
let existingOpenApiFiles = [];
|
|
37
28
|
try {
|
|
38
|
-
existingOpenApiFiles = (
|
|
29
|
+
existingOpenApiFiles = (await readJsonFile(sourcePath));
|
|
39
30
|
}
|
|
40
|
-
catch
|
|
31
|
+
catch { }
|
|
41
32
|
const existingIndex = existingOpenApiFiles.findIndex((file) => file.originalFileLocation === openApiFile.originalFileLocation);
|
|
42
33
|
if (existingIndex >= 0) {
|
|
43
34
|
existingOpenApiFiles[existingIndex] = openApiFile;
|
|
@@ -45,7 +36,7 @@ export const upsertOpenApiFile = (openApiFile) => __awaiter(void 0, void 0, void
|
|
|
45
36
|
else {
|
|
46
37
|
existingOpenApiFiles.push(openApiFile);
|
|
47
38
|
}
|
|
48
|
-
|
|
39
|
+
await fse.outputFile(sourcePath, JSON.stringify(existingOpenApiFiles, null, 2), {
|
|
49
40
|
flag: 'w',
|
|
50
41
|
});
|
|
51
|
-
}
|
|
42
|
+
};
|
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { promises as _promises } from 'fs';
|
|
11
2
|
import fse from 'fs-extra';
|
|
12
3
|
const { stat } = _promises;
|
|
13
4
|
export const getFileExtension = (filename) => {
|
|
14
5
|
return filename.substring(filename.lastIndexOf('.') + 1, filename.length) || filename;
|
|
15
6
|
};
|
|
16
|
-
export const isFileSizeValid = (path, maxFileSizeInMb) =>
|
|
7
|
+
export const isFileSizeValid = async (path, maxFileSizeInMb) => {
|
|
17
8
|
const maxFileSizeBytes = maxFileSizeInMb * 1000000;
|
|
18
|
-
const stats =
|
|
9
|
+
const stats = await stat(path);
|
|
19
10
|
return stats.size <= maxFileSizeBytes;
|
|
20
|
-
}
|
|
11
|
+
};
|
|
21
12
|
export function isError(obj) {
|
|
22
13
|
return Object.prototype.toString.call(obj) === '[object Error]';
|
|
23
14
|
}
|
|
24
|
-
export const readJsonFile = (path) =>
|
|
25
|
-
const file =
|
|
15
|
+
export const readJsonFile = async (path) => {
|
|
16
|
+
const file = await fse.readFile(path, 'utf-8');
|
|
26
17
|
return JSON.parse(file);
|
|
27
|
-
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import open from 'better-opn';
|
|
2
|
+
import Chalk from 'chalk';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import { createServer } from 'http';
|
|
5
|
+
import { Server as SocketServer } from 'socket.io';
|
|
6
|
+
import { NEXT_PUBLIC_PATH } from '../constants.js';
|
|
7
|
+
import { maybeFixMissingWindowsEnvVar } from '../util.js';
|
|
8
|
+
import listener from './listener/index.js';
|
|
9
|
+
import { setupNext } from './setupNext.js';
|
|
10
|
+
export const run = async (argv) => {
|
|
11
|
+
const port = argv.port || '3000';
|
|
12
|
+
const currentPort = parseInt(port, 10) || 3000;
|
|
13
|
+
const app = express();
|
|
14
|
+
const server = createServer(app);
|
|
15
|
+
const io = new SocketServer(server);
|
|
16
|
+
const requestHandler = await setupNext();
|
|
17
|
+
// next-server is bugged, public files added after starting aren't served
|
|
18
|
+
app.use('/', express.static(NEXT_PUBLIC_PATH));
|
|
19
|
+
app.all('*', (req, res) => requestHandler(req, res));
|
|
20
|
+
const onChange = () => {
|
|
21
|
+
io.emit('reload');
|
|
22
|
+
};
|
|
23
|
+
server.listen(currentPort, () => {
|
|
24
|
+
console.log(`${Chalk.green(`Your local preview is available at http://localhost:${port}`)}`);
|
|
25
|
+
// Note: We wait for this exact text to be sure the server is ready in the cli e2e test,
|
|
26
|
+
// if it changes, the test will fail/require an update.
|
|
27
|
+
console.log(`${Chalk.green('Press Ctrl+C any time to stop the local preview.')}`);
|
|
28
|
+
/**
|
|
29
|
+
* We're running into a known bug with the `open` package, where Windows machines error out because process.env.SYSTEMROOT is not set:
|
|
30
|
+
* https://github.com/sindresorhus/open/issues/292
|
|
31
|
+
*
|
|
32
|
+
* Let's use the same workaround that this project did:
|
|
33
|
+
* https://github.com/sanity-io/sanity/pull/4221/files#diff-aeb574e1becf61f21fdf87fbea709669c93d604d660dad4b0f9e24527a2fb54bR256-R262
|
|
34
|
+
*/
|
|
35
|
+
maybeFixMissingWindowsEnvVar();
|
|
36
|
+
if (argv.open) {
|
|
37
|
+
void open(`http://localhost:${port}`);
|
|
38
|
+
}
|
|
39
|
+
// exit with successful status
|
|
40
|
+
const onExit = () => {
|
|
41
|
+
process.exit(0);
|
|
42
|
+
};
|
|
43
|
+
process.on('SIGINT', onExit);
|
|
44
|
+
process.on('SIGTERM', onExit);
|
|
45
|
+
});
|
|
46
|
+
listener(onChange);
|
|
47
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When creating a standalone build, next.js outputs a server.js file that can be used as
|
|
3
|
+
* an entry point into the server. However, because we want to customize some parts of the
|
|
4
|
+
* http server (adding a socket.io server, serving the whole public directory), we
|
|
5
|
+
* create the server ourselves, and just reproduce the setup that next.js would do.
|
|
6
|
+
*
|
|
7
|
+
* Because we need to directly import from node_modules files, this solution seems very hacky,
|
|
8
|
+
* but it is arguably no more hacky than using the server.js that ships with the standalone
|
|
9
|
+
* build.
|
|
10
|
+
*
|
|
11
|
+
* This function attempts to replicate the behavior of two next.js files:
|
|
12
|
+
* - environment setup from server.js
|
|
13
|
+
* - initialization of the request handler from start-server.ts
|
|
14
|
+
*
|
|
15
|
+
* Links:
|
|
16
|
+
* - [standalone build](https://nextjs.org/docs/pages/api-reference/next-config-js/output#automatically-copying-traced-files)
|
|
17
|
+
* - [server.js](https://github.com/vercel/next.js/blob/492156b4c5e2559b2a280f7d483cd85a8e8742a9/packages/next/src/build/utils.ts#L2108-L2113) (created programmatically)
|
|
18
|
+
* - [start-server.ts](https://github.com/vercel/next.js/blob/492156b4c5e2559b2a280f7d483cd85a8e8742a9/packages/next/src/server/lib/start-server.ts#L296-L308)
|
|
19
|
+
*
|
|
20
|
+
* @returns the request handler provided by next.js
|
|
21
|
+
*/
|
|
22
|
+
export declare const setupNext: () => Promise<any>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fse from 'fs-extra';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { CLIENT_PATH, NEXT_CONFIG_PATH, NEXT_ROUTER_SERVER_PATH, NEXT_SIDE_EFFECT_PATH, } from '../constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* When creating a standalone build, next.js outputs a server.js file that can be used as
|
|
6
|
+
* an entry point into the server. However, because we want to customize some parts of the
|
|
7
|
+
* http server (adding a socket.io server, serving the whole public directory), we
|
|
8
|
+
* create the server ourselves, and just reproduce the setup that next.js would do.
|
|
9
|
+
*
|
|
10
|
+
* Because we need to directly import from node_modules files, this solution seems very hacky,
|
|
11
|
+
* but it is arguably no more hacky than using the server.js that ships with the standalone
|
|
12
|
+
* build.
|
|
13
|
+
*
|
|
14
|
+
* This function attempts to replicate the behavior of two next.js files:
|
|
15
|
+
* - environment setup from server.js
|
|
16
|
+
* - initialization of the request handler from start-server.ts
|
|
17
|
+
*
|
|
18
|
+
* Links:
|
|
19
|
+
* - [standalone build](https://nextjs.org/docs/pages/api-reference/next-config-js/output#automatically-copying-traced-files)
|
|
20
|
+
* - [server.js](https://github.com/vercel/next.js/blob/492156b4c5e2559b2a280f7d483cd85a8e8742a9/packages/next/src/build/utils.ts#L2108-L2113) (created programmatically)
|
|
21
|
+
* - [start-server.ts](https://github.com/vercel/next.js/blob/492156b4c5e2559b2a280f7d483cd85a8e8742a9/packages/next/src/server/lib/start-server.ts#L296-L308)
|
|
22
|
+
*
|
|
23
|
+
* @returns the request handler provided by next.js
|
|
24
|
+
*/
|
|
25
|
+
export const setupNext = async () => {
|
|
26
|
+
const hostname = process.env.HOSTNAME || 'localhost';
|
|
27
|
+
const { config } = await JSON.parse(fse.readFileSync(NEXT_CONFIG_PATH, 'utf8'));
|
|
28
|
+
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config);
|
|
29
|
+
// The server.js provided by next.js's standalone build does a similar import of this file.
|
|
30
|
+
// Not sure what side effects are being created, but want to change as little as possible.
|
|
31
|
+
// Also, Windows requires us to use `pathToFileURL` (see #899)
|
|
32
|
+
await import(pathToFileURL(NEXT_SIDE_EFFECT_PATH).href);
|
|
33
|
+
const { initialize } = await import(pathToFileURL(NEXT_ROUTER_SERVER_PATH).href);
|
|
34
|
+
const [requestHandler] = await initialize({
|
|
35
|
+
dir: CLIENT_PATH,
|
|
36
|
+
dev: false,
|
|
37
|
+
hostname,
|
|
38
|
+
minimalMode: true,
|
|
39
|
+
});
|
|
40
|
+
return requestHandler;
|
|
41
|
+
};
|