almostnode 0.2.4 → 0.2.6
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/LICENSE +1 -1
- package/dist/__sw__.js +32 -1
- package/dist/assets/{runtime-worker-D9x_Ddwz.js → runtime-worker-B8_LZkBX.js} +85 -32
- package/dist/assets/runtime-worker-B8_LZkBX.js.map +1 -0
- package/dist/frameworks/next-dev-server.d.ts +63 -0
- package/dist/frameworks/next-dev-server.d.ts.map +1 -1
- package/dist/frameworks/tailwind-config-loader.d.ts +32 -0
- package/dist/frameworks/tailwind-config-loader.d.ts.map +1 -0
- package/dist/frameworks/vite-dev-server.d.ts +1 -0
- package/dist/frameworks/vite-dev-server.d.ts.map +1 -1
- package/dist/index.cjs +995 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +975 -60
- package/dist/index.mjs.map +1 -1
- package/dist/macaly-demo.d.ts +42 -0
- package/dist/macaly-demo.d.ts.map +1 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/types/package-json.d.ts +16 -0
- package/dist/types/package-json.d.ts.map +1 -0
- package/dist/utils/hash.d.ts +6 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/virtual-fs.d.ts +1 -0
- package/dist/virtual-fs.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/frameworks/next-dev-server.ts +940 -34
- package/src/frameworks/tailwind-config-loader.ts +206 -0
- package/src/frameworks/vite-dev-server.ts +25 -0
- package/src/macaly-demo.ts +172 -0
- package/src/runtime.ts +84 -25
- package/src/types/package-json.ts +15 -0
- package/src/utils/hash.ts +12 -0
- package/src/virtual-fs.ts +14 -10
- package/dist/assets/runtime-worker-D9x_Ddwz.js.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -39,7 +39,8 @@ let __tla = (async () => {
|
|
|
39
39
|
__publicField(this, "eventListeners", /* @__PURE__ */ new Map());
|
|
40
40
|
this.root = {
|
|
41
41
|
type: "directory",
|
|
42
|
-
children: /* @__PURE__ */ new Map()
|
|
42
|
+
children: /* @__PURE__ */ new Map(),
|
|
43
|
+
mtime: Date.now()
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
on(event, listener) {
|
|
@@ -152,7 +153,8 @@ let __tla = (async () => {
|
|
|
152
153
|
const content = typeof data === "string" ? this.encoder.encode(data) : data;
|
|
153
154
|
parent.children.set(basename2, {
|
|
154
155
|
type: "file",
|
|
155
|
-
content
|
|
156
|
+
content,
|
|
157
|
+
mtime: Date.now()
|
|
156
158
|
});
|
|
157
159
|
if (emitEvent) {
|
|
158
160
|
this.notifyWatchers(normalized, existed ? "change" : "rename");
|
|
@@ -213,7 +215,8 @@ let __tla = (async () => {
|
|
|
213
215
|
if (!child) {
|
|
214
216
|
child = {
|
|
215
217
|
type: "directory",
|
|
216
|
-
children: /* @__PURE__ */ new Map()
|
|
218
|
+
children: /* @__PURE__ */ new Map(),
|
|
219
|
+
mtime: Date.now()
|
|
217
220
|
};
|
|
218
221
|
current.children.set(segment, child);
|
|
219
222
|
} else if (child.type !== "directory") {
|
|
@@ -232,8 +235,8 @@ let __tla = (async () => {
|
|
|
232
235
|
if (!node) {
|
|
233
236
|
throw createNodeError("ENOENT", "stat", path2);
|
|
234
237
|
}
|
|
235
|
-
const now = Date.now();
|
|
236
238
|
const size = node.type === "file" ? ((_a2 = node.content) == null ? void 0 : _a2.length) || 0 : 0;
|
|
239
|
+
const mtime = node.mtime;
|
|
237
240
|
return {
|
|
238
241
|
isFile: () => node.type === "file",
|
|
239
242
|
isDirectory: () => node.type === "directory",
|
|
@@ -244,14 +247,14 @@ let __tla = (async () => {
|
|
|
244
247
|
isSocket: () => false,
|
|
245
248
|
size,
|
|
246
249
|
mode: node.type === "directory" ? 493 : 420,
|
|
247
|
-
mtime: new Date(
|
|
248
|
-
atime: new Date(
|
|
249
|
-
ctime: new Date(
|
|
250
|
-
birthtime: new Date(
|
|
251
|
-
mtimeMs:
|
|
252
|
-
atimeMs:
|
|
253
|
-
ctimeMs:
|
|
254
|
-
birthtimeMs:
|
|
250
|
+
mtime: new Date(mtime),
|
|
251
|
+
atime: new Date(mtime),
|
|
252
|
+
ctime: new Date(mtime),
|
|
253
|
+
birthtime: new Date(mtime),
|
|
254
|
+
mtimeMs: mtime,
|
|
255
|
+
atimeMs: mtime,
|
|
256
|
+
ctimeMs: mtime,
|
|
257
|
+
birthtimeMs: mtime,
|
|
255
258
|
nlink: 1,
|
|
256
259
|
uid: 1e3,
|
|
257
260
|
gid: 1e3,
|
|
@@ -305,7 +308,8 @@ let __tla = (async () => {
|
|
|
305
308
|
}
|
|
306
309
|
parent.children.set(basename2, {
|
|
307
310
|
type: "directory",
|
|
308
|
-
children: /* @__PURE__ */ new Map()
|
|
311
|
+
children: /* @__PURE__ */ new Map(),
|
|
312
|
+
mtime: Date.now()
|
|
309
313
|
});
|
|
310
314
|
}
|
|
311
315
|
readdirSync(path2) {
|
|
@@ -589,6 +593,14 @@ let __tla = (async () => {
|
|
|
589
593
|
};
|
|
590
594
|
}
|
|
591
595
|
};
|
|
596
|
+
function simpleHash(str) {
|
|
597
|
+
let hash = 0;
|
|
598
|
+
for (let i = 0; i < str.length; i++) {
|
|
599
|
+
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
600
|
+
hash |= 0;
|
|
601
|
+
}
|
|
602
|
+
return hash.toString(36);
|
|
603
|
+
}
|
|
592
604
|
class Dirent {
|
|
593
605
|
constructor(name, isDirectory, isFile) {
|
|
594
606
|
__publicField(this, "name");
|
|
@@ -9188,7 +9200,23 @@ let __tla = (async () => {
|
|
|
9188
9200
|
"@sentry/node": sentryShim,
|
|
9189
9201
|
"@sentry/core": sentryShim
|
|
9190
9202
|
};
|
|
9191
|
-
function createRequire(vfs, fsShim, process, currentDir, moduleCache, options) {
|
|
9203
|
+
function createRequire(vfs, fsShim, process, currentDir, moduleCache, options, processedCodeCache) {
|
|
9204
|
+
const resolutionCache = /* @__PURE__ */ new Map();
|
|
9205
|
+
const packageJsonCache = /* @__PURE__ */ new Map();
|
|
9206
|
+
const getParsedPackageJson = (pkgPath) => {
|
|
9207
|
+
if (packageJsonCache.has(pkgPath)) {
|
|
9208
|
+
return packageJsonCache.get(pkgPath);
|
|
9209
|
+
}
|
|
9210
|
+
try {
|
|
9211
|
+
const content = vfs.readFileSync(pkgPath, "utf8");
|
|
9212
|
+
const parsed = JSON.parse(content);
|
|
9213
|
+
packageJsonCache.set(pkgPath, parsed);
|
|
9214
|
+
return parsed;
|
|
9215
|
+
} catch {
|
|
9216
|
+
packageJsonCache.set(pkgPath, null);
|
|
9217
|
+
return null;
|
|
9218
|
+
}
|
|
9219
|
+
};
|
|
9192
9220
|
const resolveModule = (id, fromDir) => {
|
|
9193
9221
|
if (id.startsWith("node:")) {
|
|
9194
9222
|
id = id.slice(5);
|
|
@@ -9196,15 +9224,25 @@ let __tla = (async () => {
|
|
|
9196
9224
|
if (builtinModules[id] || id === "fs" || id === "process" || id === "url" || id === "querystring" || id === "util") {
|
|
9197
9225
|
return id;
|
|
9198
9226
|
}
|
|
9227
|
+
const cacheKey = `${fromDir}|${id}`;
|
|
9228
|
+
const cached = resolutionCache.get(cacheKey);
|
|
9229
|
+
if (cached !== void 0) {
|
|
9230
|
+
if (cached === null) {
|
|
9231
|
+
throw new Error(`Cannot find module '${id}'`);
|
|
9232
|
+
}
|
|
9233
|
+
return cached;
|
|
9234
|
+
}
|
|
9199
9235
|
if (id.startsWith("./") || id.startsWith("../") || id.startsWith("/")) {
|
|
9200
9236
|
const resolved = id.startsWith("/") ? id : resolve$2(fromDir, id);
|
|
9201
9237
|
if (vfs.existsSync(resolved)) {
|
|
9202
9238
|
const stats = vfs.statSync(resolved);
|
|
9203
9239
|
if (stats.isFile()) {
|
|
9240
|
+
resolutionCache.set(cacheKey, resolved);
|
|
9204
9241
|
return resolved;
|
|
9205
9242
|
}
|
|
9206
9243
|
const indexPath = join(resolved, "index.js");
|
|
9207
9244
|
if (vfs.existsSync(indexPath)) {
|
|
9245
|
+
resolutionCache.set(cacheKey, indexPath);
|
|
9208
9246
|
return indexPath;
|
|
9209
9247
|
}
|
|
9210
9248
|
}
|
|
@@ -9215,9 +9253,11 @@ let __tla = (async () => {
|
|
|
9215
9253
|
for (const ext of extensions) {
|
|
9216
9254
|
const withExt = resolved + ext;
|
|
9217
9255
|
if (vfs.existsSync(withExt)) {
|
|
9256
|
+
resolutionCache.set(cacheKey, withExt);
|
|
9218
9257
|
return withExt;
|
|
9219
9258
|
}
|
|
9220
9259
|
}
|
|
9260
|
+
resolutionCache.set(cacheKey, null);
|
|
9221
9261
|
throw new Error(`Cannot find module '${id}' from '${fromDir}'`);
|
|
9222
9262
|
}
|
|
9223
9263
|
const tryResolveFile = (basePath) => {
|
|
@@ -9252,9 +9292,8 @@ let __tla = (async () => {
|
|
|
9252
9292
|
const pkgName = parts[0].startsWith("@") && parts.length > 1 ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
9253
9293
|
const pkgRoot = join(nodeModulesDir, pkgName);
|
|
9254
9294
|
const pkgPath = join(pkgRoot, "package.json");
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
const pkg = JSON.parse(pkgContent);
|
|
9295
|
+
const pkg = getParsedPackageJson(pkgPath);
|
|
9296
|
+
if (pkg) {
|
|
9258
9297
|
if (pkg.exports) {
|
|
9259
9298
|
try {
|
|
9260
9299
|
const resolved2 = resolve$3(pkg, moduleId, {
|
|
@@ -9282,11 +9321,18 @@ let __tla = (async () => {
|
|
|
9282
9321
|
while (searchDir !== "/") {
|
|
9283
9322
|
const nodeModulesDir = join(searchDir, "node_modules");
|
|
9284
9323
|
const resolved = tryResolveFromNodeModules(nodeModulesDir, id);
|
|
9285
|
-
if (resolved)
|
|
9324
|
+
if (resolved) {
|
|
9325
|
+
resolutionCache.set(cacheKey, resolved);
|
|
9326
|
+
return resolved;
|
|
9327
|
+
}
|
|
9286
9328
|
searchDir = dirname(searchDir);
|
|
9287
9329
|
}
|
|
9288
9330
|
const rootResolved = tryResolveFromNodeModules("/node_modules", id);
|
|
9289
|
-
if (rootResolved)
|
|
9331
|
+
if (rootResolved) {
|
|
9332
|
+
resolutionCache.set(cacheKey, rootResolved);
|
|
9333
|
+
return rootResolved;
|
|
9334
|
+
}
|
|
9335
|
+
resolutionCache.set(cacheKey, null);
|
|
9290
9336
|
throw new Error(`Cannot find module '${id}'`);
|
|
9291
9337
|
};
|
|
9292
9338
|
const loadModule = (resolvedPath) => {
|
|
@@ -9308,19 +9354,25 @@ let __tla = (async () => {
|
|
|
9308
9354
|
module.loaded = true;
|
|
9309
9355
|
return module;
|
|
9310
9356
|
}
|
|
9311
|
-
|
|
9357
|
+
const rawCode = vfs.readFileSync(resolvedPath, "utf8");
|
|
9312
9358
|
const dirname$1 = dirname(resolvedPath);
|
|
9313
|
-
const
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9323
|
-
|
|
9359
|
+
const codeCacheKey = `${resolvedPath}|${simpleHash(rawCode)}`;
|
|
9360
|
+
let code = processedCodeCache == null ? void 0 : processedCodeCache.get(codeCacheKey);
|
|
9361
|
+
if (!code) {
|
|
9362
|
+
code = rawCode;
|
|
9363
|
+
const isCjsFile = resolvedPath.endsWith(".cjs");
|
|
9364
|
+
const isAlreadyBundledCjs = code.startsWith('"use strict";\nvar __') || code.startsWith("'use strict';\nvar __");
|
|
9365
|
+
const hasEsmImport = /\bimport\s+[\w{*'"]/m.test(code);
|
|
9366
|
+
const hasEsmExport = /\bexport\s+(?:default|const|let|var|function|class|{|\*)/m.test(code);
|
|
9367
|
+
if (!isCjsFile && !isAlreadyBundledCjs) {
|
|
9368
|
+
if (resolvedPath.endsWith(".mjs") || resolvedPath.includes("/esm/") || hasEsmImport || hasEsmExport) {
|
|
9369
|
+
code = transformEsmToCjs(code, resolvedPath);
|
|
9370
|
+
}
|
|
9371
|
+
}
|
|
9372
|
+
code = transformDynamicImports(code);
|
|
9373
|
+
processedCodeCache == null ? void 0 : processedCodeCache.set(codeCacheKey, code);
|
|
9374
|
+
}
|
|
9375
|
+
const moduleRequire = createRequire(vfs, fsShim, process, dirname$1, moduleCache, options, processedCodeCache);
|
|
9324
9376
|
moduleRequire.cache = moduleCache;
|
|
9325
9377
|
const consoleWrapper = createConsoleWrapper(options.onConsole);
|
|
9326
9378
|
try {
|
|
@@ -9492,6 +9544,7 @@ ${code}
|
|
|
9492
9544
|
__publicField(this, "process");
|
|
9493
9545
|
__publicField(this, "moduleCache", {});
|
|
9494
9546
|
__publicField(this, "options");
|
|
9547
|
+
__publicField(this, "processedCodeCache", /* @__PURE__ */ new Map());
|
|
9495
9548
|
__publicField(this, "executeSync", this.execute);
|
|
9496
9549
|
__publicField(this, "runFileSync", this.runFile);
|
|
9497
9550
|
this.vfs = vfs2;
|
|
@@ -9576,7 +9629,7 @@ ${code}
|
|
|
9576
9629
|
execute(code, filename = "/index.js") {
|
|
9577
9630
|
const dirname$1 = dirname(filename);
|
|
9578
9631
|
this.vfs.writeFileSync(filename, code);
|
|
9579
|
-
const require = createRequire(this.vfs, this.fsShim, this.process, dirname$1, this.moduleCache, this.options);
|
|
9632
|
+
const require = createRequire(this.vfs, this.fsShim, this.process, dirname$1, this.moduleCache, this.options, this.processedCodeCache);
|
|
9580
9633
|
const module = {
|
|
9581
9634
|
id: filename,
|
|
9582
9635
|
filename,
|
|
@@ -9658,7 +9711,7 @@ ${code}
|
|
|
9658
9711
|
__publicField(this, "deleteListener", null);
|
|
9659
9712
|
this.vfs = vfs2;
|
|
9660
9713
|
this.options = options2;
|
|
9661
|
-
this.worker = new Worker(new URL("/assets/runtime-worker-
|
|
9714
|
+
this.worker = new Worker(new URL("/assets/runtime-worker-B8_LZkBX.js", import.meta.url), {
|
|
9662
9715
|
type: "module"
|
|
9663
9716
|
});
|
|
9664
9717
|
this.workerApi = wrap(this.worker);
|
|
@@ -11626,6 +11679,7 @@ console.log('[HMR] React Refresh initialized');
|
|
|
11626
11679
|
__publicField(this, "watcherCleanup", null);
|
|
11627
11680
|
__publicField(this, "options");
|
|
11628
11681
|
__publicField(this, "hmrTargetWindow", null);
|
|
11682
|
+
__publicField(this, "transformCache", /* @__PURE__ */ new Map());
|
|
11629
11683
|
this.options = {
|
|
11630
11684
|
jsx: true,
|
|
11631
11685
|
jsxFactory: "React.createElement",
|
|
@@ -11742,7 +11796,28 @@ console.log('[HMR] React Refresh initialized');
|
|
|
11742
11796
|
async transformAndServe(filePath, urlPath) {
|
|
11743
11797
|
try {
|
|
11744
11798
|
const content = this.vfs.readFileSync(filePath, "utf8");
|
|
11799
|
+
const hash = simpleHash(content);
|
|
11800
|
+
const cached = this.transformCache.get(filePath);
|
|
11801
|
+
if (cached && cached.hash === hash) {
|
|
11802
|
+
const buffer22 = BufferPolyfill.from(cached.code);
|
|
11803
|
+
return {
|
|
11804
|
+
statusCode: 200,
|
|
11805
|
+
statusMessage: "OK",
|
|
11806
|
+
headers: {
|
|
11807
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
11808
|
+
"Content-Length": String(buffer22.length),
|
|
11809
|
+
"Cache-Control": "no-cache",
|
|
11810
|
+
"X-Transformed": "true",
|
|
11811
|
+
"X-Cache": "hit"
|
|
11812
|
+
},
|
|
11813
|
+
body: buffer22
|
|
11814
|
+
};
|
|
11815
|
+
}
|
|
11745
11816
|
const transformed = await this.transformCode(content, urlPath);
|
|
11817
|
+
this.transformCache.set(filePath, {
|
|
11818
|
+
code: transformed,
|
|
11819
|
+
hash
|
|
11820
|
+
});
|
|
11746
11821
|
const buffer2 = BufferPolyfill.from(transformed);
|
|
11747
11822
|
return {
|
|
11748
11823
|
statusCode: 200,
|
|
@@ -11902,6 +11977,123 @@ export default css;
|
|
|
11902
11977
|
}
|
|
11903
11978
|
}
|
|
11904
11979
|
};
|
|
11980
|
+
const CONFIG_FILE_NAMES = [
|
|
11981
|
+
"/tailwind.config.ts",
|
|
11982
|
+
"/tailwind.config.js",
|
|
11983
|
+
"/tailwind.config.mjs"
|
|
11984
|
+
];
|
|
11985
|
+
async function loadTailwindConfig(vfs2, root = "/") {
|
|
11986
|
+
let configPath = null;
|
|
11987
|
+
let configContent = null;
|
|
11988
|
+
for (const fileName of CONFIG_FILE_NAMES) {
|
|
11989
|
+
const fullPath = root === "/" ? fileName : `${root}${fileName}`;
|
|
11990
|
+
try {
|
|
11991
|
+
const content = vfs2.readFileSync(fullPath);
|
|
11992
|
+
configContent = typeof content === "string" ? content : content instanceof Uint8Array ? new TextDecoder("utf-8").decode(content) : Buffer.from(content).toString("utf-8");
|
|
11993
|
+
configPath = fullPath;
|
|
11994
|
+
break;
|
|
11995
|
+
} catch {
|
|
11996
|
+
continue;
|
|
11997
|
+
}
|
|
11998
|
+
}
|
|
11999
|
+
if (!configPath || configContent === null) {
|
|
12000
|
+
return {
|
|
12001
|
+
configScript: "",
|
|
12002
|
+
success: true
|
|
12003
|
+
};
|
|
12004
|
+
}
|
|
12005
|
+
try {
|
|
12006
|
+
const jsConfig = stripTypescriptSyntax(configContent);
|
|
12007
|
+
const configObject = extractConfigObject(jsConfig);
|
|
12008
|
+
if (!configObject) {
|
|
12009
|
+
return {
|
|
12010
|
+
configScript: "",
|
|
12011
|
+
success: false,
|
|
12012
|
+
error: "Could not extract config object from tailwind.config"
|
|
12013
|
+
};
|
|
12014
|
+
}
|
|
12015
|
+
const configScript = generateConfigScript(configObject);
|
|
12016
|
+
return {
|
|
12017
|
+
configScript,
|
|
12018
|
+
success: true
|
|
12019
|
+
};
|
|
12020
|
+
} catch (error) {
|
|
12021
|
+
return {
|
|
12022
|
+
configScript: "",
|
|
12023
|
+
success: false,
|
|
12024
|
+
error: `Failed to parse tailwind.config: ${error instanceof Error ? error.message : String(error)}`
|
|
12025
|
+
};
|
|
12026
|
+
}
|
|
12027
|
+
}
|
|
12028
|
+
function stripTypescriptSyntax(content) {
|
|
12029
|
+
let result = content;
|
|
12030
|
+
result = result.replace(/import\s+type\s+\{[^}]*\}\s+from\s+['"][^'"]*['"]\s*;?\s*/g, "");
|
|
12031
|
+
result = result.replace(/import\s+\{[^}]*\}\s+from\s+['"][^'"]*['"]\s*;?\s*/g, "");
|
|
12032
|
+
result = result.replace(/\s+satisfies\s+\w+\s*$/gm, "");
|
|
12033
|
+
result = result.replace(/\s+satisfies\s+\w+\s*;?\s*$/gm, "");
|
|
12034
|
+
result = result.replace(/:\s*Config\s*=/g, " =");
|
|
12035
|
+
result = result.replace(/\s+as\s+const\s*/g, " ");
|
|
12036
|
+
return result;
|
|
12037
|
+
}
|
|
12038
|
+
function extractConfigObject(content) {
|
|
12039
|
+
const exportDefaultMatch = content.match(/export\s+default\s*/);
|
|
12040
|
+
if (!exportDefaultMatch || exportDefaultMatch.index === void 0) {
|
|
12041
|
+
return null;
|
|
12042
|
+
}
|
|
12043
|
+
const startIndex = exportDefaultMatch.index + exportDefaultMatch[0].length;
|
|
12044
|
+
const remaining = content.substring(startIndex);
|
|
12045
|
+
const trimmedRemaining = remaining.trimStart();
|
|
12046
|
+
if (!trimmedRemaining.startsWith("{")) {
|
|
12047
|
+
return null;
|
|
12048
|
+
}
|
|
12049
|
+
const objectStart = startIndex + (remaining.length - trimmedRemaining.length);
|
|
12050
|
+
const objectContent = content.substring(objectStart);
|
|
12051
|
+
let braceCount = 0;
|
|
12052
|
+
let inString = false;
|
|
12053
|
+
let stringChar = "";
|
|
12054
|
+
let escaped = false;
|
|
12055
|
+
let endIndex = -1;
|
|
12056
|
+
for (let i = 0; i < objectContent.length; i++) {
|
|
12057
|
+
const char = objectContent[i];
|
|
12058
|
+
if (escaped) {
|
|
12059
|
+
escaped = false;
|
|
12060
|
+
continue;
|
|
12061
|
+
}
|
|
12062
|
+
if (char === "\\") {
|
|
12063
|
+
escaped = true;
|
|
12064
|
+
continue;
|
|
12065
|
+
}
|
|
12066
|
+
if (inString) {
|
|
12067
|
+
if (char === stringChar) {
|
|
12068
|
+
inString = false;
|
|
12069
|
+
}
|
|
12070
|
+
continue;
|
|
12071
|
+
}
|
|
12072
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
12073
|
+
inString = true;
|
|
12074
|
+
stringChar = char;
|
|
12075
|
+
continue;
|
|
12076
|
+
}
|
|
12077
|
+
if (char === "{") {
|
|
12078
|
+
braceCount++;
|
|
12079
|
+
} else if (char === "}") {
|
|
12080
|
+
braceCount--;
|
|
12081
|
+
if (braceCount === 0) {
|
|
12082
|
+
endIndex = i + 1;
|
|
12083
|
+
break;
|
|
12084
|
+
}
|
|
12085
|
+
}
|
|
12086
|
+
}
|
|
12087
|
+
if (endIndex === -1) {
|
|
12088
|
+
return null;
|
|
12089
|
+
}
|
|
12090
|
+
return objectContent.substring(0, endIndex);
|
|
12091
|
+
}
|
|
12092
|
+
function generateConfigScript(configObject) {
|
|
12093
|
+
return `<script>
|
|
12094
|
+
tailwind.config = ${configObject};
|
|
12095
|
+
<\/script>`;
|
|
12096
|
+
}
|
|
11905
12097
|
const isBrowser = typeof window !== "undefined" && typeof window.navigator !== "undefined" && "serviceWorker" in window.navigator;
|
|
11906
12098
|
async function initEsbuild() {
|
|
11907
12099
|
if (!isBrowser) return;
|
|
@@ -12126,25 +12318,31 @@ const applyVirtualBase = (url) => {
|
|
|
12126
12318
|
|
|
12127
12319
|
export default function Link({ href, children, ...props }) {
|
|
12128
12320
|
const handleClick = (e) => {
|
|
12321
|
+
console.log('[Link] Click handler called, href:', href);
|
|
12322
|
+
|
|
12129
12323
|
if (props.onClick) {
|
|
12130
12324
|
props.onClick(e);
|
|
12131
12325
|
}
|
|
12132
12326
|
|
|
12133
12327
|
// Allow cmd/ctrl click to open in new tab
|
|
12134
12328
|
if (e.metaKey || e.ctrlKey) {
|
|
12329
|
+
console.log('[Link] Meta/Ctrl key pressed, allowing default behavior');
|
|
12135
12330
|
return;
|
|
12136
12331
|
}
|
|
12137
12332
|
|
|
12138
12333
|
if (typeof href !== 'string' || !href || href.startsWith('#') || href.startsWith('?')) {
|
|
12334
|
+
console.log('[Link] Skipping navigation for href:', href);
|
|
12139
12335
|
return;
|
|
12140
12336
|
}
|
|
12141
12337
|
|
|
12142
12338
|
if (/^(https?:)?\\/\\//.test(href)) {
|
|
12339
|
+
console.log('[Link] External URL, allowing default behavior:', href);
|
|
12143
12340
|
return;
|
|
12144
12341
|
}
|
|
12145
12342
|
|
|
12146
12343
|
e.preventDefault();
|
|
12147
12344
|
const resolvedHref = applyVirtualBase(href);
|
|
12345
|
+
console.log('[Link] Navigating to:', resolvedHref);
|
|
12148
12346
|
window.history.pushState({}, '', resolvedHref);
|
|
12149
12347
|
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
12150
12348
|
};
|
|
@@ -12482,6 +12680,305 @@ export default function Head({ children }) {
|
|
|
12482
12680
|
|
|
12483
12681
|
return null;
|
|
12484
12682
|
}
|
|
12683
|
+
`;
|
|
12684
|
+
const NEXT_IMAGE_SHIM = `
|
|
12685
|
+
import React from 'react';
|
|
12686
|
+
|
|
12687
|
+
function Image({
|
|
12688
|
+
src,
|
|
12689
|
+
alt = '',
|
|
12690
|
+
width,
|
|
12691
|
+
height,
|
|
12692
|
+
fill,
|
|
12693
|
+
loader,
|
|
12694
|
+
quality = 75,
|
|
12695
|
+
priority,
|
|
12696
|
+
loading,
|
|
12697
|
+
placeholder,
|
|
12698
|
+
blurDataURL,
|
|
12699
|
+
unoptimized,
|
|
12700
|
+
onLoad,
|
|
12701
|
+
onError,
|
|
12702
|
+
style,
|
|
12703
|
+
className,
|
|
12704
|
+
sizes,
|
|
12705
|
+
...rest
|
|
12706
|
+
}) {
|
|
12707
|
+
// Handle src - could be string or StaticImageData object
|
|
12708
|
+
const imageSrc = typeof src === 'object' ? src.src : src;
|
|
12709
|
+
|
|
12710
|
+
// Build style object
|
|
12711
|
+
const imgStyle = { ...style };
|
|
12712
|
+
if (fill) {
|
|
12713
|
+
imgStyle.position = 'absolute';
|
|
12714
|
+
imgStyle.width = '100%';
|
|
12715
|
+
imgStyle.height = '100%';
|
|
12716
|
+
imgStyle.objectFit = imgStyle.objectFit || 'cover';
|
|
12717
|
+
imgStyle.inset = '0';
|
|
12718
|
+
}
|
|
12719
|
+
|
|
12720
|
+
return React.createElement('img', {
|
|
12721
|
+
src: imageSrc,
|
|
12722
|
+
alt,
|
|
12723
|
+
width: fill ? undefined : width,
|
|
12724
|
+
height: fill ? undefined : height,
|
|
12725
|
+
loading: priority ? 'eager' : (loading || 'lazy'),
|
|
12726
|
+
decoding: 'async',
|
|
12727
|
+
style: imgStyle,
|
|
12728
|
+
className,
|
|
12729
|
+
onLoad,
|
|
12730
|
+
onError,
|
|
12731
|
+
...rest
|
|
12732
|
+
});
|
|
12733
|
+
}
|
|
12734
|
+
|
|
12735
|
+
export default Image;
|
|
12736
|
+
export { Image };
|
|
12737
|
+
`;
|
|
12738
|
+
const NEXT_DYNAMIC_SHIM = `
|
|
12739
|
+
import React from 'react';
|
|
12740
|
+
|
|
12741
|
+
function dynamic(importFn, options = {}) {
|
|
12742
|
+
const {
|
|
12743
|
+
loading: LoadingComponent,
|
|
12744
|
+
ssr = true,
|
|
12745
|
+
} = options;
|
|
12746
|
+
|
|
12747
|
+
// Create a lazy component
|
|
12748
|
+
const LazyComponent = React.lazy(importFn);
|
|
12749
|
+
|
|
12750
|
+
// Wrapper component that handles loading state
|
|
12751
|
+
function DynamicComponent(props) {
|
|
12752
|
+
const fallback = LoadingComponent
|
|
12753
|
+
? React.createElement(LoadingComponent, { isLoading: true })
|
|
12754
|
+
: null;
|
|
12755
|
+
|
|
12756
|
+
return React.createElement(
|
|
12757
|
+
React.Suspense,
|
|
12758
|
+
{ fallback },
|
|
12759
|
+
React.createElement(LazyComponent, props)
|
|
12760
|
+
);
|
|
12761
|
+
}
|
|
12762
|
+
|
|
12763
|
+
return DynamicComponent;
|
|
12764
|
+
}
|
|
12765
|
+
|
|
12766
|
+
export default dynamic;
|
|
12767
|
+
export { dynamic };
|
|
12768
|
+
`;
|
|
12769
|
+
const NEXT_SCRIPT_SHIM = `
|
|
12770
|
+
import React from 'react';
|
|
12771
|
+
|
|
12772
|
+
function Script({
|
|
12773
|
+
src,
|
|
12774
|
+
strategy = 'afterInteractive',
|
|
12775
|
+
onLoad,
|
|
12776
|
+
onReady,
|
|
12777
|
+
onError,
|
|
12778
|
+
children,
|
|
12779
|
+
dangerouslySetInnerHTML,
|
|
12780
|
+
...rest
|
|
12781
|
+
}) {
|
|
12782
|
+
React.useEffect(function() {
|
|
12783
|
+
if (!src && !children && !dangerouslySetInnerHTML) return;
|
|
12784
|
+
|
|
12785
|
+
var script = document.createElement('script');
|
|
12786
|
+
|
|
12787
|
+
if (src) {
|
|
12788
|
+
script.src = src;
|
|
12789
|
+
script.async = strategy !== 'beforeInteractive';
|
|
12790
|
+
}
|
|
12791
|
+
|
|
12792
|
+
Object.keys(rest).forEach(function(key) {
|
|
12793
|
+
script.setAttribute(key, rest[key]);
|
|
12794
|
+
});
|
|
12795
|
+
|
|
12796
|
+
if (children) {
|
|
12797
|
+
script.textContent = children;
|
|
12798
|
+
} else if (dangerouslySetInnerHTML && dangerouslySetInnerHTML.__html) {
|
|
12799
|
+
script.textContent = dangerouslySetInnerHTML.__html;
|
|
12800
|
+
}
|
|
12801
|
+
|
|
12802
|
+
script.onload = function() {
|
|
12803
|
+
if (onLoad) onLoad();
|
|
12804
|
+
if (onReady) onReady();
|
|
12805
|
+
};
|
|
12806
|
+
script.onerror = onError;
|
|
12807
|
+
|
|
12808
|
+
document.head.appendChild(script);
|
|
12809
|
+
|
|
12810
|
+
return function() {
|
|
12811
|
+
if (script.parentNode) {
|
|
12812
|
+
script.parentNode.removeChild(script);
|
|
12813
|
+
}
|
|
12814
|
+
};
|
|
12815
|
+
}, [src]);
|
|
12816
|
+
|
|
12817
|
+
return null;
|
|
12818
|
+
}
|
|
12819
|
+
|
|
12820
|
+
export default Script;
|
|
12821
|
+
export { Script };
|
|
12822
|
+
`;
|
|
12823
|
+
const NEXT_FONT_GOOGLE_SHIM = `
|
|
12824
|
+
// Track loaded fonts to avoid duplicate style injections
|
|
12825
|
+
const loadedFonts = new Set();
|
|
12826
|
+
|
|
12827
|
+
/**
|
|
12828
|
+
* Convert font function name to Google Fonts family name
|
|
12829
|
+
* Examples:
|
|
12830
|
+
* DM_Sans -> DM Sans
|
|
12831
|
+
* Open_Sans -> Open Sans
|
|
12832
|
+
* Fraunces -> Fraunces
|
|
12833
|
+
*/
|
|
12834
|
+
function toFontFamily(fontName) {
|
|
12835
|
+
return fontName.replace(/_/g, ' ');
|
|
12836
|
+
}
|
|
12837
|
+
|
|
12838
|
+
/**
|
|
12839
|
+
* Inject font CSS into document
|
|
12840
|
+
* - Adds preconnect links for faster font loading
|
|
12841
|
+
* - Loads the font from Google Fonts CDN
|
|
12842
|
+
* - Creates a CSS class that sets the CSS variable
|
|
12843
|
+
*/
|
|
12844
|
+
function injectFontCSS(fontFamily, variableName, weight, style) {
|
|
12845
|
+
const fontKey = fontFamily + '-' + (variableName || 'default');
|
|
12846
|
+
if (loadedFonts.has(fontKey)) {
|
|
12847
|
+
return;
|
|
12848
|
+
}
|
|
12849
|
+
loadedFonts.add(fontKey);
|
|
12850
|
+
|
|
12851
|
+
if (typeof document === 'undefined') {
|
|
12852
|
+
return;
|
|
12853
|
+
}
|
|
12854
|
+
|
|
12855
|
+
// Add preconnect links for faster loading (only once)
|
|
12856
|
+
if (!document.querySelector('link[href="https://fonts.googleapis.com"]')) {
|
|
12857
|
+
const preconnect1 = document.createElement('link');
|
|
12858
|
+
preconnect1.rel = 'preconnect';
|
|
12859
|
+
preconnect1.href = 'https://fonts.googleapis.com';
|
|
12860
|
+
document.head.appendChild(preconnect1);
|
|
12861
|
+
|
|
12862
|
+
const preconnect2 = document.createElement('link');
|
|
12863
|
+
preconnect2.rel = 'preconnect';
|
|
12864
|
+
preconnect2.href = 'https://fonts.gstatic.com';
|
|
12865
|
+
preconnect2.crossOrigin = 'anonymous';
|
|
12866
|
+
document.head.appendChild(preconnect2);
|
|
12867
|
+
}
|
|
12868
|
+
|
|
12869
|
+
// Build Google Fonts URL
|
|
12870
|
+
const escapedFamily = fontFamily.replace(/ /g, '+');
|
|
12871
|
+
|
|
12872
|
+
// Build axis list based on options
|
|
12873
|
+
let axisList = '';
|
|
12874
|
+
const axes = [];
|
|
12875
|
+
|
|
12876
|
+
// Handle italic style
|
|
12877
|
+
if (style === 'italic') {
|
|
12878
|
+
axes.push('ital');
|
|
12879
|
+
}
|
|
12880
|
+
|
|
12881
|
+
// Handle weight - use specific weight or variable range
|
|
12882
|
+
if (weight && weight !== '400' && !Array.isArray(weight)) {
|
|
12883
|
+
// Specific weight requested
|
|
12884
|
+
axes.push('wght');
|
|
12885
|
+
if (style === 'italic') {
|
|
12886
|
+
axisList = ':ital,wght@1,' + weight;
|
|
12887
|
+
} else {
|
|
12888
|
+
axisList = ':wght@' + weight;
|
|
12889
|
+
}
|
|
12890
|
+
} else if (Array.isArray(weight)) {
|
|
12891
|
+
// Multiple weights
|
|
12892
|
+
axes.push('wght');
|
|
12893
|
+
axisList = ':wght@' + weight.join(';');
|
|
12894
|
+
} else {
|
|
12895
|
+
// Default: request common weights for flexibility
|
|
12896
|
+
axisList = ':wght@400;500;600;700';
|
|
12897
|
+
}
|
|
12898
|
+
|
|
12899
|
+
const fontUrl = 'https://fonts.googleapis.com/css2?family=' +
|
|
12900
|
+
escapedFamily + axisList + '&display=swap';
|
|
12901
|
+
|
|
12902
|
+
// Add link element for Google Fonts (if not already present)
|
|
12903
|
+
if (!document.querySelector('link[href*="family=' + escapedFamily + '"]')) {
|
|
12904
|
+
const link = document.createElement('link');
|
|
12905
|
+
link.rel = 'stylesheet';
|
|
12906
|
+
link.href = fontUrl;
|
|
12907
|
+
document.head.appendChild(link);
|
|
12908
|
+
}
|
|
12909
|
+
|
|
12910
|
+
// Create style element for CSS variable at :root level (globally available)
|
|
12911
|
+
// This makes the variable work without needing to apply the class to body
|
|
12912
|
+
if (variableName) {
|
|
12913
|
+
const styleEl = document.createElement('style');
|
|
12914
|
+
styleEl.setAttribute('data-font-var', variableName);
|
|
12915
|
+
styleEl.textContent = ':root { ' + variableName + ': "' + fontFamily + '", ' + (fontFamily.includes('Serif') ? 'serif' : 'sans-serif') + '; }';
|
|
12916
|
+
document.head.appendChild(styleEl);
|
|
12917
|
+
}
|
|
12918
|
+
}
|
|
12919
|
+
|
|
12920
|
+
/**
|
|
12921
|
+
* Create a font loader function for a specific font
|
|
12922
|
+
*/
|
|
12923
|
+
function createFontLoader(fontName) {
|
|
12924
|
+
const fontFamily = toFontFamily(fontName);
|
|
12925
|
+
|
|
12926
|
+
return function(options = {}) {
|
|
12927
|
+
const {
|
|
12928
|
+
weight,
|
|
12929
|
+
style = 'normal',
|
|
12930
|
+
subsets = ['latin'],
|
|
12931
|
+
variable,
|
|
12932
|
+
display = 'swap',
|
|
12933
|
+
preload = true,
|
|
12934
|
+
fallback = ['sans-serif'],
|
|
12935
|
+
adjustFontFallback = true
|
|
12936
|
+
} = options;
|
|
12937
|
+
|
|
12938
|
+
// Inject the font CSS
|
|
12939
|
+
injectFontCSS(fontFamily, variable, weight, style);
|
|
12940
|
+
|
|
12941
|
+
// Generate class name from variable (--font-inter -> __font-inter)
|
|
12942
|
+
const className = variable
|
|
12943
|
+
? variable.replace('--', '__')
|
|
12944
|
+
: '__font-' + fontName.toLowerCase().replace(/_/g, '-');
|
|
12945
|
+
|
|
12946
|
+
return {
|
|
12947
|
+
className,
|
|
12948
|
+
variable: className,
|
|
12949
|
+
style: {
|
|
12950
|
+
fontFamily: '"' + fontFamily + '", ' + fallback.join(', ')
|
|
12951
|
+
}
|
|
12952
|
+
};
|
|
12953
|
+
};
|
|
12954
|
+
}
|
|
12955
|
+
|
|
12956
|
+
/**
|
|
12957
|
+
* Use a Proxy to dynamically create font loaders for ANY font name
|
|
12958
|
+
* This allows: import { AnyGoogleFont } from "next/font/google"
|
|
12959
|
+
*/
|
|
12960
|
+
const fontProxy = new Proxy({}, {
|
|
12961
|
+
get(target, prop) {
|
|
12962
|
+
// Handle special properties
|
|
12963
|
+
if (prop === '__esModule') return true;
|
|
12964
|
+
if (prop === 'default') return fontProxy;
|
|
12965
|
+
if (typeof prop !== 'string') return undefined;
|
|
12966
|
+
|
|
12967
|
+
// Create a font loader for this font name
|
|
12968
|
+
return createFontLoader(prop);
|
|
12969
|
+
}
|
|
12970
|
+
});
|
|
12971
|
+
|
|
12972
|
+
// Export the proxy as both default and named exports
|
|
12973
|
+
export default fontProxy;
|
|
12974
|
+
|
|
12975
|
+
// Re-export through proxy for named imports
|
|
12976
|
+
export const {
|
|
12977
|
+
Fraunces, Inter, DM_Sans, DM_Serif_Text, Roboto, Open_Sans, Lato,
|
|
12978
|
+
Montserrat, Poppins, Playfair_Display, Merriweather, Raleway, Nunito,
|
|
12979
|
+
Ubuntu, Oswald, Quicksand, Work_Sans, Fira_Sans, Barlow, Mulish, Rubik,
|
|
12980
|
+
Noto_Sans, Manrope, Space_Grotesk, Geist, Geist_Mono
|
|
12981
|
+
} = fontProxy;
|
|
12485
12982
|
`;
|
|
12486
12983
|
NextDevServer = class extends DevServer {
|
|
12487
12984
|
constructor(vfs2, options2) {
|
|
@@ -12493,6 +12990,11 @@ export default function Head({ children }) {
|
|
|
12493
12990
|
__publicField(this, "watcherCleanup", null);
|
|
12494
12991
|
__publicField(this, "hmrTargetWindow", null);
|
|
12495
12992
|
__publicField(this, "options");
|
|
12993
|
+
__publicField(this, "transformCache", /* @__PURE__ */ new Map());
|
|
12994
|
+
__publicField(this, "pathAliases", /* @__PURE__ */ new Map());
|
|
12995
|
+
__publicField(this, "tailwindConfigScript", "");
|
|
12996
|
+
__publicField(this, "tailwindConfigLoaded", false);
|
|
12997
|
+
__publicField(this, "assetPrefix", "");
|
|
12496
12998
|
this.options = options2;
|
|
12497
12999
|
this.pagesDir = options2.pagesDir || "/pages";
|
|
12498
13000
|
this.appDir = options2.appDir || "/app";
|
|
@@ -12502,6 +13004,82 @@ export default function Head({ children }) {
|
|
|
12502
13004
|
} else {
|
|
12503
13005
|
this.useAppRouter = this.hasAppRouter();
|
|
12504
13006
|
}
|
|
13007
|
+
this.loadPathAliases();
|
|
13008
|
+
this.loadAssetPrefix(options2.assetPrefix);
|
|
13009
|
+
}
|
|
13010
|
+
loadPathAliases() {
|
|
13011
|
+
var _a2;
|
|
13012
|
+
try {
|
|
13013
|
+
const tsconfigPath = "/tsconfig.json";
|
|
13014
|
+
if (!this.vfs.existsSync(tsconfigPath)) {
|
|
13015
|
+
return;
|
|
13016
|
+
}
|
|
13017
|
+
const content = this.vfs.readFileSync(tsconfigPath, "utf-8");
|
|
13018
|
+
const tsconfig = JSON.parse(content);
|
|
13019
|
+
const paths = (_a2 = tsconfig == null ? void 0 : tsconfig.compilerOptions) == null ? void 0 : _a2.paths;
|
|
13020
|
+
if (!paths) {
|
|
13021
|
+
return;
|
|
13022
|
+
}
|
|
13023
|
+
for (const [alias, targets] of Object.entries(paths)) {
|
|
13024
|
+
if (Array.isArray(targets) && targets.length > 0) {
|
|
13025
|
+
const aliasPrefix = alias.replace(/\*$/, "");
|
|
13026
|
+
const targetPrefix = targets[0].replace(/\*$/, "").replace(/^\./, "");
|
|
13027
|
+
this.pathAliases.set(aliasPrefix, targetPrefix);
|
|
13028
|
+
}
|
|
13029
|
+
}
|
|
13030
|
+
} catch (e) {
|
|
13031
|
+
}
|
|
13032
|
+
}
|
|
13033
|
+
loadAssetPrefix(optionValue) {
|
|
13034
|
+
if (optionValue !== void 0) {
|
|
13035
|
+
this.assetPrefix = optionValue.startsWith("/") ? optionValue : `/${optionValue}`;
|
|
13036
|
+
if (this.assetPrefix.endsWith("/")) {
|
|
13037
|
+
this.assetPrefix = this.assetPrefix.slice(0, -1);
|
|
13038
|
+
}
|
|
13039
|
+
return;
|
|
13040
|
+
}
|
|
13041
|
+
try {
|
|
13042
|
+
const configFiles = [
|
|
13043
|
+
"/next.config.ts",
|
|
13044
|
+
"/next.config.js",
|
|
13045
|
+
"/next.config.mjs"
|
|
13046
|
+
];
|
|
13047
|
+
for (const configPath of configFiles) {
|
|
13048
|
+
if (!this.vfs.existsSync(configPath)) {
|
|
13049
|
+
continue;
|
|
13050
|
+
}
|
|
13051
|
+
const content = this.vfs.readFileSync(configPath, "utf-8");
|
|
13052
|
+
const match = content.match(/assetPrefix\s*:\s*["']([^"']+)["']/);
|
|
13053
|
+
if (match) {
|
|
13054
|
+
let prefix = match[1];
|
|
13055
|
+
if (!prefix.startsWith("/")) {
|
|
13056
|
+
prefix = `/${prefix}`;
|
|
13057
|
+
}
|
|
13058
|
+
if (prefix.endsWith("/")) {
|
|
13059
|
+
prefix = prefix.slice(0, -1);
|
|
13060
|
+
}
|
|
13061
|
+
this.assetPrefix = prefix;
|
|
13062
|
+
return;
|
|
13063
|
+
}
|
|
13064
|
+
}
|
|
13065
|
+
} catch (e) {
|
|
13066
|
+
}
|
|
13067
|
+
}
|
|
13068
|
+
resolvePathAliases(code2, currentFile) {
|
|
13069
|
+
if (this.pathAliases.size === 0) {
|
|
13070
|
+
return code2;
|
|
13071
|
+
}
|
|
13072
|
+
const virtualBase = `/__virtual__/${this.port}`;
|
|
13073
|
+
let result = code2;
|
|
13074
|
+
for (const [alias, target] of this.pathAliases) {
|
|
13075
|
+
const aliasEscaped = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13076
|
+
const pattern = new RegExp(`(from\\s*['"]|import\\s*\\(\\s*['"])${aliasEscaped}([^'"]+)(['"])`, "g");
|
|
13077
|
+
result = result.replace(pattern, (match, prefix, path2, quote) => {
|
|
13078
|
+
const resolvedPath2 = `${virtualBase}${target}${path2}`;
|
|
13079
|
+
return `${prefix}${resolvedPath2}${quote}`;
|
|
13080
|
+
});
|
|
13081
|
+
}
|
|
13082
|
+
return result;
|
|
12505
13083
|
}
|
|
12506
13084
|
setEnv(key, value) {
|
|
12507
13085
|
this.options.env = this.options.env || {};
|
|
@@ -12517,20 +13095,38 @@ export default function Head({ children }) {
|
|
|
12517
13095
|
}
|
|
12518
13096
|
generateEnvScript() {
|
|
12519
13097
|
const env = this.options.env || {};
|
|
12520
|
-
const publicEnvVars =
|
|
12521
|
-
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
|
|
12525
|
-
return "";
|
|
13098
|
+
const publicEnvVars = {};
|
|
13099
|
+
for (const [key, value] of Object.entries(env)) {
|
|
13100
|
+
if (key.startsWith("NEXT_PUBLIC_")) {
|
|
13101
|
+
publicEnvVars[key] = value;
|
|
13102
|
+
}
|
|
12526
13103
|
}
|
|
12527
13104
|
return `<script>
|
|
12528
|
-
//
|
|
13105
|
+
// Environment variables (injected by NextDevServer)
|
|
12529
13106
|
window.process = window.process || {};
|
|
12530
13107
|
window.process.env = window.process.env || {};
|
|
12531
13108
|
Object.assign(window.process.env, ${JSON.stringify(publicEnvVars)});
|
|
12532
13109
|
<\/script>`;
|
|
12533
13110
|
}
|
|
13111
|
+
async loadTailwindConfigIfNeeded() {
|
|
13112
|
+
if (this.tailwindConfigLoaded) {
|
|
13113
|
+
return this.tailwindConfigScript;
|
|
13114
|
+
}
|
|
13115
|
+
try {
|
|
13116
|
+
const result = await loadTailwindConfig(this.vfs, this.root);
|
|
13117
|
+
if (result.success) {
|
|
13118
|
+
this.tailwindConfigScript = result.configScript;
|
|
13119
|
+
} else if (result.error) {
|
|
13120
|
+
console.warn("[NextDevServer] Tailwind config warning:", result.error);
|
|
13121
|
+
this.tailwindConfigScript = "";
|
|
13122
|
+
}
|
|
13123
|
+
} catch (error) {
|
|
13124
|
+
console.warn("[NextDevServer] Failed to load tailwind.config:", error);
|
|
13125
|
+
this.tailwindConfigScript = "";
|
|
13126
|
+
}
|
|
13127
|
+
this.tailwindConfigLoaded = true;
|
|
13128
|
+
return this.tailwindConfigScript;
|
|
13129
|
+
}
|
|
12534
13130
|
hasAppRouter() {
|
|
12535
13131
|
try {
|
|
12536
13132
|
if (!this.exists(this.appDir)) return false;
|
|
@@ -12550,10 +13146,26 @@ export default function Head({ children }) {
|
|
|
12550
13146
|
}
|
|
12551
13147
|
async handleRequest(method, url2, headers, body) {
|
|
12552
13148
|
const urlObj = new URL(url2, "http://localhost");
|
|
12553
|
-
|
|
13149
|
+
let pathname = urlObj.pathname;
|
|
13150
|
+
const virtualPrefixMatch = pathname.match(/^\/__virtual__\/\d+/);
|
|
13151
|
+
if (virtualPrefixMatch) {
|
|
13152
|
+
pathname = pathname.slice(virtualPrefixMatch[0].length) || "/";
|
|
13153
|
+
}
|
|
13154
|
+
if (this.assetPrefix && pathname.startsWith(this.assetPrefix)) {
|
|
13155
|
+
const rest = pathname.slice(this.assetPrefix.length);
|
|
13156
|
+
if (rest === "" || rest.startsWith("/")) {
|
|
13157
|
+
pathname = rest || "/";
|
|
13158
|
+
if (pathname.startsWith("//")) {
|
|
13159
|
+
pathname = pathname.slice(1);
|
|
13160
|
+
}
|
|
13161
|
+
}
|
|
13162
|
+
}
|
|
12554
13163
|
if (pathname.startsWith("/_next/shims/")) {
|
|
12555
13164
|
return this.serveNextShim(pathname);
|
|
12556
13165
|
}
|
|
13166
|
+
if (pathname === "/_next/route-info") {
|
|
13167
|
+
return this.serveRouteInfo(urlObj.searchParams.get("pathname") || "/");
|
|
13168
|
+
}
|
|
12557
13169
|
if (pathname.startsWith("/_next/pages/")) {
|
|
12558
13170
|
return this.servePageComponent(pathname);
|
|
12559
13171
|
}
|
|
@@ -12573,6 +13185,13 @@ export default function Head({ children }) {
|
|
|
12573
13185
|
if (this.needsTransform(pathname) && this.exists(pathname)) {
|
|
12574
13186
|
return this.transformAndServe(pathname, pathname);
|
|
12575
13187
|
}
|
|
13188
|
+
const resolvedFile = this.resolveFileWithExtension(pathname);
|
|
13189
|
+
if (resolvedFile) {
|
|
13190
|
+
if (this.needsTransform(resolvedFile)) {
|
|
13191
|
+
return this.transformAndServe(resolvedFile, pathname);
|
|
13192
|
+
}
|
|
13193
|
+
return this.serveFile(resolvedFile);
|
|
13194
|
+
}
|
|
12576
13195
|
if (this.exists(pathname) && !this.isDirectory(pathname)) {
|
|
12577
13196
|
return this.serveFile(pathname);
|
|
12578
13197
|
}
|
|
@@ -12594,6 +13213,18 @@ export default function Head({ children }) {
|
|
|
12594
13213
|
case "navigation":
|
|
12595
13214
|
code2 = NEXT_NAVIGATION_SHIM;
|
|
12596
13215
|
break;
|
|
13216
|
+
case "image":
|
|
13217
|
+
code2 = NEXT_IMAGE_SHIM;
|
|
13218
|
+
break;
|
|
13219
|
+
case "dynamic":
|
|
13220
|
+
code2 = NEXT_DYNAMIC_SHIM;
|
|
13221
|
+
break;
|
|
13222
|
+
case "script":
|
|
13223
|
+
code2 = NEXT_SCRIPT_SHIM;
|
|
13224
|
+
break;
|
|
13225
|
+
case "font/google":
|
|
13226
|
+
code2 = NEXT_FONT_GOOGLE_SHIM;
|
|
13227
|
+
break;
|
|
12597
13228
|
default:
|
|
12598
13229
|
return this.notFound(pathname);
|
|
12599
13230
|
}
|
|
@@ -12609,6 +13240,28 @@ export default function Head({ children }) {
|
|
|
12609
13240
|
body: buffer2
|
|
12610
13241
|
};
|
|
12611
13242
|
}
|
|
13243
|
+
serveRouteInfo(pathname) {
|
|
13244
|
+
const route = this.resolveAppRoute(pathname);
|
|
13245
|
+
const info = route ? {
|
|
13246
|
+
params: route.params,
|
|
13247
|
+
found: true
|
|
13248
|
+
} : {
|
|
13249
|
+
params: {},
|
|
13250
|
+
found: false
|
|
13251
|
+
};
|
|
13252
|
+
const json = JSON.stringify(info);
|
|
13253
|
+
const buffer2 = BufferPolyfill.from(json);
|
|
13254
|
+
return {
|
|
13255
|
+
statusCode: 200,
|
|
13256
|
+
statusMessage: "OK",
|
|
13257
|
+
headers: {
|
|
13258
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
13259
|
+
"Content-Length": String(buffer2.length),
|
|
13260
|
+
"Cache-Control": "no-cache"
|
|
13261
|
+
},
|
|
13262
|
+
body: buffer2
|
|
13263
|
+
};
|
|
13264
|
+
}
|
|
12612
13265
|
serveStaticAsset(pathname) {
|
|
12613
13266
|
const filePath = pathname.replace("/_next/static/", "/");
|
|
12614
13267
|
if (this.exists(filePath)) {
|
|
@@ -13117,7 +13770,8 @@ export default function Head({ children }) {
|
|
|
13117
13770
|
if (this.exists(pagePath)) {
|
|
13118
13771
|
return {
|
|
13119
13772
|
page: pagePath,
|
|
13120
|
-
layouts
|
|
13773
|
+
layouts,
|
|
13774
|
+
params: {}
|
|
13121
13775
|
};
|
|
13122
13776
|
}
|
|
13123
13777
|
}
|
|
@@ -13130,7 +13784,7 @@ export default function Head({ children }) {
|
|
|
13130
13784
|
".js",
|
|
13131
13785
|
".ts"
|
|
13132
13786
|
];
|
|
13133
|
-
const tryPath = (dirPath, remainingSegments, layouts2) => {
|
|
13787
|
+
const tryPath = (dirPath, remainingSegments, layouts2, params) => {
|
|
13134
13788
|
for (const ext of extensions) {
|
|
13135
13789
|
const layoutPath = `${dirPath}/layout${ext}`;
|
|
13136
13790
|
if (this.exists(layoutPath) && !layouts2.includes(layoutPath)) {
|
|
@@ -13146,7 +13800,8 @@ export default function Head({ children }) {
|
|
|
13146
13800
|
if (this.exists(pagePath)) {
|
|
13147
13801
|
return {
|
|
13148
13802
|
page: pagePath,
|
|
13149
|
-
layouts: layouts2
|
|
13803
|
+
layouts: layouts2,
|
|
13804
|
+
params
|
|
13150
13805
|
};
|
|
13151
13806
|
}
|
|
13152
13807
|
}
|
|
@@ -13155,16 +13810,35 @@ export default function Head({ children }) {
|
|
|
13155
13810
|
const [current, ...rest] = remainingSegments;
|
|
13156
13811
|
const exactPath = `${dirPath}/${current}`;
|
|
13157
13812
|
if (this.isDirectory(exactPath)) {
|
|
13158
|
-
const result = tryPath(exactPath, rest, layouts2);
|
|
13813
|
+
const result = tryPath(exactPath, rest, layouts2, params);
|
|
13159
13814
|
if (result) return result;
|
|
13160
13815
|
}
|
|
13161
13816
|
try {
|
|
13162
13817
|
const entries = this.vfs.readdirSync(dirPath);
|
|
13163
13818
|
for (const entry of entries) {
|
|
13164
|
-
if (entry.startsWith("[") && entry.endsWith("]")
|
|
13819
|
+
if (entry.startsWith("[...") && entry.endsWith("]")) {
|
|
13820
|
+
const dynamicPath = `${dirPath}/${entry}`;
|
|
13821
|
+
if (this.isDirectory(dynamicPath)) {
|
|
13822
|
+
const paramName = entry.slice(4, -1);
|
|
13823
|
+
const newParams = {
|
|
13824
|
+
...params,
|
|
13825
|
+
[paramName]: [
|
|
13826
|
+
current,
|
|
13827
|
+
...rest
|
|
13828
|
+
]
|
|
13829
|
+
};
|
|
13830
|
+
const result = tryPath(dynamicPath, [], layouts2, newParams);
|
|
13831
|
+
if (result) return result;
|
|
13832
|
+
}
|
|
13833
|
+
} else if (entry.startsWith("[") && entry.endsWith("]") && !entry.includes(".")) {
|
|
13165
13834
|
const dynamicPath = `${dirPath}/${entry}`;
|
|
13166
13835
|
if (this.isDirectory(dynamicPath)) {
|
|
13167
|
-
const
|
|
13836
|
+
const paramName = entry.slice(1, -1);
|
|
13837
|
+
const newParams = {
|
|
13838
|
+
...params,
|
|
13839
|
+
[paramName]: current
|
|
13840
|
+
};
|
|
13841
|
+
const result = tryPath(dynamicPath, rest, layouts2, newParams);
|
|
13168
13842
|
if (result) return result;
|
|
13169
13843
|
}
|
|
13170
13844
|
}
|
|
@@ -13181,7 +13855,7 @@ export default function Head({ children }) {
|
|
|
13181
13855
|
break;
|
|
13182
13856
|
}
|
|
13183
13857
|
}
|
|
13184
|
-
return tryPath(this.appDir, segments, layouts);
|
|
13858
|
+
return tryPath(this.appDir, segments, layouts, {});
|
|
13185
13859
|
}
|
|
13186
13860
|
async generateAppRouterHtml(route, pathname) {
|
|
13187
13861
|
const virtualPrefix = `/__virtual__/${this.port}`;
|
|
@@ -13201,6 +13875,7 @@ export default function Head({ children }) {
|
|
|
13201
13875
|
for (let i = route.layouts.length - 1; i >= 0; i--) {
|
|
13202
13876
|
}
|
|
13203
13877
|
const envScript = this.generateEnvScript();
|
|
13878
|
+
const tailwindConfigScript = await this.loadTailwindConfigIfNeeded();
|
|
13204
13879
|
return `<!DOCTYPE html>
|
|
13205
13880
|
<html lang="en">
|
|
13206
13881
|
<head>
|
|
@@ -13210,6 +13885,7 @@ export default function Head({ children }) {
|
|
|
13210
13885
|
<title>Next.js App</title>
|
|
13211
13886
|
${envScript}
|
|
13212
13887
|
${TAILWIND_CDN_SCRIPT}
|
|
13888
|
+
${tailwindConfigScript}
|
|
13213
13889
|
${CORS_PROXY_SCRIPT}
|
|
13214
13890
|
${globalCssLinks.join("\n ")}
|
|
13215
13891
|
${REACT_REFRESH_PREAMBLE}
|
|
@@ -13231,7 +13907,11 @@ export default function Head({ children }) {
|
|
|
13231
13907
|
"next/link": "${virtualPrefix}/_next/shims/link.js",
|
|
13232
13908
|
"next/router": "${virtualPrefix}/_next/shims/router.js",
|
|
13233
13909
|
"next/head": "${virtualPrefix}/_next/shims/head.js",
|
|
13234
|
-
"next/navigation": "${virtualPrefix}/_next/shims/navigation.js"
|
|
13910
|
+
"next/navigation": "${virtualPrefix}/_next/shims/navigation.js",
|
|
13911
|
+
"next/image": "${virtualPrefix}/_next/shims/image.js",
|
|
13912
|
+
"next/dynamic": "${virtualPrefix}/_next/shims/dynamic.js",
|
|
13913
|
+
"next/script": "${virtualPrefix}/_next/shims/script.js",
|
|
13914
|
+
"next/font/google": "${virtualPrefix}/_next/shims/font/google.js"
|
|
13235
13915
|
}
|
|
13236
13916
|
}
|
|
13237
13917
|
<\/script>
|
|
@@ -13245,6 +13925,39 @@ export default function Head({ children }) {
|
|
|
13245
13925
|
|
|
13246
13926
|
const virtualBase = '${virtualPrefix}';
|
|
13247
13927
|
|
|
13928
|
+
// Initial route params (embedded by server for initial page load)
|
|
13929
|
+
const initialRouteParams = ${JSON.stringify(route.params)};
|
|
13930
|
+
const initialPathname = '${pathname}';
|
|
13931
|
+
|
|
13932
|
+
// Route params cache for client-side navigation
|
|
13933
|
+
const routeParamsCache = new Map();
|
|
13934
|
+
routeParamsCache.set(initialPathname, initialRouteParams);
|
|
13935
|
+
|
|
13936
|
+
// Extract route params from server for client-side navigation
|
|
13937
|
+
async function extractRouteParams(pathname) {
|
|
13938
|
+
// Strip virtual base if present
|
|
13939
|
+
let route = pathname;
|
|
13940
|
+
if (route.startsWith(virtualBase)) {
|
|
13941
|
+
route = route.slice(virtualBase.length);
|
|
13942
|
+
}
|
|
13943
|
+
route = route.replace(/^\\/+/, '/') || '/';
|
|
13944
|
+
|
|
13945
|
+
// Check cache first
|
|
13946
|
+
if (routeParamsCache.has(route)) {
|
|
13947
|
+
return routeParamsCache.get(route);
|
|
13948
|
+
}
|
|
13949
|
+
|
|
13950
|
+
try {
|
|
13951
|
+
const response = await fetch(virtualBase + '/_next/route-info?pathname=' + encodeURIComponent(route));
|
|
13952
|
+
const info = await response.json();
|
|
13953
|
+
routeParamsCache.set(route, info.params || {});
|
|
13954
|
+
return info.params || {};
|
|
13955
|
+
} catch (e) {
|
|
13956
|
+
console.error('[Router] Failed to extract route params:', e);
|
|
13957
|
+
return {};
|
|
13958
|
+
}
|
|
13959
|
+
}
|
|
13960
|
+
|
|
13248
13961
|
// Convert URL path to app router page module path
|
|
13249
13962
|
function getAppPageModulePath(pathname) {
|
|
13250
13963
|
let route = pathname;
|
|
@@ -13311,11 +14024,60 @@ export default function Head({ children }) {
|
|
|
13311
14024
|
return layouts;
|
|
13312
14025
|
}
|
|
13313
14026
|
|
|
14027
|
+
// Wrapper for async Server Components
|
|
14028
|
+
function AsyncComponent({ component: Component, pathname, search }) {
|
|
14029
|
+
const [content, setContent] = React.useState(null);
|
|
14030
|
+
const [error, setError] = React.useState(null);
|
|
14031
|
+
|
|
14032
|
+
React.useEffect(() => {
|
|
14033
|
+
let cancelled = false;
|
|
14034
|
+
async function render() {
|
|
14035
|
+
try {
|
|
14036
|
+
// Create searchParams as a Promise (Next.js 15 pattern)
|
|
14037
|
+
const url = new URL(window.location.href);
|
|
14038
|
+
const searchParamsObj = Object.fromEntries(url.searchParams);
|
|
14039
|
+
const searchParams = Promise.resolve(searchParamsObj);
|
|
14040
|
+
|
|
14041
|
+
// Extract route params from pathname (fetches from server for dynamic routes)
|
|
14042
|
+
const routeParams = await extractRouteParams(pathname);
|
|
14043
|
+
const params = Promise.resolve(routeParams);
|
|
14044
|
+
|
|
14045
|
+
// Call component with props like Next.js does for page components
|
|
14046
|
+
const result = Component({ searchParams, params });
|
|
14047
|
+
if (result && typeof result.then === 'function') {
|
|
14048
|
+
// It's a Promise (async component)
|
|
14049
|
+
const resolved = await result;
|
|
14050
|
+
if (!cancelled) setContent(resolved);
|
|
14051
|
+
} else {
|
|
14052
|
+
// Synchronous component - result is already JSX
|
|
14053
|
+
if (!cancelled) setContent(result);
|
|
14054
|
+
}
|
|
14055
|
+
} catch (e) {
|
|
14056
|
+
console.error('[AsyncComponent] Error rendering:', e);
|
|
14057
|
+
if (!cancelled) setError(e);
|
|
14058
|
+
}
|
|
14059
|
+
}
|
|
14060
|
+
render();
|
|
14061
|
+
return () => { cancelled = true; };
|
|
14062
|
+
}, [Component, pathname, search]);
|
|
14063
|
+
|
|
14064
|
+
if (error) {
|
|
14065
|
+
return React.createElement('div', { style: { color: 'red', padding: '20px' } },
|
|
14066
|
+
'Error: ' + error.message
|
|
14067
|
+
);
|
|
14068
|
+
}
|
|
14069
|
+
if (!content) {
|
|
14070
|
+
return React.createElement('div', { style: { padding: '20px' } }, 'Loading...');
|
|
14071
|
+
}
|
|
14072
|
+
return content;
|
|
14073
|
+
}
|
|
14074
|
+
|
|
13314
14075
|
// Router component
|
|
13315
14076
|
function Router() {
|
|
13316
14077
|
const [Page, setPage] = React.useState(null);
|
|
13317
14078
|
const [layouts, setLayouts] = React.useState([]);
|
|
13318
14079
|
const [path, setPath] = React.useState(window.location.pathname);
|
|
14080
|
+
const [search, setSearch] = React.useState(window.location.search);
|
|
13319
14081
|
|
|
13320
14082
|
React.useEffect(() => {
|
|
13321
14083
|
Promise.all([loadPage(path), loadLayouts(path)]).then(([P, L]) => {
|
|
@@ -13327,21 +14089,35 @@ export default function Head({ children }) {
|
|
|
13327
14089
|
React.useEffect(() => {
|
|
13328
14090
|
const handleNavigation = async () => {
|
|
13329
14091
|
const newPath = window.location.pathname;
|
|
14092
|
+
const newSearch = window.location.search;
|
|
14093
|
+
console.log('[Router] handleNavigation called, newPath:', newPath, 'current path:', path);
|
|
14094
|
+
|
|
14095
|
+
// Always update search params
|
|
14096
|
+
if (newSearch !== search) {
|
|
14097
|
+
setSearch(newSearch);
|
|
14098
|
+
}
|
|
14099
|
+
|
|
13330
14100
|
if (newPath !== path) {
|
|
14101
|
+
console.log('[Router] Path changed, loading new page...');
|
|
13331
14102
|
setPath(newPath);
|
|
13332
14103
|
const [P, L] = await Promise.all([loadPage(newPath), loadLayouts(newPath)]);
|
|
14104
|
+
console.log('[Router] Page loaded:', !!P, 'Layouts:', L.length);
|
|
13333
14105
|
if (P) setPage(() => P);
|
|
13334
14106
|
setLayouts(L);
|
|
14107
|
+
} else {
|
|
14108
|
+
console.log('[Router] Path unchanged, skipping navigation');
|
|
13335
14109
|
}
|
|
13336
14110
|
};
|
|
13337
14111
|
window.addEventListener('popstate', handleNavigation);
|
|
14112
|
+
console.log('[Router] Added popstate listener for path:', path);
|
|
13338
14113
|
return () => window.removeEventListener('popstate', handleNavigation);
|
|
13339
|
-
}, [path]);
|
|
14114
|
+
}, [path, search]);
|
|
13340
14115
|
|
|
13341
14116
|
if (!Page) return null;
|
|
13342
14117
|
|
|
13343
|
-
//
|
|
13344
|
-
|
|
14118
|
+
// Use AsyncComponent wrapper to handle async Server Components
|
|
14119
|
+
// Pass search to force re-render when query params change
|
|
14120
|
+
let content = React.createElement(AsyncComponent, { component: Page, pathname: path, search: search });
|
|
13345
14121
|
for (let i = layouts.length - 1; i >= 0; i--) {
|
|
13346
14122
|
content = React.createElement(layouts[i], null, content);
|
|
13347
14123
|
}
|
|
@@ -13463,6 +14239,7 @@ export default function Head({ children }) {
|
|
|
13463
14239
|
}
|
|
13464
14240
|
}
|
|
13465
14241
|
const envScript = this.generateEnvScript();
|
|
14242
|
+
const tailwindConfigScript = await this.loadTailwindConfigIfNeeded();
|
|
13466
14243
|
return `<!DOCTYPE html>
|
|
13467
14244
|
<html lang="en">
|
|
13468
14245
|
<head>
|
|
@@ -13472,6 +14249,7 @@ export default function Head({ children }) {
|
|
|
13472
14249
|
<title>Next.js App</title>
|
|
13473
14250
|
${envScript}
|
|
13474
14251
|
${TAILWIND_CDN_SCRIPT}
|
|
14252
|
+
${tailwindConfigScript}
|
|
13475
14253
|
${CORS_PROXY_SCRIPT}
|
|
13476
14254
|
${globalCssLinks.join("\n ")}
|
|
13477
14255
|
${REACT_REFRESH_PREAMBLE}
|
|
@@ -13485,7 +14263,12 @@ export default function Head({ children }) {
|
|
|
13485
14263
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client?dev",
|
|
13486
14264
|
"next/link": "${virtualPrefix}/_next/shims/link.js",
|
|
13487
14265
|
"next/router": "${virtualPrefix}/_next/shims/router.js",
|
|
13488
|
-
"next/head": "${virtualPrefix}/_next/shims/head.js"
|
|
14266
|
+
"next/head": "${virtualPrefix}/_next/shims/head.js",
|
|
14267
|
+
"next/navigation": "${virtualPrefix}/_next/shims/navigation.js",
|
|
14268
|
+
"next/image": "${virtualPrefix}/_next/shims/image.js",
|
|
14269
|
+
"next/dynamic": "${virtualPrefix}/_next/shims/dynamic.js",
|
|
14270
|
+
"next/script": "${virtualPrefix}/_next/shims/script.js",
|
|
14271
|
+
"next/font/google": "${virtualPrefix}/_next/shims/font/google.js"
|
|
13489
14272
|
}
|
|
13490
14273
|
}
|
|
13491
14274
|
<\/script>
|
|
@@ -13601,13 +14384,58 @@ export default function Head({ children }) {
|
|
|
13601
14384
|
body: buffer2
|
|
13602
14385
|
};
|
|
13603
14386
|
}
|
|
14387
|
+
resolveFileWithExtension(pathname) {
|
|
14388
|
+
if (/\.\w+$/.test(pathname) && this.exists(pathname)) {
|
|
14389
|
+
return pathname;
|
|
14390
|
+
}
|
|
14391
|
+
const extensions = [
|
|
14392
|
+
".tsx",
|
|
14393
|
+
".ts",
|
|
14394
|
+
".jsx",
|
|
14395
|
+
".js"
|
|
14396
|
+
];
|
|
14397
|
+
for (const ext of extensions) {
|
|
14398
|
+
const withExt = pathname + ext;
|
|
14399
|
+
if (this.exists(withExt)) {
|
|
14400
|
+
return withExt;
|
|
14401
|
+
}
|
|
14402
|
+
}
|
|
14403
|
+
for (const ext of extensions) {
|
|
14404
|
+
const indexPath = pathname + "/index" + ext;
|
|
14405
|
+
if (this.exists(indexPath)) {
|
|
14406
|
+
return indexPath;
|
|
14407
|
+
}
|
|
14408
|
+
}
|
|
14409
|
+
return null;
|
|
14410
|
+
}
|
|
13604
14411
|
needsTransform(path2) {
|
|
13605
14412
|
return /\.(jsx|tsx|ts)$/.test(path2);
|
|
13606
14413
|
}
|
|
13607
14414
|
async transformAndServe(filePath, urlPath) {
|
|
13608
14415
|
try {
|
|
13609
14416
|
const content = this.vfs.readFileSync(filePath, "utf8");
|
|
13610
|
-
const
|
|
14417
|
+
const hash = simpleHash(content);
|
|
14418
|
+
const cached = this.transformCache.get(filePath);
|
|
14419
|
+
if (cached && cached.hash === hash) {
|
|
14420
|
+
const buffer22 = BufferPolyfill.from(cached.code);
|
|
14421
|
+
return {
|
|
14422
|
+
statusCode: 200,
|
|
14423
|
+
statusMessage: "OK",
|
|
14424
|
+
headers: {
|
|
14425
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
14426
|
+
"Content-Length": String(buffer22.length),
|
|
14427
|
+
"Cache-Control": "no-cache",
|
|
14428
|
+
"X-Transformed": "true",
|
|
14429
|
+
"X-Cache": "hit"
|
|
14430
|
+
},
|
|
14431
|
+
body: buffer22
|
|
14432
|
+
};
|
|
14433
|
+
}
|
|
14434
|
+
const transformed = await this.transformCode(content, filePath);
|
|
14435
|
+
this.transformCache.set(filePath, {
|
|
14436
|
+
code: transformed,
|
|
14437
|
+
hash
|
|
14438
|
+
});
|
|
13611
14439
|
const buffer2 = BufferPolyfill.from(transformed);
|
|
13612
14440
|
return {
|
|
13613
14441
|
statusCode: 200,
|
|
@@ -13646,11 +14474,12 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13646
14474
|
throw new Error("esbuild not available");
|
|
13647
14475
|
}
|
|
13648
14476
|
const codeWithoutCssImports = this.stripCssImports(code2);
|
|
14477
|
+
const codeWithResolvedAliases = this.resolvePathAliases(codeWithoutCssImports, filename2);
|
|
13649
14478
|
let loader = "js";
|
|
13650
14479
|
if (filename2.endsWith(".jsx")) loader = "jsx";
|
|
13651
14480
|
else if (filename2.endsWith(".tsx")) loader = "tsx";
|
|
13652
14481
|
else if (filename2.endsWith(".ts")) loader = "ts";
|
|
13653
|
-
const result = await esbuild2.transform(
|
|
14482
|
+
const result = await esbuild2.transform(codeWithResolvedAliases, {
|
|
13654
14483
|
loader,
|
|
13655
14484
|
format: "esm",
|
|
13656
14485
|
target: "esnext",
|
|
@@ -13659,15 +14488,57 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13659
14488
|
sourcemap: "inline",
|
|
13660
14489
|
sourcefile: filename2
|
|
13661
14490
|
});
|
|
14491
|
+
const codeWithCdnImports = this.redirectNpmImports(result.code);
|
|
13662
14492
|
if (/\.(jsx|tsx)$/.test(filename2)) {
|
|
13663
|
-
return this.addReactRefresh(
|
|
14493
|
+
return this.addReactRefresh(codeWithCdnImports, filename2);
|
|
13664
14494
|
}
|
|
13665
|
-
return
|
|
14495
|
+
return codeWithCdnImports;
|
|
14496
|
+
}
|
|
14497
|
+
redirectNpmImports(code2) {
|
|
14498
|
+
const explicitMappings = {
|
|
14499
|
+
"react": "https://esm.sh/react@18.2.0?dev",
|
|
14500
|
+
"react/jsx-runtime": "https://esm.sh/react@18.2.0&dev/jsx-runtime",
|
|
14501
|
+
"react/jsx-dev-runtime": "https://esm.sh/react@18.2.0&dev/jsx-dev-runtime",
|
|
14502
|
+
"react-dom": "https://esm.sh/react-dom@18.2.0?dev",
|
|
14503
|
+
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client?dev"
|
|
14504
|
+
};
|
|
14505
|
+
const localPackages = /* @__PURE__ */ new Set([
|
|
14506
|
+
"next/link",
|
|
14507
|
+
"next/router",
|
|
14508
|
+
"next/head",
|
|
14509
|
+
"next/navigation",
|
|
14510
|
+
"next/dynamic",
|
|
14511
|
+
"next/image",
|
|
14512
|
+
"next/script",
|
|
14513
|
+
"next/font/google",
|
|
14514
|
+
"convex/_generated/api"
|
|
14515
|
+
]);
|
|
14516
|
+
const importPattern = /(from\s*['"])([^'"./][^'"]*?)(['"])/g;
|
|
14517
|
+
return code2.replace(importPattern, (match, prefix, packageName, suffix) => {
|
|
14518
|
+
if (packageName.startsWith("http://") || packageName.startsWith("https://") || packageName.startsWith("/__virtual__")) {
|
|
14519
|
+
return match;
|
|
14520
|
+
}
|
|
14521
|
+
if (explicitMappings[packageName]) {
|
|
14522
|
+
return `${prefix}${explicitMappings[packageName]}${suffix}`;
|
|
14523
|
+
}
|
|
14524
|
+
if (localPackages.has(packageName)) {
|
|
14525
|
+
return match;
|
|
14526
|
+
}
|
|
14527
|
+
const basePkg = packageName.includes("/") ? packageName.split("/")[0] : packageName;
|
|
14528
|
+
const isScoped = basePkg.startsWith("@");
|
|
14529
|
+
const scopedBasePkg = isScoped && packageName.includes("/") ? packageName.split("/").slice(0, 2).join("/") : basePkg;
|
|
14530
|
+
if (localPackages.has(scopedBasePkg)) {
|
|
14531
|
+
return match;
|
|
14532
|
+
}
|
|
14533
|
+
const esmUrl = `https://esm.sh/${packageName}?external=react`;
|
|
14534
|
+
return `${prefix}${esmUrl}${suffix}`;
|
|
14535
|
+
});
|
|
13666
14536
|
}
|
|
13667
14537
|
stripCssImports(code2) {
|
|
13668
|
-
return code2.replace(/import\s+['"][^'"]+\.css['"]\s*;?/g, "
|
|
14538
|
+
return code2.replace(/import\s+['"][^'"]+\.css['"]\s*;?/g, "");
|
|
13669
14539
|
}
|
|
13670
14540
|
async transformApiHandler(code2, filename2) {
|
|
14541
|
+
const codeWithResolvedAliases = this.resolvePathAliases(code2, filename2);
|
|
13671
14542
|
if (isBrowser) {
|
|
13672
14543
|
await initEsbuild();
|
|
13673
14544
|
const esbuild2 = getEsbuild();
|
|
@@ -13678,7 +14549,7 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13678
14549
|
if (filename2.endsWith(".jsx")) loader = "jsx";
|
|
13679
14550
|
else if (filename2.endsWith(".tsx")) loader = "tsx";
|
|
13680
14551
|
else if (filename2.endsWith(".ts")) loader = "ts";
|
|
13681
|
-
const result = await esbuild2.transform(
|
|
14552
|
+
const result = await esbuild2.transform(codeWithResolvedAliases, {
|
|
13682
14553
|
loader,
|
|
13683
14554
|
format: "cjs",
|
|
13684
14555
|
target: "esnext",
|
|
@@ -13687,7 +14558,7 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13687
14558
|
});
|
|
13688
14559
|
return result.code;
|
|
13689
14560
|
}
|
|
13690
|
-
let transformed =
|
|
14561
|
+
let transformed = codeWithResolvedAliases;
|
|
13691
14562
|
transformed = transformed.replace(/import\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g, 'const $1 = require("$2")');
|
|
13692
14563
|
transformed = transformed.replace(/import\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g, 'const {$1} = require("$2")');
|
|
13693
14564
|
transformed = transformed.replace(/export\s+default\s+function\s+(\w+)/g, "module.exports = function $1");
|
|
@@ -13803,6 +14674,50 @@ ${registrations}
|
|
|
13803
14674
|
}
|
|
13804
14675
|
}
|
|
13805
14676
|
}
|
|
14677
|
+
serveFile(filePath) {
|
|
14678
|
+
if (filePath.endsWith(".json")) {
|
|
14679
|
+
try {
|
|
14680
|
+
const normalizedPath = this.resolvePath(filePath);
|
|
14681
|
+
const content = this.vfs.readFileSync(normalizedPath);
|
|
14682
|
+
let jsonContent;
|
|
14683
|
+
if (typeof content === "string") {
|
|
14684
|
+
jsonContent = content;
|
|
14685
|
+
} else if (content instanceof Uint8Array) {
|
|
14686
|
+
jsonContent = new TextDecoder("utf-8").decode(content);
|
|
14687
|
+
} else {
|
|
14688
|
+
jsonContent = BufferPolyfill.from(content).toString("utf-8");
|
|
14689
|
+
}
|
|
14690
|
+
const esModuleContent = `export default ${jsonContent};`;
|
|
14691
|
+
const buffer2 = BufferPolyfill.from(esModuleContent);
|
|
14692
|
+
return {
|
|
14693
|
+
statusCode: 200,
|
|
14694
|
+
statusMessage: "OK",
|
|
14695
|
+
headers: {
|
|
14696
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
14697
|
+
"Content-Length": String(buffer2.length),
|
|
14698
|
+
"Cache-Control": "no-cache"
|
|
14699
|
+
},
|
|
14700
|
+
body: buffer2
|
|
14701
|
+
};
|
|
14702
|
+
} catch (error) {
|
|
14703
|
+
if (error.code === "ENOENT") {
|
|
14704
|
+
return this.notFound(filePath);
|
|
14705
|
+
}
|
|
14706
|
+
return this.serverError(error);
|
|
14707
|
+
}
|
|
14708
|
+
}
|
|
14709
|
+
return super.serveFile(filePath);
|
|
14710
|
+
}
|
|
14711
|
+
resolvePath(urlPath) {
|
|
14712
|
+
let path2 = urlPath.split("?")[0].split("#")[0];
|
|
14713
|
+
if (!path2.startsWith("/")) {
|
|
14714
|
+
path2 = "/" + path2;
|
|
14715
|
+
}
|
|
14716
|
+
if (this.root !== "/") {
|
|
14717
|
+
path2 = this.root + path2;
|
|
14718
|
+
}
|
|
14719
|
+
return path2;
|
|
14720
|
+
}
|
|
13806
14721
|
stop() {
|
|
13807
14722
|
if (this.watcherCleanup) {
|
|
13808
14723
|
this.watcherCleanup();
|