@timber-js/app 0.1.29 → 0.1.30
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/client/index.js +128 -124
- package/dist/client/index.js.map +1 -1
- package/dist/client/link-status-provider.d.ts +10 -4
- package/dist/client/link-status-provider.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +8 -0
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/use-navigation-pending.d.ts.map +1 -1
- package/dist/index.js +120 -7
- package/dist/index.js.map +1 -1
- package/dist/plugins/chunks.d.ts +17 -6
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client/browser-entry.ts +3 -0
- package/src/client/link-status-provider.tsx +18 -24
- package/src/client/navigation-context.ts +9 -1
- package/src/client/router.ts +23 -4
- package/src/client/use-navigation-pending.ts +10 -17
- package/src/plugins/chunks.ts +145 -17
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as setViteServer, t as formatSize } from "./_chunks/format-DNt20Kt8.js";
|
|
2
2
|
import { i as scanRoutes, n as generateRouteMap, t as collectInterceptionRewrites } from "./_chunks/interception-DGDIjDbR.js";
|
|
3
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { dirname, extname, join, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
@@ -12748,7 +12748,8 @@ function detectDynamicFontCallAst(source, importedNames) {
|
|
|
12748
12748
|
} catch {
|
|
12749
12749
|
return null;
|
|
12750
12750
|
}
|
|
12751
|
-
|
|
12751
|
+
const nameSet = new Set(importedNames);
|
|
12752
|
+
return walkForDynamicCalls(ast, nameSet, source);
|
|
12752
12753
|
}
|
|
12753
12754
|
/**
|
|
12754
12755
|
* Recursively walk the AST looking for CallExpression nodes where
|
|
@@ -14067,14 +14068,119 @@ function timberReactProd() {
|
|
|
14067
14068
|
//#endregion
|
|
14068
14069
|
//#region src/plugins/chunks.ts
|
|
14069
14070
|
/**
|
|
14071
|
+
* timber-chunks — Vite sub-plugin for intelligent client chunk splitting.
|
|
14072
|
+
*
|
|
14073
|
+
* Splits client bundles into cache tiers based on update frequency:
|
|
14074
|
+
*
|
|
14075
|
+
* Tier 1: vendor-react — react, react-dom, scheduler (changes rarely)
|
|
14076
|
+
* Tier 2: vendor-timber — timber runtime, RSC runtime (changes per framework update)
|
|
14077
|
+
* Tier 3: vendor-app — user node_modules (changes on dependency updates)
|
|
14078
|
+
* Tier 4: shared-app — small shared app utilities/components (< 5KB source)
|
|
14079
|
+
* Tier 5: [route]-* — per-route page/layout chunks (default Rollup splitting)
|
|
14080
|
+
*
|
|
14081
|
+
* The shared-app tier prevents tiny utility modules (constants, helpers,
|
|
14082
|
+
* small UI components) from becoming individual chunks when shared across
|
|
14083
|
+
* routes. Without this, Rolldown creates per-module chunks for any code
|
|
14084
|
+
* shared between two or more entry points, producing many sub-1KB chunks.
|
|
14085
|
+
*
|
|
14086
|
+
* Server environments (RSC, SSR) are left to Vite's default chunking since
|
|
14087
|
+
* Cloudflare Workers load all code from a single deployment bundle with no
|
|
14088
|
+
* benefit from cache-tier separation.
|
|
14089
|
+
*
|
|
14090
|
+
* Design docs: 27-chunking-strategy.md
|
|
14091
|
+
*/
|
|
14092
|
+
/**
|
|
14093
|
+
* Source file size threshold for the shared-app chunk.
|
|
14094
|
+
* Modules under this size that aren't route files get merged into shared-app
|
|
14095
|
+
* instead of getting their own tiny chunks.
|
|
14096
|
+
*/
|
|
14097
|
+
var SMALL_MODULE_THRESHOLD = 5 * 1024;
|
|
14098
|
+
/**
|
|
14099
|
+
* Route convention file basenames (without extension).
|
|
14100
|
+
* These files define route segments and must stay in per-route chunks
|
|
14101
|
+
* to preserve route-based code splitting.
|
|
14102
|
+
*/
|
|
14103
|
+
var ROUTE_FILE_BASENAMES = new Set([
|
|
14104
|
+
"page",
|
|
14105
|
+
"layout",
|
|
14106
|
+
"loading",
|
|
14107
|
+
"error",
|
|
14108
|
+
"not-found",
|
|
14109
|
+
"template",
|
|
14110
|
+
"access",
|
|
14111
|
+
"middleware",
|
|
14112
|
+
"default",
|
|
14113
|
+
"route"
|
|
14114
|
+
]);
|
|
14115
|
+
/**
|
|
14116
|
+
* Cache for source file sizes to avoid repeated statSync calls.
|
|
14117
|
+
* Populated lazily during the build.
|
|
14118
|
+
*/
|
|
14119
|
+
var sizeCache = /* @__PURE__ */ new Map();
|
|
14120
|
+
/**
|
|
14121
|
+
* Get the source file size, with caching.
|
|
14122
|
+
* Returns Infinity for virtual modules or files that can't be stat'd.
|
|
14123
|
+
*/
|
|
14124
|
+
function getSourceSize(id) {
|
|
14125
|
+
const cached = sizeCache.get(id);
|
|
14126
|
+
if (cached !== void 0) return cached;
|
|
14127
|
+
try {
|
|
14128
|
+
const size = statSync(id).size;
|
|
14129
|
+
sizeCache.set(id, size);
|
|
14130
|
+
return size;
|
|
14131
|
+
} catch {
|
|
14132
|
+
sizeCache.set(id, Infinity);
|
|
14133
|
+
return Infinity;
|
|
14134
|
+
}
|
|
14135
|
+
}
|
|
14136
|
+
/**
|
|
14137
|
+
* Extract the basename without extension from a module ID.
|
|
14138
|
+
* e.g. '/project/app/dashboard/page.tsx' → 'page'
|
|
14139
|
+
*/
|
|
14140
|
+
function getBasename(id) {
|
|
14141
|
+
const lastSlash = id.lastIndexOf("/");
|
|
14142
|
+
const filename = lastSlash >= 0 ? id.substring(lastSlash + 1) : id;
|
|
14143
|
+
const dotIndex = filename.indexOf(".");
|
|
14144
|
+
return dotIndex >= 0 ? filename.substring(0, dotIndex) : filename;
|
|
14145
|
+
}
|
|
14146
|
+
/**
|
|
14147
|
+
* Check if a module is a React ecosystem package (tier 1).
|
|
14148
|
+
*/
|
|
14149
|
+
function isReactVendor(id) {
|
|
14150
|
+
return id.includes("node_modules/react-dom") || id.includes("node_modules/react/") || id.includes("node_modules/scheduler");
|
|
14151
|
+
}
|
|
14152
|
+
/**
|
|
14153
|
+
* Check if a module is part of the timber framework runtime (tier 2).
|
|
14154
|
+
*/
|
|
14155
|
+
function isTimberRuntime(id) {
|
|
14156
|
+
return id.includes("/timber-app/") || id.includes("react-server-dom") || id.includes("@vitejs/plugin-rsc");
|
|
14157
|
+
}
|
|
14158
|
+
/**
|
|
14159
|
+
* Check if a module is a user-installed node_modules dependency (tier 3).
|
|
14160
|
+
* Excludes React ecosystem and timber runtime packages which have their own tiers.
|
|
14161
|
+
*/
|
|
14162
|
+
function isUserVendor(id) {
|
|
14163
|
+
return id.includes("node_modules/") && !isReactVendor(id) && !isTimberRuntime(id);
|
|
14164
|
+
}
|
|
14165
|
+
/**
|
|
14166
|
+
* Check if a module is a route convention file that should stay per-route.
|
|
14167
|
+
*/
|
|
14168
|
+
function isRouteFile(id) {
|
|
14169
|
+
return ROUTE_FILE_BASENAMES.has(getBasename(id));
|
|
14170
|
+
}
|
|
14171
|
+
/**
|
|
14070
14172
|
* Categorize a module ID into a cache tier chunk name.
|
|
14071
14173
|
*
|
|
14072
|
-
* Returns a chunk name for vendor modules
|
|
14073
|
-
* Rollup's default splitting handle
|
|
14174
|
+
* Returns a chunk name for vendor modules and small shared app code,
|
|
14175
|
+
* or undefined to let Rollup's default splitting handle route code.
|
|
14074
14176
|
*/
|
|
14075
14177
|
function assignChunk(id) {
|
|
14076
|
-
if (
|
|
14077
|
-
if (
|
|
14178
|
+
if (isReactVendor(id)) return "vendor-react";
|
|
14179
|
+
if (isTimberRuntime(id)) return "vendor-timber";
|
|
14180
|
+
if (isUserVendor(id)) return "vendor-app";
|
|
14181
|
+
if (!id.includes("\0") && id.startsWith("/") && !isRouteFile(id)) {
|
|
14182
|
+
if (getSourceSize(id) < SMALL_MODULE_THRESHOLD) return "shared-app";
|
|
14183
|
+
}
|
|
14078
14184
|
}
|
|
14079
14185
|
/**
|
|
14080
14186
|
* Group timber's internal 'use client' modules into the vendor-timber chunk.
|
|
@@ -14082,10 +14188,17 @@ function assignChunk(id) {
|
|
|
14082
14188
|
* The RSC plugin creates separate entry points for each 'use client' module,
|
|
14083
14189
|
* which manualChunks can't merge. This function is passed as the RSC plugin's
|
|
14084
14190
|
* `clientChunks` callback to group timber internals into a single chunk.
|
|
14085
|
-
*
|
|
14191
|
+
*
|
|
14192
|
+
* User client components that are small (< 5KB) are grouped into shared-client
|
|
14193
|
+
* to prevent thin facade wrappers from becoming individual chunks. This handles
|
|
14194
|
+
* the RSC client reference facade problem where each 'use client' module gets
|
|
14195
|
+
* a ~100-300 byte re-export wrapper chunk.
|
|
14086
14196
|
*/
|
|
14087
14197
|
function assignClientChunk(meta) {
|
|
14088
14198
|
if (meta.id.includes("/timber-app/")) return "vendor-timber";
|
|
14199
|
+
if (!meta.id.includes("\0") && meta.id.startsWith("/")) {
|
|
14200
|
+
if (getSourceSize(meta.id) < SMALL_MODULE_THRESHOLD) return "shared-client";
|
|
14201
|
+
}
|
|
14089
14202
|
}
|
|
14090
14203
|
/**
|
|
14091
14204
|
* Create the timber-chunks Vite plugin.
|