Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
CoCo_Code_Op2
next.js
提交
494889ac
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,发现更多精彩内容 >>
未验证
提交
494889ac
编写于
3月 01, 2019
作者:
J
Joe Haddad
提交者:
GitHub
3月 01, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Format a few documents (#6505)
上级
a9c39885
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
386 addition
and
155 deletion
+386
-155
packages/next-server/server/next-server.ts
packages/next-server/server/next-server.ts
+150
-46
packages/next-server/server/render.tsx
packages/next-server/server/render.tsx
+3
-1
packages/next/pages/_document.js
packages/next/pages/_document.js
+233
-108
未找到文件。
packages/next-server/server/next-server.ts
浏览文件 @
494889ac
/* eslint-disable import/first */
import
{
IncomingMessage
,
ServerResponse
}
from
'
http
'
import
{
IncomingMessage
,
ServerResponse
}
from
'
http
'
import
{
resolve
,
join
,
sep
}
from
'
path
'
import
{
parse
as
parseUrl
,
UrlWithParsedQuery
}
from
'
url
'
import
{
parse
as
parseQs
,
ParsedUrlQuery
}
from
'
querystring
'
import
fs
from
'
fs
'
import
{
renderToHTML
}
from
'
./render
'
import
{
sendHTML
}
from
'
./send-html
'
import
{
serveStatic
}
from
'
./serve-static
'
import
Router
,
{
route
,
Route
}
from
'
./router
'
import
{
renderToHTML
}
from
'
./render
'
import
{
sendHTML
}
from
'
./send-html
'
import
{
serveStatic
}
from
'
./serve-static
'
import
Router
,
{
route
,
Route
}
from
'
./router
'
import
{
isInternalUrl
,
isBlockedPage
}
from
'
./utils
'
import
loadConfig
from
'
next-server/next-config
'
import
{
PHASE_PRODUCTION_SERVER
,
BUILD_ID_FILE
,
CLIENT_STATIC_FILES_PATH
,
CLIENT_STATIC_FILES_RUNTIME
}
from
'
next-server/constants
'
import
{
PHASE_PRODUCTION_SERVER
,
BUILD_ID_FILE
,
CLIENT_STATIC_FILES_PATH
,
CLIENT_STATIC_FILES_RUNTIME
,
}
from
'
next-server/constants
'
import
*
as
envConfig
from
'
../lib/runtime-config
'
import
{
loadComponents
}
from
'
./load-components
'
import
{
loadComponents
}
from
'
./load-components
'
type
NextConfig
=
any
type
ServerConstructor
=
{
dir
?:
string
,
staticMarkup
?:
boolean
,
quiet
?:
boolean
,
dir
?:
string
staticMarkup
?:
boolean
quiet
?:
boolean
conf
?:
NextConfig
,
}
...
...
@@ -30,16 +35,21 @@ export default class Server {
distDir
:
string
buildId
:
string
renderOpts
:
{
ampEnabled
:
boolean
,
staticMarkup
:
boolean
,
buildId
:
string
,
generateEtags
:
boolean
,
runtimeConfig
?:
{
[
key
:
string
]:
any
},
ampEnabled
:
boolean
staticMarkup
:
boolean
buildId
:
string
generateEtags
:
boolean
runtimeConfig
?:
{
[
key
:
string
]:
any
}
assetPrefix
?:
string
,
}
router
:
Router
public
constructor
({
dir
=
'
.
'
,
staticMarkup
=
false
,
quiet
=
false
,
conf
=
null
}:
ServerConstructor
=
{})
{
public
constructor
({
dir
=
'
.
'
,
staticMarkup
=
false
,
quiet
=
false
,
conf
=
null
,
}:
ServerConstructor
=
{})
{
this
.
dir
=
resolve
(
dir
)
this
.
quiet
=
quiet
const
phase
=
this
.
currentPhase
()
...
...
@@ -48,9 +58,18 @@ export default class Server {
// Only serverRuntimeConfig needs the default
// publicRuntimeConfig gets it's default in client/index.js
const
{
serverRuntimeConfig
=
{},
publicRuntimeConfig
,
assetPrefix
,
generateEtags
,
target
}
=
this
.
nextConfig
const
{
serverRuntimeConfig
=
{},
publicRuntimeConfig
,
assetPrefix
,
generateEtags
,
target
,
}
=
this
.
nextConfig
if
(
process
.
env
.
NODE_ENV
===
'
production
'
&&
target
!==
'
server
'
)
throw
new
Error
(
'
Cannot start server when target is not server. https://err.sh/zeit/next.js/next-start-serverless
'
)
if
(
process
.
env
.
NODE_ENV
===
'
production
'
&&
target
!==
'
server
'
)
throw
new
Error
(
'
Cannot start server when target is not server. https://err.sh/zeit/next.js/next-start-serverless
'
,
)
this
.
buildId
=
this
.
readBuildId
()
this
.
renderOpts
=
{
...
...
@@ -87,7 +106,11 @@ export default class Server {
console
.
error
(...
args
)
}
private
handleRequest
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
parsedUrl
?:
UrlWithParsedQuery
):
Promise
<
void
>
{
private
handleRequest
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
parsedUrl
?:
UrlWithParsedQuery
,
):
Promise
<
void
>
{
// Parse url if parsedUrl not provided
if
(
!
parsedUrl
||
typeof
parsedUrl
!==
'
object
'
)
{
const
url
:
any
=
req
.
url
...
...
@@ -100,12 +123,11 @@ export default class Server {
}
res
.
statusCode
=
200
return
this
.
run
(
req
,
res
,
parsedUrl
)
.
catch
((
err
)
=>
{
this
.
logError
(
err
)
res
.
statusCode
=
500
res
.
end
(
'
Internal Server Error
'
)
})
return
this
.
run
(
req
,
res
,
parsedUrl
).
catch
((
err
)
=>
{
this
.
logError
(
err
)
res
.
statusCode
=
500
res
.
end
(
'
Internal Server Error
'
)
})
}
public
getRequestHandler
()
{
...
...
@@ -134,10 +156,18 @@ export default class Server {
// The commons folder holds commonschunk files
// The chunks folder holds dynamic entries
// The buildId folder holds pages and potentially other assets. As buildId changes per build it can be long-term cached.
if
(
params
.
path
[
0
]
===
CLIENT_STATIC_FILES_RUNTIME
||
params
.
path
[
0
]
===
'
chunks
'
||
params
.
path
[
0
]
===
this
.
buildId
)
{
if
(
params
.
path
[
0
]
===
CLIENT_STATIC_FILES_RUNTIME
||
params
.
path
[
0
]
===
'
chunks
'
||
params
.
path
[
0
]
===
this
.
buildId
)
{
this
.
setImmutableAssetCacheControl
(
res
)
}
const
p
=
join
(
this
.
distDir
,
CLIENT_STATIC_FILES_PATH
,
...(
params
.
path
||
[]))
const
p
=
join
(
this
.
distDir
,
CLIENT_STATIC_FILES_PATH
,
...(
params
.
path
||
[]),
)
await
this
.
serveStatic
(
req
,
res
,
p
,
parsedUrl
)
},
},
...
...
@@ -187,7 +217,11 @@ export default class Server {
return
routes
}
private
async
run
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
parsedUrl
:
UrlWithParsedQuery
)
{
private
async
run
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
parsedUrl
:
UrlWithParsedQuery
,
)
{
try
{
const
fn
=
this
.
router
.
match
(
req
,
res
,
parsedUrl
)
if
(
fn
)
{
...
...
@@ -210,12 +244,22 @@ export default class Server {
}
}
private
async
sendHTML
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
html
:
string
)
{
const
{
generateEtags
}
=
this
.
renderOpts
return
sendHTML
(
req
,
res
,
html
,
{
generateEtags
})
private
async
sendHTML
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
html
:
string
,
)
{
const
{
generateEtags
}
=
this
.
renderOpts
return
sendHTML
(
req
,
res
,
html
,
{
generateEtags
})
}
public
async
render
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
parsedUrl
?:
UrlWithParsedQuery
):
Promise
<
void
>
{
public
async
render
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
parsedUrl
?:
UrlWithParsedQuery
,
):
Promise
<
void
>
{
const
url
:
any
=
req
.
url
if
(
isInternalUrl
(
url
))
{
return
this
.
handleRequest
(
req
,
res
,
parsedUrl
)
...
...
@@ -237,7 +281,13 @@ export default class Server {
return
this
.
sendHTML
(
req
,
res
,
html
)
}
public
async
renderToAMP
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
parsedUrl
?:
UrlWithParsedQuery
):
Promise
<
void
>
{
public
async
renderToAMP
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
parsedUrl
?:
UrlWithParsedQuery
,
):
Promise
<
void
>
{
if
(
!
this
.
nextConfig
.
experimental
.
amp
)
{
throw
new
Error
(
'
"experimental.amp" is not enabled in "next.config.js"
'
)
}
...
...
@@ -262,22 +312,45 @@ export default class Server {
return
this
.
sendHTML
(
req
,
res
,
html
)
}
private
async
renderToHTMLWithComponents
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
opts
:
any
)
{
private
async
renderToHTMLWithComponents
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
opts
:
any
,
)
{
const
result
=
await
loadComponents
(
this
.
distDir
,
this
.
buildId
,
pathname
)
return
renderToHTML
(
req
,
res
,
pathname
,
query
,
{
...
result
,
...
opts
})
return
renderToHTML
(
req
,
res
,
pathname
,
query
,
{
...
result
,
...
opts
})
}
public
async
renderToAMPHTML
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{}):
Promise
<
string
|
null
>
{
public
async
renderToAMPHTML
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
):
Promise
<
string
|
null
>
{
if
(
!
this
.
nextConfig
.
experimental
.
amp
)
{
throw
new
Error
(
'
"experimental.amp" is not enabled in "next.config.js"
'
)
}
return
this
.
renderToHTML
(
req
,
res
,
pathname
,
query
,
{
amphtml
:
true
})
return
this
.
renderToHTML
(
req
,
res
,
pathname
,
query
,
{
amphtml
:
true
})
}
public
async
renderToHTML
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
{
amphtml
}:
{
amphtml
?:
boolean
}
=
{}):
Promise
<
string
|
null
>
{
public
async
renderToHTML
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
{
amphtml
}:
{
amphtml
?:
boolean
}
=
{},
):
Promise
<
string
|
null
>
{
try
{
// To make sure the try/catch is executed
const
html
=
await
this
.
renderToHTMLWithComponents
(
req
,
res
,
pathname
,
query
,
{...
this
.
renderOpts
,
amphtml
})
const
html
=
await
this
.
renderToHTMLWithComponents
(
req
,
res
,
pathname
,
query
,
{
...
this
.
renderOpts
,
amphtml
},
)
return
html
}
catch
(
err
)
{
if
(
err
.
code
===
'
ENOENT
'
)
{
...
...
@@ -291,8 +364,17 @@ export default class Server {
}
}
public
async
renderError
(
err
:
Error
|
null
,
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{}):
Promise
<
void
>
{
res
.
setHeader
(
'
Cache-Control
'
,
'
no-cache, no-store, max-age=0, must-revalidate
'
)
public
async
renderError
(
err
:
Error
|
null
,
req
:
IncomingMessage
,
res
:
ServerResponse
,
pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
):
Promise
<
void
>
{
res
.
setHeader
(
'
Cache-Control
'
,
'
no-cache, no-store, max-age=0, must-revalidate
'
,
)
const
html
=
await
this
.
renderErrorToHTML
(
err
,
req
,
res
,
pathname
,
query
)
if
(
html
===
null
)
{
return
...
...
@@ -300,11 +382,24 @@ export default class Server {
return
this
.
sendHTML
(
req
,
res
,
html
)
}
public
async
renderErrorToHTML
(
err
:
Error
|
null
,
req
:
IncomingMessage
,
res
:
ServerResponse
,
_pathname
:
string
,
query
:
ParsedUrlQuery
=
{})
{
return
this
.
renderToHTMLWithComponents
(
req
,
res
,
'
/_error
'
,
query
,
{...
this
.
renderOpts
,
err
})
public
async
renderErrorToHTML
(
err
:
Error
|
null
,
req
:
IncomingMessage
,
res
:
ServerResponse
,
_pathname
:
string
,
query
:
ParsedUrlQuery
=
{},
)
{
return
this
.
renderToHTMLWithComponents
(
req
,
res
,
'
/_error
'
,
query
,
{
...
this
.
renderOpts
,
err
,
})
}
public
async
render404
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
parsedUrl
?:
UrlWithParsedQuery
):
Promise
<
void
>
{
public
async
render404
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
parsedUrl
?:
UrlWithParsedQuery
,
):
Promise
<
void
>
{
const
url
:
any
=
req
.
url
const
{
pathname
,
query
}
=
parsedUrl
?
parsedUrl
:
parseUrl
(
url
,
true
)
if
(
!
pathname
)
{
...
...
@@ -314,7 +409,12 @@ export default class Server {
return
this
.
renderError
(
null
,
req
,
res
,
pathname
,
query
)
}
public
async
serveStatic
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
path
:
string
,
parsedUrl
?:
UrlWithParsedQuery
):
Promise
<
void
>
{
public
async
serveStatic
(
req
:
IncomingMessage
,
res
:
ServerResponse
,
path
:
string
,
parsedUrl
?:
UrlWithParsedQuery
,
):
Promise
<
void
>
{
if
(
!
this
.
isServeableUrl
(
path
))
{
return
this
.
render404
(
req
,
res
,
parsedUrl
)
}
...
...
@@ -349,7 +449,11 @@ export default class Server {
return
fs
.
readFileSync
(
buildIdFile
,
'
utf8
'
).
trim
()
}
catch
(
err
)
{
if
(
!
fs
.
existsSync
(
buildIdFile
))
{
throw
new
Error
(
`Could not find a valid build in the '
${
this
.
distDir
}
' directory! Try building your app with 'next build' before starting the server.`
)
throw
new
Error
(
`Could not find a valid build in the '
${
this
.
distDir
}
' directory! Try building your app with 'next build' before starting the server.`
,
)
}
throw
err
...
...
packages/next-server/server/render.tsx
浏览文件 @
494889ac
...
...
@@ -213,7 +213,9 @@ export async function renderToHTML(
}
if
(
dev
&&
(
props
.
router
||
props
.
Component
))
{
throw
new
Error
(
`'router' and 'Component' can not be returned in getInitialProps from _app.js https://err.sh/zeit/next.js/cant-override-next-props.md`
)
throw
new
Error
(
`'router' and 'Component' can not be returned in getInitialProps from _app.js https://err.sh/zeit/next.js/cant-override-next-props.md`
,
)
}
const
{
...
...
packages/next/pages/_document.js
浏览文件 @
494889ac
...
...
@@ -14,19 +14,20 @@ export default class Document extends Component {
_devOnlyInvalidateCacheQueryString
:
PropTypes
.
string
,
}
static
getInitialProps
({
renderPage
})
{
static
getInitialProps
({
renderPage
})
{
const
{
html
,
head
}
=
renderPage
()
const
styles
=
flush
()
return
{
html
,
head
,
styles
}
}
getChildContext
()
{
getChildContext
()
{
return
{
_documentProps
:
this
.
props
,
// In dev we invalidate the cache by appending a timestamp to the resource URL.
// This is a workaround to fix https://github.com/zeit/next.js/issues/5860
// TODO: remove this workaround when https://bugs.webkit.org/show_bug.cgi?id=187726 is fixed.
_devOnlyInvalidateCacheQueryString
:
process
.
env
.
NODE_ENV
!==
'
production
'
?
'
?ts=
'
+
Date
.
now
()
:
''
_devOnlyInvalidateCacheQueryString
:
process
.
env
.
NODE_ENV
!==
'
production
'
?
'
?ts=
'
+
Date
.
now
()
:
''
,
}
}
...
...
@@ -71,111 +72,181 @@ export class Head extends Component {
static
propTypes
=
{
nonce
:
PropTypes
.
string
,
crossOrigin
:
PropTypes
.
string
crossOrigin
:
PropTypes
.
string
,
}
getCssLinks
()
{
getCssLinks
()
{
const
{
assetPrefix
,
files
}
=
this
.
context
.
_documentProps
if
(
!
files
||
files
.
length
===
0
)
{
if
(
!
files
||
files
.
length
===
0
)
{
return
null
}
return
files
.
map
(
(
file
)
=>
{
return
files
.
map
(
file
=>
{
// Only render .css files here
if
(
!
/
\.
css$/
.
exec
(
file
))
{
if
(
!
/
\.
css$/
.
exec
(
file
))
{
return
null
}
return
<
link
key
=
{
file
}
nonce
=
{
this
.
props
.
nonce
}
rel
=
'
stylesheet
'
href
=
{
`
${
assetPrefix
}
/_next/
${
file
}
`
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
return
(
<
link
key
=
{
file
}
nonce
=
{
this
.
props
.
nonce
}
rel
=
"
stylesheet
"
href
=
{
`
${
assetPrefix
}
/_next/
${
file
}
`
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)
})
}
getPreloadDynamicChunks
()
{
getPreloadDynamicChunks
()
{
const
{
dynamicImports
,
assetPrefix
}
=
this
.
context
.
_documentProps
const
{
_devOnlyInvalidateCacheQueryString
}
=
this
.
context
return
dynamicImports
.
map
((
bundle
)
=>
{
return
<
link
rel
=
'
preload
'
key
=
{
bundle
.
file
}
href
=
{
`
${
assetPrefix
}
/_next/
${
bundle
.
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
'
script
'
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
return
dynamicImports
.
map
(
bundle
=>
{
return
(
<
link
rel
=
"
preload
"
key
=
{
bundle
.
file
}
href
=
{
`
${
assetPrefix
}
/_next/
${
bundle
.
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
"
script
"
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)
})
}
getPreloadMainLinks
()
{
getPreloadMainLinks
()
{
const
{
assetPrefix
,
files
}
=
this
.
context
.
_documentProps
if
(
!
files
||
files
.
length
===
0
)
{
return
null
}
const
{
_devOnlyInvalidateCacheQueryString
}
=
this
.
context
return
files
.
map
(
(
file
)
=>
{
return
files
.
map
(
file
=>
{
// Only render .js files here
if
(
!
/
\.
js$/
.
exec
(
file
))
{
if
(
!
/
\.
js$/
.
exec
(
file
))
{
return
null
}
return
<
link
key
=
{
file
}
nonce
=
{
this
.
props
.
nonce
}
rel
=
'
preload
'
href
=
{
`
${
assetPrefix
}
/_next/
${
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
'
script
'
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
return
(
<
link
key
=
{
file
}
nonce
=
{
this
.
props
.
nonce
}
rel
=
"
preload
"
href
=
{
`
${
assetPrefix
}
/_next/
${
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
"
script
"
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)
})
}
render
()
{
const
{
ampEnabled
,
head
,
styles
,
amphtml
,
assetPrefix
,
__NEXT_DATA__
}
=
this
.
context
.
_documentProps
render
()
{
const
{
ampEnabled
,
head
,
styles
,
amphtml
,
assetPrefix
,
__NEXT_DATA__
,
}
=
this
.
context
.
_documentProps
const
{
_devOnlyInvalidateCacheQueryString
}
=
this
.
context
const
{
page
,
buildId
}
=
__NEXT_DATA__
let
children
=
this
.
props
.
children
// show a warning if Head contains <title> (only in development)
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
)
{
children
=
React
.
Children
.
map
(
children
,
(
child
)
=>
{
children
=
React
.
Children
.
map
(
children
,
child
=>
{
if
(
child
&&
child
.
type
===
'
title
'
)
{
console
.
warn
(
"
Warning: <title> should not be used in _document.js's <Head>. https://err.sh/next.js/no-document-title
"
)
console
.
warn
(
"
Warning: <title> should not be used in _document.js's <Head>. https://err.sh/next.js/no-document-title
"
)
}
return
child
})
if
(
this
.
props
.
crossOrigin
)
console
.
warn
(
'
Warning: `Head` attribute `crossOrigin` is deprecated. https://err.sh/next.js/doc-crossorigin-deprecated
'
)
if
(
this
.
props
.
crossOrigin
)
console
.
warn
(
'
Warning: `Head` attribute `crossOrigin` is deprecated. https://err.sh/next.js/doc-crossorigin-deprecated
'
)
}
return
<
head
{...
this
.
props
}
>
{
children
}
{
head
}
{
amphtml
&&
<>
<
meta
name
=
"
viewport
"
content
=
"
width=device-width,minimum-scale=1,initial-scale=1
"
/>
<
link
rel
=
"
canonical
"
href
=
{
page
}
/
>
{
/* https://www.ampproject.org/docs/fundamentals/optimize_amp#optimize-the-amp-runtime-loading */
}
<
link
rel
=
"
preload
"
as
=
"
script
"
href
=
"
https://cdn.ampproject.org/v0.js
"
/>
{
/* Add custom styles before AMP styles to prevent accidental overrides */
}
{
styles
&&
<
style
amp
-
custom
=
""
dangerouslySetInnerHTML
=
{{
__html
:
styles
.
map
((
style
)
=>
style
.
props
.
dangerouslySetInnerHTML
.
__html
).
join
(
''
)}}
/>
}
<
style
amp
-
boilerplate
=
""
dangerouslySetInnerHTML
=
{{
__html
:
`body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}`
}}
><
/style
>
<
noscript
><
style
amp
-
boilerplate
=
""
dangerouslySetInnerHTML
=
{{
__html
:
`body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}`
}}
><
/style></
noscript
>
<
script
async
src
=
"
https://cdn.ampproject.org/v0.js
"
><
/script
>
<
/>
}
{
!
amphtml
&&
<>
{
ampEnabled
&&
<
link
rel
=
"
amphtml
"
href
=
{
`
${
page
}
?amp=1`
}
/>
}
{
page
!==
'
/_error
'
&&
<
link
rel
=
'
preload
'
href
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages
${
getPagePathname
(
page
)}${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
'
script
'
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/>
}
<
link
rel
=
'
preload
'
href
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages/_app.js
${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
'
script
'
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
{
this
.
getPreloadDynamicChunks
()}
{
this
.
getPreloadMainLinks
()}
{
this
.
getCssLinks
()}
{
styles
||
null
}
<
/>
}
<
/head
>
return
(
<
head
{...
this
.
props
}
>
{
children
}
{
head
}
{
amphtml
&&
(
<>
<
meta
name
=
"
viewport
"
content
=
"
width=device-width,minimum-scale=1,initial-scale=1
"
/>
<
link
rel
=
"
canonical
"
href
=
{
page
}
/
>
{
/* https://www.ampproject.org/docs/fundamentals/optimize_amp#optimize-the-amp-runtime-loading */
}
<
link
rel
=
"
preload
"
as
=
"
script
"
href
=
"
https://cdn.ampproject.org/v0.js
"
/>
{
/* Add custom styles before AMP styles to prevent accidental overrides */
}
{
styles
&&
(
<
style
amp
-
custom
=
""
dangerouslySetInnerHTML
=
{{
__html
:
styles
.
map
(
style
=>
style
.
props
.
dangerouslySetInnerHTML
.
__html
)
.
join
(
''
),
}}
/
>
)}
<
style
amp
-
boilerplate
=
""
dangerouslySetInnerHTML
=
{{
__html
:
`body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}`
,
}}
/
>
<
noscript
>
<
style
amp
-
boilerplate
=
""
dangerouslySetInnerHTML
=
{{
__html
:
`body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}`
,
}}
/
>
<
/noscript
>
<
script
async
src
=
"
https://cdn.ampproject.org/v0.js
"
/>
<
/
>
)}
{
!
amphtml
&&
(
<>
{
ampEnabled
&&
<
link
rel
=
"
amphtml
"
href
=
{
`
${
page
}
?amp=1`
}
/>
}
{
page
!==
'
/_error
'
&&
(
<
link
rel
=
"
preload
"
href
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages
${
getPagePathname
(
page
)}${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
"
script
"
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)}
<
link
rel
=
"
preload
"
href
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages/_app.js
${
_devOnlyInvalidateCacheQueryString
}
`
}
as
=
"
script
"
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
{
this
.
getPreloadDynamicChunks
()}
{
this
.
getPreloadMainLinks
()}
{
this
.
getCssLinks
()}
{
styles
||
null
}
<
/
>
)}
<
/head
>
)
}
}
...
...
@@ -185,11 +256,9 @@ export class Main extends Component {
_devOnlyInvalidateCacheQueryString
:
PropTypes
.
string
,
}
render
()
{
render
()
{
const
{
html
}
=
this
.
context
.
_documentProps
return
(
<
div
id
=
'
__next
'
dangerouslySetInnerHTML
=
{{
__html
:
html
}}
/
>
)
return
<
div
id
=
"
__next
"
dangerouslySetInnerHTML
=
{{
__html
:
html
}}
/
>
}
}
...
...
@@ -201,62 +270,78 @@ export class NextScript extends Component {
static
propTypes
=
{
nonce
:
PropTypes
.
string
,
crossOrigin
:
PropTypes
.
string
crossOrigin
:
PropTypes
.
string
,
}
getDynamicChunks
()
{
getDynamicChunks
()
{
const
{
dynamicImports
,
assetPrefix
}
=
this
.
context
.
_documentProps
const
{
_devOnlyInvalidateCacheQueryString
}
=
this
.
context
return
dynamicImports
.
map
((
bundle
)
=>
{
return
<
script
async
key
=
{
bundle
.
file
}
src
=
{
`
${
assetPrefix
}
/_next/
${
bundle
.
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
return
dynamicImports
.
map
(
bundle
=>
{
return
(
<
script
async
key
=
{
bundle
.
file
}
src
=
{
`
${
assetPrefix
}
/_next/
${
bundle
.
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)
})
}
getScripts
()
{
getScripts
()
{
const
{
assetPrefix
,
files
}
=
this
.
context
.
_documentProps
if
(
!
files
||
files
.
length
===
0
)
{
return
null
}
const
{
_devOnlyInvalidateCacheQueryString
}
=
this
.
context
return
files
.
map
(
(
file
)
=>
{
return
files
.
map
(
file
=>
{
// Only render .js files here
if
(
!
/
\.
js$/
.
exec
(
file
))
{
if
(
!
/
\.
js$/
.
exec
(
file
))
{
return
null
}
return
<
script
key
=
{
file
}
src
=
{
`
${
assetPrefix
}
/_next/
${
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
async
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
return
(
<
script
key
=
{
file
}
src
=
{
`
${
assetPrefix
}
/_next/
${
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
async
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)
})
}
static
getInlineScriptSource
(
documentProps
)
{
const
{
__NEXT_DATA__
}
=
documentProps
static
getInlineScriptSource
(
documentProps
)
{
const
{
__NEXT_DATA__
}
=
documentProps
try
{
const
data
=
JSON
.
stringify
(
__NEXT_DATA__
)
return
htmlEscapeJsonString
(
data
)
}
catch
(
err
)
{
if
(
err
.
message
.
indexOf
(
'
circular structure
'
))
{
throw
new
Error
(
`Circular structure in "getInitialProps" result of page "
${
__NEXT_DATA__
.
page
}
". https://err.sh/zeit/next.js/circular-structure`
)
}
catch
(
err
)
{
if
(
err
.
message
.
indexOf
(
'
circular structure
'
))
{
throw
new
Error
(
`Circular structure in "getInitialProps" result of page "
${
__NEXT_DATA__
.
page
}
". https://err.sh/zeit/next.js/circular-structure`
)
}
throw
err
}
}
render
()
{
const
{
staticMarkup
,
assetPrefix
,
amphtml
,
devFiles
,
__NEXT_DATA__
}
=
this
.
context
.
_documentProps
render
()
{
const
{
staticMarkup
,
assetPrefix
,
amphtml
,
devFiles
,
__NEXT_DATA__
,
}
=
this
.
context
.
_documentProps
const
{
_devOnlyInvalidateCacheQueryString
}
=
this
.
context
if
(
amphtml
)
{
...
...
@@ -301,23 +386,63 @@ export class NextScript extends Component {
const
{
page
,
buildId
}
=
__NEXT_DATA__
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
)
{
if
(
this
.
props
.
crossOrigin
)
console
.
warn
(
'
Warning: `NextScript` attribute `crossOrigin` is deprecated. https://err.sh/next.js/doc-crossorigin-deprecated
'
)
if
(
this
.
props
.
crossOrigin
)
console
.
warn
(
'
Warning: `NextScript` attribute `crossOrigin` is deprecated. https://err.sh/next.js/doc-crossorigin-deprecated
'
)
}
return
<>
{
devFiles
?
devFiles
.
map
((
file
)
=>
<
script
key
=
{
file
}
src
=
{
`
${
assetPrefix
}
/_next/
${
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/>
)
: null
}
{
staticMarkup
?
null
:
<
script
id
=
"
__NEXT_DATA__
"
type
=
"
application/json
"
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
dangerouslySetInnerHTML
=
{{
__html
:
NextScript
.
getInlineScriptSource
(
this
.
context
.
_documentProps
)
}}
/>
}
{
page
!==
'
/_error
'
&&
<
script
async
id
=
{
`__NEXT_PAGE__
${
page
}
`
}
src
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages
${
getPagePathname
(
page
)}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/>
}
<
script
async
id
=
{
`__NEXT_PAGE__/_app`
}
src
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages/_app.js
${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
{
staticMarkup
?
null
:
this
.
getDynamicChunks
()}
{
staticMarkup
?
null
:
this
.
getScripts
()}
<
/
>
return
(
<>
{
devFiles
?
devFiles
.
map
(
file
=>
(
<
script
key
=
{
file
}
src
=
{
`
${
assetPrefix
}
/_next/
${
file
}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
))
:
null
}
{
staticMarkup
?
null
:
(
<
script
id
=
"
__NEXT_DATA__
"
type
=
"
application/json
"
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
dangerouslySetInnerHTML
=
{{
__html
:
NextScript
.
getInlineScriptSource
(
this
.
context
.
_documentProps
),
}}
/
>
)}
{
page
!==
'
/_error
'
&&
(
<
script
async
id
=
{
`__NEXT_PAGE__
${
page
}
`
}
src
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages
${
getPagePathname
(
page
)}${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
)}
<
script
async
id
=
{
`__NEXT_PAGE__/_app`
}
src
=
{
`
${
assetPrefix
}
/_next/static/
${
buildId
}
/pages/_app.js
${
_devOnlyInvalidateCacheQueryString
}
`
}
nonce
=
{
this
.
props
.
nonce
}
crossOrigin
=
{
this
.
props
.
crossOrigin
||
process
.
crossOrigin
}
/
>
{
staticMarkup
?
null
:
this
.
getDynamicChunks
()}
{
staticMarkup
?
null
:
this
.
getScripts
()}
<
/
>
)
}
}
function
getPagePathname
(
page
)
{
function
getPagePathname
(
page
)
{
if
(
page
===
'
/
'
)
{
return
'
/index.js
'
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录