Skip to content
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
dfd3fae
apply patch correctly for last segment
feedthejim Mar 22, 2023
739a584
re-render layout on parallel key change
feedthejim Mar 22, 2023
a51b1db
refactor for readability
feedthejim Mar 22, 2023
b120b12
implement parallel routes default
feedthejim Mar 23, 2023
a79fe3f
remove useless check
feedthejim Mar 23, 2023
452770a
remove leftover fn
feedthejim Mar 23, 2023
98f6eb2
enable tests in dev
feedthejim Mar 23, 2023
8829681
fix test + small refactor
feedthejim Mar 23, 2023
c6326ca
fix test
feedthejim Mar 23, 2023
59b3634
support @children
feedthejim Mar 24, 2023
6abf5fa
re-enable test for build
feedthejim Mar 24, 2023
3084422
fix adjacent child check for directory only
feedthejim Mar 24, 2023
47a6f00
Merge branch 'canary' into feedthejim/next-748-verify-partial-renderi…
feedthejim Mar 24, 2023
1192d34
fix lint
feedthejim Mar 24, 2023
9ade248
initial implementation
feedthejim Mar 25, 2023
64284d8
refactors
feedthejim Mar 26, 2023
4900fa2
fix hmr
feedthejim Mar 27, 2023
9b83aef
change referrer computation method
feedthejim Mar 27, 2023
92cbf42
add segment tree override
feedthejim Mar 27, 2023
999b516
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 27, 2023
b8bde07
fix types
feedthejim Mar 27, 2023
0fde8ff
fix test
feedthejim Mar 27, 2023
02d037b
update tests
feedthejim Mar 27, 2023
be9e620
rewrite tests
feedthejim Mar 27, 2023
8fdb943
remove logs
feedthejim Mar 27, 2023
94d4a59
add unit test for referrer parsing
feedthejim Mar 27, 2023
9fc9bc9
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 27, 2023
45b1a43
remove log
feedthejim Mar 27, 2023
acb3b29
update comments
feedthejim Mar 27, 2023
d097f9f
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 27, 2023
92237b9
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 27, 2023
09c6ce6
refactor: provide more consistent interface for matchers with pathnam…
wyattjoh Mar 27, 2023
ce365a9
refactor: formatting updates
wyattjoh Mar 27, 2023
be0c36c
fix: added key prop's to test files
wyattjoh Mar 28, 2023
b2ac7dc
fix: corrected invalid slot name
wyattjoh Mar 28, 2023
853f9fd
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 28, 2023
eac2b2d
address comments
feedthejim Mar 28, 2023
6783565
fix windows test
feedthejim Mar 28, 2023
6001b80
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 28, 2023
a1f00be
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 28, 2023
d615593
use check for tests
feedthejim Mar 28, 2023
d66a842
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 28, 2023
f6ab0f7
fix tests failures
feedthejim Mar 28, 2023
76c9726
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 28, 2023
61cd219
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 29, 2023
58d247d
restire test position
feedthejim Mar 28, 2023
ceaa38f
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 31, 2023
1496087
update injection method
feedthejim Mar 31, 2023
9b168df
make sure we patch the tree if the previous page was a __DEFAULT__
feedthejim Mar 31, 2023
148f04f
pass the previous cache node when populating the cache tree
feedthejim Mar 31, 2023
08cdb07
add a fast refresh reducer
feedthejim Mar 31, 2023
ab4533f
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Mar 31, 2023
f7041fe
remove misc change
feedthejim Mar 31, 2023
1512bc8
Merge branch 'canary' into feedthejim/next-749-implement-route-interc…
feedthejim Apr 3, 2023
266c003
pass the existing cache node nonethelesss
feedthejim Apr 3, 2023
c4589bf
skip __DEFAULT__ item when applying fligth data to the cache
feedthejim Apr 3, 2023
5e4abc0
don't overwrite cache node if already ready
feedthejim Apr 3, 2023
6ce7349
add 404 by default for parallel routes
feedthejim Apr 3, 2023
b59a53d
Merge branch 'canary' into feedthejim/next-918-make-default-pagets-404
feedthejim Apr 4, 2023
4a369f8
Merge branch 'canary' into feedthejim/next-918-make-default-pagets-404
feedthejim Apr 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/next/src/client/components/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
import type { ErrorComponent } from './error-boundary'
import { reducer } from './router-reducer/router-reducer'
import {
ACTION_FAST_REFRESH,
ACTION_NAVIGATE,
ACTION_PREFETCH,
ACTION_REFRESH,
Expand Down Expand Up @@ -237,6 +238,29 @@ function Router({
})
})
},
// @ts-ignore we don't want to expose this method at all
fastRefresh: () => {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'fastRefresh can only be used in development mode. Please use refresh instead.'
)
} else {
// @ts-ignore startTransition exists
React.startTransition(() => {
dispatch({
type: ACTION_FAST_REFRESH,
cache: {
status: CacheStates.LAZY_INITIALIZED,
data: null,
subTreeData: null,
parallelRoutes: new Map(),
},
mutable: {},
origin: window.location.origin,
})
})
}
},
}

return routerInstance
Expand Down
9 changes: 5 additions & 4 deletions packages/next/src/client/components/layout-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,12 @@ function InnerLayoutRouter({
// TODO-APP: verify if this can be null based on user code
childProp.current !== null
) {
if (childNode && childNode.status === CacheStates.LAZY_INITIALIZED) {
// @ts-expect-error TODO-APP: handle changing of the type
if (
childNode &&
(childNode.status === CacheStates.LAZY_INITIALIZED ||
childNode.status === CacheStates.READY)
) {
childNode.status = CacheStates.READY
// @ts-expect-error TODO-APP: handle changing of the type
childNode.subTreeData = childProp.current
// Mutates the prop in order to clean up the memory associated with the subTreeData as it is now part of the cache.
childProp.current = null
Expand Down Expand Up @@ -365,7 +367,6 @@ function InnerLayoutRouter({
{childNode.subTreeData}
</LayoutRouterContext.Provider>
)

// Ensure root layout is not wrapped in a div as the root layout renders `<html>`
return (
<ScrollAndFocusHandler focusAndScrollRef={focusAndScrollRef}>
Expand Down
15 changes: 15 additions & 0 deletions packages/next/src/client/components/match-segments.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getSegmentParam } from '../../server/app-render/get-segment-param'
import type { Segment } from '../../server/app-render/types'

export const matchSegment = (
Expand All @@ -18,3 +19,17 @@ export const matchSegment = (

return false
}

/*
* This function is used to determine if an existing segment can be overridden by the incoming segment.
*/
export const canSegmentBeOverridden = (
existingSegment: Segment,
segment: Segment
): boolean => {
if (Array.isArray(existingSegment) || !Array.isArray(segment)) {
return false
}

return getSegmentParam(existingSegment)?.param === segment[0]
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { notFound } from './not-found'

export default function NoopParallelRouteDefault() {
return null
notFound()
}
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ function processMessage(
return window.location.reload()
}
startTransition(() => {
router.refresh()
// @ts-ignore it exists, it's just hidden
router.fastRefresh()
dispatcher.onRefresh()
})

Expand All @@ -378,20 +379,23 @@ function processMessage(
}
case 'removedPage': {
// TODO-APP: potentially only refresh if the currently viewed page was removed.
router.refresh()
// @ts-ignore it exists, it's just hidden
router.fastRefresh()
return
}
case 'addedPage': {
// TODO-APP: potentially only refresh if the currently viewed page was added.
router.refresh()
// @ts-ignore it exists, it's just hidden
router.fastRefresh()
return
}
case 'pong': {
const { invalid } = obj
if (invalid) {
// Payload can be invalid even if the page does exist.
// So, we check if it can be created.
router.refresh()
// @ts-ignore it exists, it's just hidden
router.fastRefresh()
}
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function applyPatch(

// if the applied patch segment is __DEFAULT__ then we can ignore it and return the initial tree
// this is because the __DEFAULT__ segment is used as a placeholder on navigation
if (patchSegment === '__DEFAULT__') {
if (patchSegment === '__DEFAULT__' && initialSegment !== '__DEFAULT__') {
return initialTree
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export function fillLazyItemsTillLeafWithHead(
: segmentForParallelRoute

if (existingCache) {
if (cacheKey === '__DEFAULT__') {
continue
}
const existingParallelRoutesCacheNode =
existingCache.parallelRoutes.get(key)
if (existingParallelRoutesCacheNode) {
Expand All @@ -46,7 +49,7 @@ export function fillLazyItemsTillLeafWithHead(
// Traverse deeper to apply the head / fill lazy items till the head.
fillLazyItemsTillLeafWithHead(
newCacheNode,
wasPrefetched ? existingCacheNode : undefined,
existingCacheNode,
parallelRouteState,
head,
wasPrefetched
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { fetchServerResponse } from '../fetch-server-response'
import { createRecordFromThenable } from '../create-record-from-thenable'
import { readRecordValue } from '../read-record-value'
import { createHrefFromUrl } from '../create-href-from-url'
import { applyRouterStatePatchToTree } from '../apply-router-state-patch-to-tree'
import { isNavigatingToNewRootLayout } from '../is-navigating-to-new-root-layout'
import {
ReadonlyReducerState,
ReducerState,
FastRefreshAction,
} from '../router-reducer-types'
import { handleExternalUrl } from './navigate-reducer'
import { handleMutable } from '../handle-mutable'
import { applyFlightData } from '../apply-flight-data'

// A version of refresh reducer that keeps the cache around instead of wiping all of it.
function fastRefreshReducerImpl(
state: ReadonlyReducerState,
action: FastRefreshAction
): ReducerState {
const { cache, mutable, origin } = action
const href = state.canonicalUrl

const isForCurrentTree =
JSON.stringify(mutable.previousTree) === JSON.stringify(state.tree)

if (isForCurrentTree) {
return handleMutable(state, mutable)
}

if (!cache.data) {
// TODO-APP: verify that `href` is not an external url.
// Fetch data from the root of the tree.
cache.data = createRecordFromThenable(
fetchServerResponse(new URL(href, origin), [
state.tree[0],
state.tree[1],
state.tree[2],
'refetch',
])
)
}
const [flightData, canonicalUrlOverride] = readRecordValue(cache.data!)

// Handle case when navigating to page in `pages` from `app`
if (typeof flightData === 'string') {
return handleExternalUrl(
state,
mutable,
flightData,
state.pushRef.pendingPush
)
}

// Remove cache.data as it has been resolved at this point.
cache.data = null

// TODO-APP: Currently the Flight data can only have one item but in the future it can have multiple paths.
const flightDataPath = flightData[0]

// FlightDataPath with more than two items means unexpected Flight data was returned
if (flightDataPath.length !== 3) {
// TODO-APP: handle this case better
console.log('REFRESH FAILED')
return state
}

// Given the path can only have two items the items are only the router state and subTreeData for the root.
const [treePatch] = flightDataPath
const newTree = applyRouterStatePatchToTree(
// TODO-APP: remove ''
[''],
state.tree,
treePatch
)

if (newTree === null) {
throw new Error('SEGMENT MISMATCH')
}

if (isNavigatingToNewRootLayout(state.tree, newTree)) {
return handleExternalUrl(state, mutable, href, state.pushRef.pendingPush)
}

const canonicalUrlOverrideHref = canonicalUrlOverride
? createHrefFromUrl(canonicalUrlOverride)
: undefined

if (canonicalUrlOverride) {
mutable.canonicalUrl = canonicalUrlOverrideHref
}
const applied = applyFlightData(state, cache, flightDataPath)

if (applied) {
mutable.cache = cache
}

mutable.previousTree = state.tree
mutable.patchedTree = newTree
mutable.canonicalUrl = href

return handleMutable(state, mutable)
}

function fastRefreshReducerNoop(
state: ReadonlyReducerState,
_action: FastRefreshAction
): ReducerState {
return state
}

export const fastRefreshReducer =
process.env.NODE_ENV === 'production'
? fastRefreshReducerNoop
: fastRefreshReducerImpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const ACTION_NAVIGATE = 'navigate'
export const ACTION_RESTORE = 'restore'
export const ACTION_SERVER_PATCH = 'server-patch'
export const ACTION_PREFETCH = 'prefetch'
export const ACTION_FAST_REFRESH = 'fast-refresh'

export interface Mutable {
mpaNavigation?: boolean
Expand All @@ -35,6 +36,13 @@ export interface RefreshAction {
origin: Location['origin']
}

export interface FastRefreshAction {
type: typeof ACTION_FAST_REFRESH
cache: CacheNode
mutable: Mutable
origin: Location['origin']
}

/**
* Navigate triggers a navigation to the provided url. It supports two types: `push` and `replace`.
*
Expand Down Expand Up @@ -190,4 +198,5 @@ export type ReducerActions = Readonly<
| RestoreAction
| ServerPatchAction
| PrefetchAction
| FastRefreshAction
>
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import {
ReducerActions,
ReducerState,
ReadonlyReducerState,
ACTION_FAST_REFRESH,
} from './router-reducer-types'
import { navigateReducer } from './reducers/navigate-reducer'
import { serverPatchReducer } from './reducers/server-patch-reducer'
import { restoreReducer } from './reducers/restore-reducer'
import { refreshReducer } from './reducers/refresh-reducer'
import { prefetchReducer } from './reducers/prefetch-reducer'
import { fastRefreshReducer } from './reducers/fast-refresh-reducer'

/**
* Reducer that handles the app-router state updates.
Expand All @@ -34,6 +36,9 @@ function clientReducer(
case ACTION_REFRESH: {
return refreshReducer(state, action)
}
case ACTION_FAST_REFRESH: {
return fastRefreshReducer(state, action)
}
case ACTION_PREFETCH: {
return prefetchReducer(state, action)
}
Expand Down
Loading