@wular/pnext 0.1.4 → 0.1.5
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/config/ts/react.json +2 -1
- package/package.json +1 -1
- package/reference/navigation.md +3 -1
- package/src/api/client-navigation.ts +53 -4
- package/src/api/link.tsx +6 -7
- package/src/cli/adapters/vercel-warm.ts +6 -1
- package/src/cli/adapters/vercel.ts +1 -1
- package/src/cli/build/cache.ts +8 -3
- package/src/cli/build.ts +3 -2
- package/src/cli/serve/pipeline.ts +11 -3
- package/src/cli/typegen.ts +65 -3
- package/src/client/build.ts +10 -7
- package/src/client/entry.ts +50 -29
- package/src/client/reference-stub.ts +1 -1
- package/src/client/router/hub.ts +13 -11
- package/src/client/router/page-slot.ts +58 -0
- package/src/client/router/runtime.ts +377 -388
- package/src/compat/bundler/symlink-imports.ts +1 -1
- package/src/compat/client/errors/bare-boundary.ts +1 -1
- package/src/compat/client/errors/error-boundary.ts +1 -1
- package/src/compat/client/errors/global-error.ts +40 -79
- package/src/compat/client/errors/install.ts +1 -1
- package/src/compat/client/errors/lazy.ts +7 -0
- package/src/compat/client/errors/primitive-throw.ts +36 -53
- package/src/compat/client/segment-cache-policy.ts +5 -22
- package/src/compat/client/segment-cache.ts +7 -26
- package/src/compat/css/modules.ts +1 -7
- package/src/compat/css/sass.ts +1 -7
- package/src/compat/react/parity.ts +1 -1
- package/src/compat/register/bundler.ts +9 -1
- package/src/compat/tsconfig-defaults.ts +4 -7
- package/src/compat-bootstrap.ts +15 -0
- package/src/css/build.ts +18 -15
- package/src/dev/server.ts +2 -2
- package/src/index.ts +2 -0
- package/src/render/renderer.ts +209 -24
- package/src/render/resource-hints.ts +4 -1
- package/src/resolve/imports.ts +13 -8
- package/src/routing/routes.ts +32 -18
- package/src/runtime/loader.ts +29 -10
- package/src/runtime/modules.ts +28 -7
- package/src/runtime/vendor-build.ts +2 -2
- package/src/types.ts +2 -0
- package/src/utils/fs.ts +122 -0
package/src/client/router/hub.ts
CHANGED
|
@@ -16,28 +16,30 @@ import type { EntryModule } from './types'
|
|
|
16
16
|
|
|
17
17
|
export const routerState: {
|
|
18
18
|
observedLocationKey: string
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
// The route key (pathname+search) of the currently committed navigation, used
|
|
20
|
+
// as the departing key on popstate (where `location` already points at the
|
|
21
|
+
// target). Seeded on router init and updated at each committed navigation.
|
|
22
|
+
activeRouteKey?: string
|
|
23
|
+
// The entry id whose document is currently on screen. A traversal to that
|
|
24
|
+
// same id — an app-level shallow pushState now carries the id forward — needs
|
|
25
|
+
// no fetch and no swap: the DOM already is this entry's.
|
|
26
|
+
renderedEntryId?: string
|
|
21
27
|
/** The navigation that last painted a fallback, and when. */
|
|
22
28
|
fallbackPaint?: [sequence: number, at: number]
|
|
29
|
+
/** Ends the clicked link's pending state; set once the runtime installs. */
|
|
30
|
+
settleLink?: () => void
|
|
23
31
|
} = {
|
|
24
32
|
// pathname+search of the URL the router last observed. A popstate that leaves both unchanged is a
|
|
25
33
|
// same-document FRAGMENT traversal - Chrome fires popstate, not just hashchange, for those - and
|
|
26
34
|
// treating one as a history traversal would refetch and swap the body, remounting the live tree
|
|
27
35
|
// under the user's feet.
|
|
28
36
|
observedLocationKey: locationKey(),
|
|
29
|
-
// The route key (pathname+search) of the currently committed navigation, used
|
|
30
|
-
// as the departing key on popstate (where `location` already points at the
|
|
31
|
-
// target). Seeded on router init and updated at each committed navigation.
|
|
32
|
-
activeRouteKey: undefined as string | undefined,
|
|
33
|
-
// The entry id whose document is currently on screen. A traversal to that
|
|
34
|
-
// same id — an app-level shallow pushState now carries the id forward — needs
|
|
35
|
-
// no fetch and no swap: the DOM already is this entry's.
|
|
36
|
-
renderedEntryId: undefined as string | undefined,
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function locationKey() {
|
|
40
|
-
return typeof location
|
|
40
|
+
return process.browser || typeof location !== 'undefined'
|
|
41
|
+
? location.pathname + location.search
|
|
42
|
+
: ''
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
// Installers that only the navigation runtime ever observes — compat's policy
|
|
@@ -27,6 +27,64 @@ export function elementInPageSlot(element: Element): boolean {
|
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
const SEGMENT = 'pnext-layout[data-pnext-segment]'
|
|
31
|
+
|
|
32
|
+
/** A server layout's identity and the URL prefix it rendered for. */
|
|
33
|
+
export function segmentKey(segment: Element): string {
|
|
34
|
+
return `${segment.getAttribute('data-pnext-segment')}\u0001${segment.getAttribute('data-pnext-scope')}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The server layout directly below `segment`, outside parallel-route slots. */
|
|
38
|
+
export function childSegment(segment: Element): Element | null {
|
|
39
|
+
for (const child of segment.querySelectorAll(SEGMENT))
|
|
40
|
+
if (!segment.contains(child.closest('[data-pnext-slot]'))) return child
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The live layout below the deepest layout `boundary` shares with `slot` (null when that layout
|
|
46
|
+
* holds `slot`), and the incoming node that replaces it: the boundary, or the new layout holding
|
|
47
|
+
* it. Null when either sits in an island.
|
|
48
|
+
*/
|
|
49
|
+
export function divergingLayout(slot: Node, boundary: Element): [Element | null, Element] | null {
|
|
50
|
+
let paint = boundary
|
|
51
|
+
let owner = boundary.closest(SEGMENT)
|
|
52
|
+
let below: Element | null
|
|
53
|
+
for (;;) {
|
|
54
|
+
const key = owner && segmentKey(owner)
|
|
55
|
+
below = null
|
|
56
|
+
let layout = slot.parentElement?.closest(SEGMENT)
|
|
57
|
+
for (; layout && segmentKey(layout) !== key; layout = layout.parentElement?.closest(SEGMENT))
|
|
58
|
+
below = layout
|
|
59
|
+
if (layout || !owner) break
|
|
60
|
+
paint = owner
|
|
61
|
+
owner = owner.parentElement!.closest(SEGMENT)
|
|
62
|
+
}
|
|
63
|
+
return !boundary.closest('pnext-client') &&
|
|
64
|
+
!(below ?? slot).parentElement?.closest('pnext-client')
|
|
65
|
+
? [below, paint]
|
|
66
|
+
: null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function childNodes(segment: Element): ChildNode[] | null {
|
|
70
|
+
const child = childSegment(segment)
|
|
71
|
+
if (child) return [child]
|
|
72
|
+
const range = pageSlotRange(segment)
|
|
73
|
+
return range && (range[1] ? [range[0], ...range[2], range[1]] : [range[0]])
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Replace a kept layout's children (its child layout or page slot) with the incoming ones. */
|
|
77
|
+
export function graftSegmentChildren(liveSegment: Element, incomingSegment: Element): boolean {
|
|
78
|
+
if (!childSegment(liveSegment) && !childSegment(incomingSegment))
|
|
79
|
+
return graftPageSlot(liveSegment, incomingSegment)
|
|
80
|
+
const live = childNodes(liveSegment)
|
|
81
|
+
const incoming = childNodes(incomingSegment)
|
|
82
|
+
if (!live || !incoming) return false
|
|
83
|
+
live[0]!.before(...incoming)
|
|
84
|
+
for (const stale of live) stale.remove()
|
|
85
|
+
return true
|
|
86
|
+
}
|
|
87
|
+
|
|
30
88
|
/**
|
|
31
89
|
* Graft a destination page into a preserved layout without changing the destination's mount shape.
|
|
32
90
|
* Client pages need the real `#pnext-page` element; server/island-only pages need the marker range.
|