almostnode 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frameworks/next-dev-server.d.ts +5 -0
- package/dist/frameworks/next-dev-server.d.ts.map +1 -1
- package/dist/index.cjs +127 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +128 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/frameworks/next-dev-server.ts +135 -8
package/package.json
CHANGED
|
@@ -816,11 +816,16 @@ export class NextDevServer extends DevServer {
|
|
|
816
816
|
return this.serveNextShim(pathname);
|
|
817
817
|
}
|
|
818
818
|
|
|
819
|
-
// Serve page components for client-side navigation
|
|
819
|
+
// Serve page components for client-side navigation (Pages Router)
|
|
820
820
|
if (pathname.startsWith('/_next/pages/')) {
|
|
821
821
|
return this.servePageComponent(pathname);
|
|
822
822
|
}
|
|
823
823
|
|
|
824
|
+
// Serve app components for client-side navigation (App Router)
|
|
825
|
+
if (pathname.startsWith('/_next/app/')) {
|
|
826
|
+
return this.serveAppComponent(pathname);
|
|
827
|
+
}
|
|
828
|
+
|
|
824
829
|
// Static assets from /_next/static/*
|
|
825
830
|
if (pathname.startsWith('/_next/static/')) {
|
|
826
831
|
return this.serveStaticAsset(pathname);
|
|
@@ -922,6 +927,28 @@ export class NextDevServer extends DevServer {
|
|
|
922
927
|
return this.transformAndServe(pageFile, pageFile);
|
|
923
928
|
}
|
|
924
929
|
|
|
930
|
+
/**
|
|
931
|
+
* Serve app components for client-side navigation (App Router)
|
|
932
|
+
* Maps /_next/app/app/about/page.js → /app/about/page.tsx (transformed)
|
|
933
|
+
*/
|
|
934
|
+
private async serveAppComponent(pathname: string): Promise<ResponseData> {
|
|
935
|
+
// Extract the file path from /_next/app/app/about/page.js → /app/about/page
|
|
936
|
+
const filePath = pathname
|
|
937
|
+
.replace('/_next/app', '')
|
|
938
|
+
.replace(/\.js$/, '');
|
|
939
|
+
|
|
940
|
+
// Try different extensions
|
|
941
|
+
const extensions = ['.tsx', '.jsx', '.ts', '.js'];
|
|
942
|
+
for (const ext of extensions) {
|
|
943
|
+
const fullPath = filePath + ext;
|
|
944
|
+
if (this.exists(fullPath)) {
|
|
945
|
+
return this.transformAndServe(fullPath, fullPath);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
return this.notFound(pathname);
|
|
950
|
+
}
|
|
951
|
+
|
|
925
952
|
/**
|
|
926
953
|
* Handle API route requests
|
|
927
954
|
*/
|
|
@@ -1672,17 +1699,117 @@ export class NextDevServer extends DevServer {
|
|
|
1672
1699
|
<script type="module">
|
|
1673
1700
|
import React from 'react';
|
|
1674
1701
|
import ReactDOM from 'react-dom/client';
|
|
1675
|
-
import Page from '${pageModulePath}';
|
|
1676
|
-
${layoutImports}
|
|
1677
1702
|
|
|
1678
|
-
|
|
1679
|
-
|
|
1703
|
+
const virtualBase = '${virtualPrefix}';
|
|
1704
|
+
|
|
1705
|
+
// Convert URL path to app router page module path
|
|
1706
|
+
function getAppPageModulePath(pathname) {
|
|
1707
|
+
let route = pathname;
|
|
1708
|
+
if (route.startsWith(virtualBase)) {
|
|
1709
|
+
route = route.slice(virtualBase.length);
|
|
1710
|
+
}
|
|
1711
|
+
route = route.replace(/^\\/+/, '/') || '/';
|
|
1712
|
+
// App Router: / -> /app/page, /about -> /app/about/page
|
|
1713
|
+
const pagePath = route === '/' ? '/app/page' : '/app' + route + '/page';
|
|
1714
|
+
return virtualBase + '/_next/app' + pagePath + '.js';
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
// Get layout paths for a route
|
|
1718
|
+
function getLayoutPaths(pathname) {
|
|
1719
|
+
let route = pathname;
|
|
1720
|
+
if (route.startsWith(virtualBase)) {
|
|
1721
|
+
route = route.slice(virtualBase.length);
|
|
1722
|
+
}
|
|
1723
|
+
route = route.replace(/^\\/+/, '/') || '/';
|
|
1724
|
+
|
|
1725
|
+
// Build layout paths from root to current route
|
|
1726
|
+
const layouts = [virtualBase + '/_next/app/app/layout.js'];
|
|
1727
|
+
if (route !== '/') {
|
|
1728
|
+
const segments = route.split('/').filter(Boolean);
|
|
1729
|
+
let currentPath = '/app';
|
|
1730
|
+
for (const segment of segments) {
|
|
1731
|
+
currentPath += '/' + segment;
|
|
1732
|
+
layouts.push(virtualBase + '/_next/app' + currentPath + '/layout.js');
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
return layouts;
|
|
1680
1736
|
}
|
|
1681
1737
|
|
|
1738
|
+
// Dynamic page loader
|
|
1739
|
+
async function loadPage(pathname) {
|
|
1740
|
+
const modulePath = getAppPageModulePath(pathname);
|
|
1741
|
+
try {
|
|
1742
|
+
const module = await import(/* @vite-ignore */ modulePath);
|
|
1743
|
+
return module.default;
|
|
1744
|
+
} catch (e) {
|
|
1745
|
+
console.error('[Navigation] Failed to load page:', modulePath, e);
|
|
1746
|
+
return null;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// Load layouts (with caching)
|
|
1751
|
+
const layoutCache = new Map();
|
|
1752
|
+
async function loadLayouts(pathname) {
|
|
1753
|
+
const layoutPaths = getLayoutPaths(pathname);
|
|
1754
|
+
const layouts = [];
|
|
1755
|
+
for (const path of layoutPaths) {
|
|
1756
|
+
if (layoutCache.has(path)) {
|
|
1757
|
+
layouts.push(layoutCache.get(path));
|
|
1758
|
+
} else {
|
|
1759
|
+
try {
|
|
1760
|
+
const module = await import(/* @vite-ignore */ path);
|
|
1761
|
+
layoutCache.set(path, module.default);
|
|
1762
|
+
layouts.push(module.default);
|
|
1763
|
+
} catch (e) {
|
|
1764
|
+
// Layout might not exist for this segment, skip
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
return layouts;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// Router component
|
|
1772
|
+
function Router() {
|
|
1773
|
+
const [Page, setPage] = React.useState(null);
|
|
1774
|
+
const [layouts, setLayouts] = React.useState([]);
|
|
1775
|
+
const [path, setPath] = React.useState(window.location.pathname);
|
|
1776
|
+
|
|
1777
|
+
React.useEffect(() => {
|
|
1778
|
+
Promise.all([loadPage(path), loadLayouts(path)]).then(([P, L]) => {
|
|
1779
|
+
if (P) setPage(() => P);
|
|
1780
|
+
setLayouts(L);
|
|
1781
|
+
});
|
|
1782
|
+
}, []);
|
|
1783
|
+
|
|
1784
|
+
React.useEffect(() => {
|
|
1785
|
+
const handleNavigation = async () => {
|
|
1786
|
+
const newPath = window.location.pathname;
|
|
1787
|
+
if (newPath !== path) {
|
|
1788
|
+
setPath(newPath);
|
|
1789
|
+
const [P, L] = await Promise.all([loadPage(newPath), loadLayouts(newPath)]);
|
|
1790
|
+
if (P) setPage(() => P);
|
|
1791
|
+
setLayouts(L);
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
window.addEventListener('popstate', handleNavigation);
|
|
1795
|
+
return () => window.removeEventListener('popstate', handleNavigation);
|
|
1796
|
+
}, [path]);
|
|
1797
|
+
|
|
1798
|
+
if (!Page) return null;
|
|
1799
|
+
|
|
1800
|
+
// Build nested layout structure
|
|
1801
|
+
let content = React.createElement(Page);
|
|
1802
|
+
for (let i = layouts.length - 1; i >= 0; i--) {
|
|
1803
|
+
content = React.createElement(layouts[i], null, content);
|
|
1804
|
+
}
|
|
1805
|
+
return content;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
// Mark that we've initialized (for testing no-reload)
|
|
1809
|
+
window.__NEXT_INITIALIZED__ = Date.now();
|
|
1810
|
+
|
|
1682
1811
|
ReactDOM.createRoot(document.getElementById('__next')).render(
|
|
1683
|
-
React.createElement(React.StrictMode, null,
|
|
1684
|
-
React.createElement(App)
|
|
1685
|
-
)
|
|
1812
|
+
React.createElement(React.StrictMode, null, React.createElement(Router))
|
|
1686
1813
|
);
|
|
1687
1814
|
</script>
|
|
1688
1815
|
</body>
|