almostnode 0.2.5 → 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 +25 -16
- package/dist/frameworks/next-dev-server.d.ts +61 -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/index.cjs +869 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +845 -27
- 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/package.json +2 -1
- package/src/frameworks/next-dev-server.ts +913 -34
- package/src/frameworks/tailwind-config-loader.ts +206 -0
- package/src/macaly-demo.ts +172 -0
package/dist/index.mjs
CHANGED
|
@@ -11977,6 +11977,123 @@ export default css;
|
|
|
11977
11977
|
}
|
|
11978
11978
|
}
|
|
11979
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
|
+
}
|
|
11980
12097
|
const isBrowser = typeof window !== "undefined" && typeof window.navigator !== "undefined" && "serviceWorker" in window.navigator;
|
|
11981
12098
|
async function initEsbuild() {
|
|
11982
12099
|
if (!isBrowser) return;
|
|
@@ -12201,25 +12318,31 @@ const applyVirtualBase = (url) => {
|
|
|
12201
12318
|
|
|
12202
12319
|
export default function Link({ href, children, ...props }) {
|
|
12203
12320
|
const handleClick = (e) => {
|
|
12321
|
+
console.log('[Link] Click handler called, href:', href);
|
|
12322
|
+
|
|
12204
12323
|
if (props.onClick) {
|
|
12205
12324
|
props.onClick(e);
|
|
12206
12325
|
}
|
|
12207
12326
|
|
|
12208
12327
|
// Allow cmd/ctrl click to open in new tab
|
|
12209
12328
|
if (e.metaKey || e.ctrlKey) {
|
|
12329
|
+
console.log('[Link] Meta/Ctrl key pressed, allowing default behavior');
|
|
12210
12330
|
return;
|
|
12211
12331
|
}
|
|
12212
12332
|
|
|
12213
12333
|
if (typeof href !== 'string' || !href || href.startsWith('#') || href.startsWith('?')) {
|
|
12334
|
+
console.log('[Link] Skipping navigation for href:', href);
|
|
12214
12335
|
return;
|
|
12215
12336
|
}
|
|
12216
12337
|
|
|
12217
12338
|
if (/^(https?:)?\\/\\//.test(href)) {
|
|
12339
|
+
console.log('[Link] External URL, allowing default behavior:', href);
|
|
12218
12340
|
return;
|
|
12219
12341
|
}
|
|
12220
12342
|
|
|
12221
12343
|
e.preventDefault();
|
|
12222
12344
|
const resolvedHref = applyVirtualBase(href);
|
|
12345
|
+
console.log('[Link] Navigating to:', resolvedHref);
|
|
12223
12346
|
window.history.pushState({}, '', resolvedHref);
|
|
12224
12347
|
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
12225
12348
|
};
|
|
@@ -12557,6 +12680,305 @@ export default function Head({ children }) {
|
|
|
12557
12680
|
|
|
12558
12681
|
return null;
|
|
12559
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;
|
|
12560
12982
|
`;
|
|
12561
12983
|
NextDevServer = class extends DevServer {
|
|
12562
12984
|
constructor(vfs2, options2) {
|
|
@@ -12569,6 +12991,10 @@ export default function Head({ children }) {
|
|
|
12569
12991
|
__publicField(this, "hmrTargetWindow", null);
|
|
12570
12992
|
__publicField(this, "options");
|
|
12571
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", "");
|
|
12572
12998
|
this.options = options2;
|
|
12573
12999
|
this.pagesDir = options2.pagesDir || "/pages";
|
|
12574
13000
|
this.appDir = options2.appDir || "/app";
|
|
@@ -12578,6 +13004,82 @@ export default function Head({ children }) {
|
|
|
12578
13004
|
} else {
|
|
12579
13005
|
this.useAppRouter = this.hasAppRouter();
|
|
12580
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;
|
|
12581
13083
|
}
|
|
12582
13084
|
setEnv(key, value) {
|
|
12583
13085
|
this.options.env = this.options.env || {};
|
|
@@ -12593,20 +13095,38 @@ export default function Head({ children }) {
|
|
|
12593
13095
|
}
|
|
12594
13096
|
generateEnvScript() {
|
|
12595
13097
|
const env = this.options.env || {};
|
|
12596
|
-
const publicEnvVars =
|
|
12597
|
-
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
return "";
|
|
13098
|
+
const publicEnvVars = {};
|
|
13099
|
+
for (const [key, value] of Object.entries(env)) {
|
|
13100
|
+
if (key.startsWith("NEXT_PUBLIC_")) {
|
|
13101
|
+
publicEnvVars[key] = value;
|
|
13102
|
+
}
|
|
12602
13103
|
}
|
|
12603
13104
|
return `<script>
|
|
12604
|
-
//
|
|
13105
|
+
// Environment variables (injected by NextDevServer)
|
|
12605
13106
|
window.process = window.process || {};
|
|
12606
13107
|
window.process.env = window.process.env || {};
|
|
12607
13108
|
Object.assign(window.process.env, ${JSON.stringify(publicEnvVars)});
|
|
12608
13109
|
<\/script>`;
|
|
12609
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
|
+
}
|
|
12610
13130
|
hasAppRouter() {
|
|
12611
13131
|
try {
|
|
12612
13132
|
if (!this.exists(this.appDir)) return false;
|
|
@@ -12626,10 +13146,26 @@ export default function Head({ children }) {
|
|
|
12626
13146
|
}
|
|
12627
13147
|
async handleRequest(method, url2, headers, body) {
|
|
12628
13148
|
const urlObj = new URL(url2, "http://localhost");
|
|
12629
|
-
|
|
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
|
+
}
|
|
12630
13163
|
if (pathname.startsWith("/_next/shims/")) {
|
|
12631
13164
|
return this.serveNextShim(pathname);
|
|
12632
13165
|
}
|
|
13166
|
+
if (pathname === "/_next/route-info") {
|
|
13167
|
+
return this.serveRouteInfo(urlObj.searchParams.get("pathname") || "/");
|
|
13168
|
+
}
|
|
12633
13169
|
if (pathname.startsWith("/_next/pages/")) {
|
|
12634
13170
|
return this.servePageComponent(pathname);
|
|
12635
13171
|
}
|
|
@@ -12649,6 +13185,13 @@ export default function Head({ children }) {
|
|
|
12649
13185
|
if (this.needsTransform(pathname) && this.exists(pathname)) {
|
|
12650
13186
|
return this.transformAndServe(pathname, pathname);
|
|
12651
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
|
+
}
|
|
12652
13195
|
if (this.exists(pathname) && !this.isDirectory(pathname)) {
|
|
12653
13196
|
return this.serveFile(pathname);
|
|
12654
13197
|
}
|
|
@@ -12670,6 +13213,18 @@ export default function Head({ children }) {
|
|
|
12670
13213
|
case "navigation":
|
|
12671
13214
|
code2 = NEXT_NAVIGATION_SHIM;
|
|
12672
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;
|
|
12673
13228
|
default:
|
|
12674
13229
|
return this.notFound(pathname);
|
|
12675
13230
|
}
|
|
@@ -12685,6 +13240,28 @@ export default function Head({ children }) {
|
|
|
12685
13240
|
body: buffer2
|
|
12686
13241
|
};
|
|
12687
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
|
+
}
|
|
12688
13265
|
serveStaticAsset(pathname) {
|
|
12689
13266
|
const filePath = pathname.replace("/_next/static/", "/");
|
|
12690
13267
|
if (this.exists(filePath)) {
|
|
@@ -13193,7 +13770,8 @@ export default function Head({ children }) {
|
|
|
13193
13770
|
if (this.exists(pagePath)) {
|
|
13194
13771
|
return {
|
|
13195
13772
|
page: pagePath,
|
|
13196
|
-
layouts
|
|
13773
|
+
layouts,
|
|
13774
|
+
params: {}
|
|
13197
13775
|
};
|
|
13198
13776
|
}
|
|
13199
13777
|
}
|
|
@@ -13206,7 +13784,7 @@ export default function Head({ children }) {
|
|
|
13206
13784
|
".js",
|
|
13207
13785
|
".ts"
|
|
13208
13786
|
];
|
|
13209
|
-
const tryPath = (dirPath, remainingSegments, layouts2) => {
|
|
13787
|
+
const tryPath = (dirPath, remainingSegments, layouts2, params) => {
|
|
13210
13788
|
for (const ext of extensions) {
|
|
13211
13789
|
const layoutPath = `${dirPath}/layout${ext}`;
|
|
13212
13790
|
if (this.exists(layoutPath) && !layouts2.includes(layoutPath)) {
|
|
@@ -13222,7 +13800,8 @@ export default function Head({ children }) {
|
|
|
13222
13800
|
if (this.exists(pagePath)) {
|
|
13223
13801
|
return {
|
|
13224
13802
|
page: pagePath,
|
|
13225
|
-
layouts: layouts2
|
|
13803
|
+
layouts: layouts2,
|
|
13804
|
+
params
|
|
13226
13805
|
};
|
|
13227
13806
|
}
|
|
13228
13807
|
}
|
|
@@ -13231,16 +13810,35 @@ export default function Head({ children }) {
|
|
|
13231
13810
|
const [current, ...rest] = remainingSegments;
|
|
13232
13811
|
const exactPath = `${dirPath}/${current}`;
|
|
13233
13812
|
if (this.isDirectory(exactPath)) {
|
|
13234
|
-
const result = tryPath(exactPath, rest, layouts2);
|
|
13813
|
+
const result = tryPath(exactPath, rest, layouts2, params);
|
|
13235
13814
|
if (result) return result;
|
|
13236
13815
|
}
|
|
13237
13816
|
try {
|
|
13238
13817
|
const entries = this.vfs.readdirSync(dirPath);
|
|
13239
13818
|
for (const entry of entries) {
|
|
13240
|
-
if (entry.startsWith("[") && entry.endsWith("]")
|
|
13819
|
+
if (entry.startsWith("[...") && entry.endsWith("]")) {
|
|
13241
13820
|
const dynamicPath = `${dirPath}/${entry}`;
|
|
13242
13821
|
if (this.isDirectory(dynamicPath)) {
|
|
13243
|
-
const
|
|
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(".")) {
|
|
13834
|
+
const dynamicPath = `${dirPath}/${entry}`;
|
|
13835
|
+
if (this.isDirectory(dynamicPath)) {
|
|
13836
|
+
const paramName = entry.slice(1, -1);
|
|
13837
|
+
const newParams = {
|
|
13838
|
+
...params,
|
|
13839
|
+
[paramName]: current
|
|
13840
|
+
};
|
|
13841
|
+
const result = tryPath(dynamicPath, rest, layouts2, newParams);
|
|
13244
13842
|
if (result) return result;
|
|
13245
13843
|
}
|
|
13246
13844
|
}
|
|
@@ -13257,7 +13855,7 @@ export default function Head({ children }) {
|
|
|
13257
13855
|
break;
|
|
13258
13856
|
}
|
|
13259
13857
|
}
|
|
13260
|
-
return tryPath(this.appDir, segments, layouts);
|
|
13858
|
+
return tryPath(this.appDir, segments, layouts, {});
|
|
13261
13859
|
}
|
|
13262
13860
|
async generateAppRouterHtml(route, pathname) {
|
|
13263
13861
|
const virtualPrefix = `/__virtual__/${this.port}`;
|
|
@@ -13277,6 +13875,7 @@ export default function Head({ children }) {
|
|
|
13277
13875
|
for (let i = route.layouts.length - 1; i >= 0; i--) {
|
|
13278
13876
|
}
|
|
13279
13877
|
const envScript = this.generateEnvScript();
|
|
13878
|
+
const tailwindConfigScript = await this.loadTailwindConfigIfNeeded();
|
|
13280
13879
|
return `<!DOCTYPE html>
|
|
13281
13880
|
<html lang="en">
|
|
13282
13881
|
<head>
|
|
@@ -13286,6 +13885,7 @@ export default function Head({ children }) {
|
|
|
13286
13885
|
<title>Next.js App</title>
|
|
13287
13886
|
${envScript}
|
|
13288
13887
|
${TAILWIND_CDN_SCRIPT}
|
|
13888
|
+
${tailwindConfigScript}
|
|
13289
13889
|
${CORS_PROXY_SCRIPT}
|
|
13290
13890
|
${globalCssLinks.join("\n ")}
|
|
13291
13891
|
${REACT_REFRESH_PREAMBLE}
|
|
@@ -13307,7 +13907,11 @@ export default function Head({ children }) {
|
|
|
13307
13907
|
"next/link": "${virtualPrefix}/_next/shims/link.js",
|
|
13308
13908
|
"next/router": "${virtualPrefix}/_next/shims/router.js",
|
|
13309
13909
|
"next/head": "${virtualPrefix}/_next/shims/head.js",
|
|
13310
|
-
"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"
|
|
13311
13915
|
}
|
|
13312
13916
|
}
|
|
13313
13917
|
<\/script>
|
|
@@ -13321,6 +13925,39 @@ export default function Head({ children }) {
|
|
|
13321
13925
|
|
|
13322
13926
|
const virtualBase = '${virtualPrefix}';
|
|
13323
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
|
+
|
|
13324
13961
|
// Convert URL path to app router page module path
|
|
13325
13962
|
function getAppPageModulePath(pathname) {
|
|
13326
13963
|
let route = pathname;
|
|
@@ -13387,11 +14024,60 @@ export default function Head({ children }) {
|
|
|
13387
14024
|
return layouts;
|
|
13388
14025
|
}
|
|
13389
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
|
+
|
|
13390
14075
|
// Router component
|
|
13391
14076
|
function Router() {
|
|
13392
14077
|
const [Page, setPage] = React.useState(null);
|
|
13393
14078
|
const [layouts, setLayouts] = React.useState([]);
|
|
13394
14079
|
const [path, setPath] = React.useState(window.location.pathname);
|
|
14080
|
+
const [search, setSearch] = React.useState(window.location.search);
|
|
13395
14081
|
|
|
13396
14082
|
React.useEffect(() => {
|
|
13397
14083
|
Promise.all([loadPage(path), loadLayouts(path)]).then(([P, L]) => {
|
|
@@ -13403,21 +14089,35 @@ export default function Head({ children }) {
|
|
|
13403
14089
|
React.useEffect(() => {
|
|
13404
14090
|
const handleNavigation = async () => {
|
|
13405
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
|
+
|
|
13406
14100
|
if (newPath !== path) {
|
|
14101
|
+
console.log('[Router] Path changed, loading new page...');
|
|
13407
14102
|
setPath(newPath);
|
|
13408
14103
|
const [P, L] = await Promise.all([loadPage(newPath), loadLayouts(newPath)]);
|
|
14104
|
+
console.log('[Router] Page loaded:', !!P, 'Layouts:', L.length);
|
|
13409
14105
|
if (P) setPage(() => P);
|
|
13410
14106
|
setLayouts(L);
|
|
14107
|
+
} else {
|
|
14108
|
+
console.log('[Router] Path unchanged, skipping navigation');
|
|
13411
14109
|
}
|
|
13412
14110
|
};
|
|
13413
14111
|
window.addEventListener('popstate', handleNavigation);
|
|
14112
|
+
console.log('[Router] Added popstate listener for path:', path);
|
|
13414
14113
|
return () => window.removeEventListener('popstate', handleNavigation);
|
|
13415
|
-
}, [path]);
|
|
14114
|
+
}, [path, search]);
|
|
13416
14115
|
|
|
13417
14116
|
if (!Page) return null;
|
|
13418
14117
|
|
|
13419
|
-
//
|
|
13420
|
-
|
|
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 });
|
|
13421
14121
|
for (let i = layouts.length - 1; i >= 0; i--) {
|
|
13422
14122
|
content = React.createElement(layouts[i], null, content);
|
|
13423
14123
|
}
|
|
@@ -13539,6 +14239,7 @@ export default function Head({ children }) {
|
|
|
13539
14239
|
}
|
|
13540
14240
|
}
|
|
13541
14241
|
const envScript = this.generateEnvScript();
|
|
14242
|
+
const tailwindConfigScript = await this.loadTailwindConfigIfNeeded();
|
|
13542
14243
|
return `<!DOCTYPE html>
|
|
13543
14244
|
<html lang="en">
|
|
13544
14245
|
<head>
|
|
@@ -13548,6 +14249,7 @@ export default function Head({ children }) {
|
|
|
13548
14249
|
<title>Next.js App</title>
|
|
13549
14250
|
${envScript}
|
|
13550
14251
|
${TAILWIND_CDN_SCRIPT}
|
|
14252
|
+
${tailwindConfigScript}
|
|
13551
14253
|
${CORS_PROXY_SCRIPT}
|
|
13552
14254
|
${globalCssLinks.join("\n ")}
|
|
13553
14255
|
${REACT_REFRESH_PREAMBLE}
|
|
@@ -13561,7 +14263,12 @@ export default function Head({ children }) {
|
|
|
13561
14263
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client?dev",
|
|
13562
14264
|
"next/link": "${virtualPrefix}/_next/shims/link.js",
|
|
13563
14265
|
"next/router": "${virtualPrefix}/_next/shims/router.js",
|
|
13564
|
-
"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"
|
|
13565
14272
|
}
|
|
13566
14273
|
}
|
|
13567
14274
|
<\/script>
|
|
@@ -13677,6 +14384,30 @@ export default function Head({ children }) {
|
|
|
13677
14384
|
body: buffer2
|
|
13678
14385
|
};
|
|
13679
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
|
+
}
|
|
13680
14411
|
needsTransform(path2) {
|
|
13681
14412
|
return /\.(jsx|tsx|ts)$/.test(path2);
|
|
13682
14413
|
}
|
|
@@ -13700,7 +14431,7 @@ export default function Head({ children }) {
|
|
|
13700
14431
|
body: buffer22
|
|
13701
14432
|
};
|
|
13702
14433
|
}
|
|
13703
|
-
const transformed = await this.transformCode(content,
|
|
14434
|
+
const transformed = await this.transformCode(content, filePath);
|
|
13704
14435
|
this.transformCache.set(filePath, {
|
|
13705
14436
|
code: transformed,
|
|
13706
14437
|
hash
|
|
@@ -13743,11 +14474,12 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13743
14474
|
throw new Error("esbuild not available");
|
|
13744
14475
|
}
|
|
13745
14476
|
const codeWithoutCssImports = this.stripCssImports(code2);
|
|
14477
|
+
const codeWithResolvedAliases = this.resolvePathAliases(codeWithoutCssImports, filename2);
|
|
13746
14478
|
let loader = "js";
|
|
13747
14479
|
if (filename2.endsWith(".jsx")) loader = "jsx";
|
|
13748
14480
|
else if (filename2.endsWith(".tsx")) loader = "tsx";
|
|
13749
14481
|
else if (filename2.endsWith(".ts")) loader = "ts";
|
|
13750
|
-
const result = await esbuild2.transform(
|
|
14482
|
+
const result = await esbuild2.transform(codeWithResolvedAliases, {
|
|
13751
14483
|
loader,
|
|
13752
14484
|
format: "esm",
|
|
13753
14485
|
target: "esnext",
|
|
@@ -13756,15 +14488,57 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13756
14488
|
sourcemap: "inline",
|
|
13757
14489
|
sourcefile: filename2
|
|
13758
14490
|
});
|
|
14491
|
+
const codeWithCdnImports = this.redirectNpmImports(result.code);
|
|
13759
14492
|
if (/\.(jsx|tsx)$/.test(filename2)) {
|
|
13760
|
-
return this.addReactRefresh(
|
|
14493
|
+
return this.addReactRefresh(codeWithCdnImports, filename2);
|
|
13761
14494
|
}
|
|
13762
|
-
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
|
+
});
|
|
13763
14536
|
}
|
|
13764
14537
|
stripCssImports(code2) {
|
|
13765
|
-
return code2.replace(/import\s+['"][^'"]+\.css['"]\s*;?/g, "
|
|
14538
|
+
return code2.replace(/import\s+['"][^'"]+\.css['"]\s*;?/g, "");
|
|
13766
14539
|
}
|
|
13767
14540
|
async transformApiHandler(code2, filename2) {
|
|
14541
|
+
const codeWithResolvedAliases = this.resolvePathAliases(code2, filename2);
|
|
13768
14542
|
if (isBrowser) {
|
|
13769
14543
|
await initEsbuild();
|
|
13770
14544
|
const esbuild2 = getEsbuild();
|
|
@@ -13775,7 +14549,7 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13775
14549
|
if (filename2.endsWith(".jsx")) loader = "jsx";
|
|
13776
14550
|
else if (filename2.endsWith(".tsx")) loader = "tsx";
|
|
13777
14551
|
else if (filename2.endsWith(".ts")) loader = "ts";
|
|
13778
|
-
const result = await esbuild2.transform(
|
|
14552
|
+
const result = await esbuild2.transform(codeWithResolvedAliases, {
|
|
13779
14553
|
loader,
|
|
13780
14554
|
format: "cjs",
|
|
13781
14555
|
target: "esnext",
|
|
@@ -13784,7 +14558,7 @@ console.error(${JSON.stringify(message)});`;
|
|
|
13784
14558
|
});
|
|
13785
14559
|
return result.code;
|
|
13786
14560
|
}
|
|
13787
|
-
let transformed =
|
|
14561
|
+
let transformed = codeWithResolvedAliases;
|
|
13788
14562
|
transformed = transformed.replace(/import\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g, 'const $1 = require("$2")');
|
|
13789
14563
|
transformed = transformed.replace(/import\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g, 'const {$1} = require("$2")');
|
|
13790
14564
|
transformed = transformed.replace(/export\s+default\s+function\s+(\w+)/g, "module.exports = function $1");
|
|
@@ -13900,6 +14674,50 @@ ${registrations}
|
|
|
13900
14674
|
}
|
|
13901
14675
|
}
|
|
13902
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
|
+
}
|
|
13903
14721
|
stop() {
|
|
13904
14722
|
if (this.watcherCleanup) {
|
|
13905
14723
|
this.watcherCleanup();
|