Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
CoCo_Code_Op2
next.js
提交
83334f11
N
next.js
项目概览
CoCo_Code_Op2
/
next.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
N
next.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
83334f11
编写于
3月 14, 2019
作者:
T
Tim Neutkens
提交者:
GitHub
3月 14, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Convert change/getRouteInfo to not use async (#6648)
More updates to the router coming.
上级
1c31d79c
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
134 addition
and
143 deletion
+134
-143
packages/next-server/lib/router/router.ts
packages/next-server/lib/router/router.ts
+134
-143
未找到文件。
packages/next-server/lib/router/router.ts
浏览文件 @
83334f11
...
...
@@ -35,7 +35,7 @@ export default class Router implements IRouterInterface {
subscriptions
:
Set
<
Subscription
>
componentLoadCancel
:
(()
=>
void
)
|
null
pageLoader
:
any
_b
eforePopState
:
BeforePopStateCallback
_b
ps
:
BeforePopStateCallback
|
undefined
static
events
:
MittEmitter
=
mitt
()
...
...
@@ -65,7 +65,6 @@ export default class Router implements IRouterInterface {
this
.
asPath
=
as
this
.
subscriptions
=
new
Set
()
this
.
componentLoadCancel
=
null
this
.
_beforePopState
=
()
=>
true
if
(
typeof
window
!==
'
undefined
'
)
{
// in order for `e.state` to work on the `onpopstate` event
...
...
@@ -86,31 +85,19 @@ export default class Router implements IRouterInterface {
}
}
static
_rewriteUrlForNextExport
(
url
:
string
)
{
const
[,
hash
]
=
url
.
split
(
'
#
'
)
url
=
url
.
replace
(
/#.*/
,
''
)
static
_rewriteUrlForNextExport
(
url
:
string
):
string
{
const
[
pathname
,
hash
]
=
url
.
split
(
'
#
'
)
// tslint:disable-next-line
let
[
path
,
qs
]
=
url
.
split
(
'
?
'
)
let
[
path
,
qs
]
=
pathname
.
split
(
'
?
'
)
path
=
path
.
replace
(
/
\/
$/
,
''
)
let
newPath
=
path
// Append a trailing slash if this path does not have an extension
if
(
!
/
\.[^/]
+
\/?
$/
.
test
(
path
))
{
newPath
=
`
${
path
}
/`
}
if
(
qs
)
{
newPath
=
`
${
newPath
}
?
${
qs
}
`
}
if
(
hash
)
{
newPath
=
`
${
newPath
}
#
${
hash
}
`
}
return
newPath
if
(
!
/
\.[^/]
+
\/?
$/
.
test
(
path
))
path
+=
`/`
if
(
qs
)
path
+=
'
?
'
+
qs
if
(
hash
)
path
+=
'
#
'
+
hash
return
path
}
onPopState
=
(
e
:
PopStateEvent
)
=>
{
onPopState
=
(
e
:
PopStateEvent
)
:
void
=>
{
if
(
!
e
.
state
)
{
// We get state as undefined for two reasons.
// 1. With older safari (< 8) and older chrome (< 34)
...
...
@@ -128,7 +115,7 @@ export default class Router implements IRouterInterface {
// If the downstream application returns falsy, return.
// They will then be responsible for handling the event.
if
(
!
this
.
_beforePopState
(
e
.
state
))
{
if
(
this
.
_bps
&&
!
this
.
_bps
(
e
.
state
))
{
return
}
...
...
@@ -209,79 +196,74 @@ export default class Router implements IRouterInterface {
return
this
.
change
(
'
replaceState
'
,
url
,
as
,
options
)
}
async
change
(
method
:
string
,
_url
:
string
,
_as
:
string
,
options
:
any
)
{
// If url and as provided as an object representation,
// we'll format them into the string version here.
const
url
=
typeof
_url
===
'
object
'
?
formatWithValidation
(
_url
)
:
_url
let
as
=
typeof
_as
===
'
object
'
?
formatWithValidation
(
_as
)
:
_as
// Add the ending slash to the paths. So, we can serve the
// "<page>/index.html" directly for the SSR page.
// @ts-ignore this is temporarily global (attached to window)
if
(
__NEXT_DATA__
.
nextExport
)
{
as
=
Router
.
_rewriteUrlForNextExport
(
as
)
}
change
(
method
:
string
,
_url
:
string
,
_as
:
string
,
options
:
any
):
Promise
<
boolean
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
// If url and as provided as an object representation,
// we'll format them into the string version here.
const
url
=
typeof
_url
===
'
object
'
?
formatWithValidation
(
_url
)
:
_url
let
as
=
typeof
_as
===
'
object
'
?
formatWithValidation
(
_as
)
:
_as
// Add the ending slash to the paths. So, we can serve the
// "<page>/index.html" directly for the SSR page.
// @ts-ignore this is temporarily global (attached to window)
if
(
__NEXT_DATA__
.
nextExport
)
{
as
=
Router
.
_rewriteUrlForNextExport
(
as
)
}
this
.
abortComponentLoad
(
as
)
this
.
abortComponentLoad
(
as
)
// If the url change is only related to a hash change
// We should not proceed. We should only change the state.
if
(
this
.
onlyAHashChange
(
as
))
{
Router
.
events
.
emit
(
'
hashChangeStart
'
,
as
)
this
.
changeState
(
method
,
url
,
as
)
this
.
scrollToHash
(
as
)
Router
.
events
.
emit
(
'
hashChangeComplete
'
,
as
)
return
true
}
// If the url change is only related to a hash change
// We should not proceed. We should only change the state.
if
(
this
.
onlyAHashChange
(
as
))
{
Router
.
events
.
emit
(
'
hashChangeStart
'
,
as
)
this
.
changeState
(
method
,
url
,
as
)
this
.
scrollToHash
(
as
)
Router
.
events
.
emit
(
'
hashChangeComplete
'
,
as
)
return
true
}
const
{
pathname
,
query
}
=
parse
(
url
,
true
)
const
{
pathname
,
query
}
=
parse
(
url
,
true
)
// If asked to change the current URL we should reload the current page
// (not location.reload() but reload getInitialProps and other Next.js stuffs)
// We also need to set the method = replaceState always
// as this should not go into the history (That's how browsers work)
// We should compare the new asPath to the current asPath, not the url
if
(
!
this
.
urlIsNew
(
as
))
{
method
=
'
replaceState
'
}
// If asked to change the current URL we should reload the current page
// (not location.reload() but reload getInitialProps and other Next.js stuffs)
// We also need to set the method = replaceState always
// as this should not go into the history (That's how browsers work)
// We should compare the new asPath to the current asPath, not the url
if
(
!
this
.
urlIsNew
(
as
))
{
method
=
'
replaceState
'
}
// @ts-ignore pathname is always a string
const
route
=
toRoute
(
pathname
)
const
{
shallow
=
false
}
=
options
let
routeInfo
=
null
// @ts-ignore pathname is always a string
const
route
=
toRoute
(
pathname
)
const
{
shallow
=
false
}
=
options
Router
.
events
.
emit
(
'
routeChangeStart
'
,
as
)
Router
.
events
.
emit
(
'
routeChangeStart
'
,
as
)
// If shallow === false and other conditions met, we reuse the
// existing routeInfo for this route.
// Because of this, getInitialProps would not run.
if
(
shallow
&&
this
.
isShallowRoutingPossible
(
route
))
{
routeInfo
=
this
.
components
[
route
]
}
else
{
// If shallow is true and the route exists in the router cache we reuse the previous result
// @ts-ignore pathname is always a string
routeInfo
=
await
this
.
getRouteInfo
(
route
,
pathname
,
query
,
as
)
}
const
{
error
}
=
routeInfo
this
.
getRouteInfo
(
route
,
pathname
,
query
,
as
,
shallow
).
then
((
routeInfo
)
=>
{
const
{
error
}
=
routeInfo
if
(
error
&&
error
.
cancelled
)
{
return
false
}
if
(
error
&&
error
.
cancelled
)
{
return
resolve
(
false
)
}
Router
.
events
.
emit
(
'
beforeHistoryChange
'
,
as
)
this
.
changeState
(
method
,
url
,
as
,
options
)
const
hash
=
window
.
location
.
hash
.
substring
(
1
)
Router
.
events
.
emit
(
'
beforeHistoryChange
'
,
as
)
this
.
changeState
(
method
,
url
,
as
,
options
)
const
hash
=
window
.
location
.
hash
.
substring
(
1
)
// @ts-ignore pathname is always defined
this
.
set
(
route
,
pathname
,
query
,
as
,
{
...
routeInfo
,
hash
})
// @ts-ignore pathname is always defined
this
.
set
(
route
,
pathname
,
query
,
as
,
{
...
routeInfo
,
hash
})
if
(
error
)
{
Router
.
events
.
emit
(
'
routeChangeError
'
,
error
,
as
)
throw
error
}
if
(
error
)
{
Router
.
events
.
emit
(
'
routeChangeError
'
,
error
,
as
)
throw
error
}
Router
.
events
.
emit
(
'
routeChangeComplete
'
,
as
)
return
true
Router
.
events
.
emit
(
'
routeChangeComplete
'
,
as
)
return
resolve
(
true
)
},
reject
)
})
}
changeState
(
method
:
string
,
url
:
string
,
as
:
string
,
options
=
{}):
void
{
...
...
@@ -303,13 +285,22 @@ export default class Router implements IRouterInterface {
}
}
async
getRouteInfo
(
route
:
string
,
pathname
:
string
,
query
:
any
,
as
:
string
):
Promise
<
RouteInfo
>
{
try
{
let
routeInfo
=
this
.
components
[
route
]
if
(
!
routeInfo
)
{
routeInfo
=
{
Component
:
await
this
.
fetchComponent
(
route
)
}
getRouteInfo
(
route
:
string
,
pathname
:
string
,
query
:
any
,
as
:
string
,
shallow
:
boolean
=
false
):
Promise
<
RouteInfo
>
{
const
cachedRouteInfo
=
this
.
components
[
route
]
// If there is a shallow route transition possible
// If the route is already rendered on the screen.
if
(
shallow
&&
cachedRouteInfo
&&
this
.
route
===
route
)
{
return
Promise
.
resolve
(
cachedRouteInfo
)
}
return
(
new
Promise
((
resolve
,
reject
)
=>
{
if
(
cachedRouteInfo
)
{
return
resolve
(
cachedRouteInfo
)
}
this
.
fetchComponent
(
route
).
then
((
Component
)
=>
resolve
({
Component
}),
reject
)
})
as
Promise
<
RouteInfo
>
).
then
((
routeInfo
:
RouteInfo
)
=>
{
const
{
Component
}
=
routeInfo
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
)
{
...
...
@@ -319,49 +310,58 @@ export default class Router implements IRouterInterface {
}
}
const
ctx
=
{
pathname
,
query
,
asPath
:
as
}
routeInfo
.
props
=
await
this
.
getInitialProps
(
Component
,
ctx
)
this
.
components
[
route
]
=
routeInfo
return
routeInfo
}
catch
(
err
)
{
if
(
err
.
code
===
'
PAGE_LOAD_ERROR
'
)
{
// If we can't load the page it could be one of following reasons
// 1. Page doesn't exists
// 2. Page does exist in a different zone
// 3. Internal error while loading the page
// So, doing a hard reload is the proper way to deal with this.
window
.
location
.
href
=
as
// Changing the URL doesn't block executing the current code path.
// So, we need to mark it as a cancelled error and stop the routing logic.
err
.
cancelled
=
true
// @ts-ignore TODO: fix the control flow here
return
{
error
:
err
}
}
if
(
err
.
cancelled
)
{
// @ts-ignore TODO: fix the control flow here
return
{
error
:
err
}
}
return
(
new
Promise
((
resolve
,
reject
)
=>
{
const
ctx
=
{
pathname
,
query
,
asPath
:
as
}
this
.
getInitialProps
(
Component
,
ctx
).
then
((
props
)
=>
{
routeInfo
.
props
=
props
this
.
components
[
route
]
=
routeInfo
resolve
(
routeInfo
)
},
reject
)
})
as
Promise
<
RouteInfo
>
)
}).
catch
((
err
)
=>
{
return
(
new
Promise
((
resolve
)
=>
{
if
(
err
.
code
===
'
PAGE_LOAD_ERROR
'
)
{
// If we can't load the page it could be one of following reasons
// 1. Page doesn't exists
// 2. Page does exist in a different zone
// 3. Internal error while loading the page
// So, doing a hard reload is the proper way to deal with this.
window
.
location
.
href
=
as
// Changing the URL doesn't block executing the current code path.
// So, we need to mark it as a cancelled error and stop the routing logic.
err
.
cancelled
=
true
// @ts-ignore TODO: fix the control flow here
return
resolve
({
error
:
err
})
}
const
Component
=
await
this
.
fetchComponent
(
'
/_error
'
)
const
routeInfo
:
RouteInfo
=
{
Component
,
err
}
const
ctx
=
{
err
,
pathname
,
query
}
try
{
routeInfo
.
props
=
await
this
.
getInitialProps
(
Component
,
ctx
)
}
catch
(
err
)
{
console
.
error
(
'
Error in error page `getInitialProps`:
'
,
err
)
routeInfo
.
props
=
{}
}
if
(
err
.
cancelled
)
{
// @ts-ignore TODO: fix the control flow here
return
resolve
({
error
:
err
})
}
routeInfo
.
error
=
err
return
routeInfo
}
resolve
(
this
.
fetchComponent
(
'
/_error
'
).
then
((
Component
)
=>
{
const
routeInfo
:
RouteInfo
=
{
Component
,
err
}
const
ctx
=
{
err
,
pathname
,
query
}
return
(
new
Promise
((
resolve
)
=>
{
this
.
getInitialProps
(
Component
,
ctx
).
then
((
props
)
=>
{
routeInfo
.
props
=
props
routeInfo
.
error
=
err
resolve
(
routeInfo
)
},
(
gipErr
)
=>
{
console
.
error
(
'
Error in error page `getInitialProps`:
'
,
gipErr
)
routeInfo
.
error
=
err
routeInfo
.
props
=
{}
resolve
(
routeInfo
)
})
})
as
Promise
<
RouteInfo
>
)
}))
})
as
Promise
<
RouteInfo
>
)
})
}
set
(
route
:
string
,
pathname
:
string
,
query
:
any
,
as
:
string
,
data
:
RouteInfo
)
{
set
(
route
:
string
,
pathname
:
string
,
query
:
any
,
as
:
string
,
data
:
RouteInfo
)
:
void
{
this
.
route
=
route
this
.
pathname
=
pathname
this
.
query
=
query
...
...
@@ -370,7 +370,7 @@ export default class Router implements IRouterInterface {
}
beforePopState
(
cb
:
BeforePopStateCallback
)
{
this
.
_b
eforePopState
=
cb
this
.
_b
ps
=
cb
}
onlyAHashChange
(
as
:
string
):
boolean
{
...
...
@@ -421,16 +421,7 @@ export default class Router implements IRouterInterface {
return
this
.
asPath
!==
asPath
}
isShallowRoutingPossible
(
route
:
string
):
boolean
{
return
(
// If there's cached routeInfo for the route.
Boolean
(
this
.
components
[
route
])
&&
// If the route is already rendered on the screen.
this
.
route
===
route
)
}
async
prefetch
(
url
:
string
)
{
prefetch
(
url
:
string
):
Promise
<
void
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
// Prefetch is not supported in development mode because it would trigger on-demand-entries
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
)
return
...
...
@@ -442,7 +433,7 @@ export default class Router implements IRouterInterface {
})
}
async
fetchComponent
(
route
:
string
)
{
async
fetchComponent
(
route
:
string
)
:
Promise
<
ComponentType
>
{
let
cancelled
=
false
const
cancel
=
this
.
componentLoadCancel
=
()
=>
{
cancelled
=
true
...
...
@@ -463,7 +454,7 @@ export default class Router implements IRouterInterface {
return
Component
}
async
getInitialProps
(
Component
:
ComponentType
,
ctx
:
Context
)
{
async
getInitialProps
(
Component
:
ComponentType
,
ctx
:
Context
)
:
Promise
<
any
>
{
let
cancelled
=
false
const
cancel
=
()
=>
{
cancelled
=
true
}
this
.
componentLoadCancel
=
cancel
...
...
@@ -484,7 +475,7 @@ export default class Router implements IRouterInterface {
return
props
}
abortComponentLoad
(
as
:
string
)
{
abortComponentLoad
(
as
:
string
)
:
void
{
if
(
this
.
componentLoadCancel
)
{
Router
.
events
.
emit
(
'
routeChangeError
'
,
new
Error
(
'
Route Cancelled
'
),
as
)
this
.
componentLoadCancel
()
...
...
@@ -492,12 +483,12 @@ export default class Router implements IRouterInterface {
}
}
notify
(
data
:
RouteInfo
)
{
notify
(
data
:
RouteInfo
)
:
void
{
const
{
Component
:
App
}
=
this
.
components
[
'
/_app
'
]
this
.
subscriptions
.
forEach
((
fn
)
=>
fn
({
...
data
,
App
}))
}
subscribe
(
fn
:
Subscription
)
{
subscribe
(
fn
:
Subscription
)
:
()
=>
void
{
this
.
subscriptions
.
add
(
fn
)
return
()
=>
this
.
subscriptions
.
delete
(
fn
)
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录