mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
parent
230ae52de2
commit
5a4176cffe
|
@ -10,7 +10,8 @@ const Fragment = React.Fragment || function Fragment ({ children }) {
|
|||
|
||||
export default class Document extends Component {
|
||||
static childContextTypes = {
|
||||
_documentProps: PropTypes.any
|
||||
_documentProps: PropTypes.any,
|
||||
_devOnlyInvalidateCacheQueryString: PropTypes.string,
|
||||
}
|
||||
|
||||
static getInitialProps ({ renderPage }) {
|
||||
|
@ -20,7 +21,13 @@ export default class Document extends Component {
|
|||
}
|
||||
|
||||
getChildContext () {
|
||||
return { _documentProps: this.props }
|
||||
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() : ''
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -36,7 +43,8 @@ export default class Document extends Component {
|
|||
|
||||
export class Head extends Component {
|
||||
static contextTypes = {
|
||||
_documentProps: PropTypes.any
|
||||
_documentProps: PropTypes.any,
|
||||
_devOnlyInvalidateCacheQueryString: PropTypes.string,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -68,11 +76,13 @@ export class Head extends Component {
|
|||
|
||||
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}`}
|
||||
href={`${assetPrefix}/_next/${bundle.file}${_devOnlyInvalidateCacheQueryString}`}
|
||||
as='script'
|
||||
nonce={this.props.nonce}
|
||||
crossOrigin={this.props.crossOrigin || process.crossOrigin}
|
||||
|
@ -82,9 +92,10 @@ export class Head extends Component {
|
|||
|
||||
getPreloadMainLinks () {
|
||||
const { assetPrefix, files } = this.context._documentProps
|
||||
if(!files || files.length === 0) {
|
||||
if (!files || files.length === 0) {
|
||||
return null
|
||||
}
|
||||
const { _devOnlyInvalidateCacheQueryString } = this.context
|
||||
|
||||
return files.map((file) => {
|
||||
// Only render .js files here
|
||||
|
@ -96,7 +107,7 @@ export class Head extends Component {
|
|||
key={file}
|
||||
nonce={this.props.nonce}
|
||||
rel='preload'
|
||||
href={`${assetPrefix}/_next/${file}`}
|
||||
href={`${assetPrefix}/_next/${file}${_devOnlyInvalidateCacheQueryString}`}
|
||||
as='script'
|
||||
crossOrigin={this.props.crossOrigin || process.crossOrigin}
|
||||
/>
|
||||
|
@ -105,6 +116,7 @@ export class Head extends Component {
|
|||
|
||||
render () {
|
||||
const { head, styles, assetPrefix, __NEXT_DATA__ } = this.context._documentProps
|
||||
const { _devOnlyInvalidateCacheQueryString } = this.context
|
||||
const { page, buildId } = __NEXT_DATA__
|
||||
const pagePathname = getPagePathname(page)
|
||||
|
||||
|
@ -119,12 +131,11 @@ export class Head extends Component {
|
|||
})
|
||||
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}
|
||||
{page !== '/_error' && <link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}`} as='script' nonce={this.props.nonce} crossOrigin={this.props.crossOrigin || process.crossOrigin} />}
|
||||
<link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages/_app.js`} as='script' nonce={this.props.nonce} crossOrigin={this.props.crossOrigin || process.crossOrigin} />
|
||||
{page !== '/_error' && <link rel='preload' href={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}${_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()}
|
||||
|
@ -135,7 +146,8 @@ export class Head extends Component {
|
|||
|
||||
export class Main extends Component {
|
||||
static contextTypes = {
|
||||
_documentProps: PropTypes.any
|
||||
_documentProps: PropTypes.any,
|
||||
_devOnlyInvalidateCacheQueryString: PropTypes.string,
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -148,7 +160,8 @@ export class Main extends Component {
|
|||
|
||||
export class NextScript extends Component {
|
||||
static contextTypes = {
|
||||
_documentProps: PropTypes.any
|
||||
_documentProps: PropTypes.any,
|
||||
_devOnlyInvalidateCacheQueryString: PropTypes.string,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -158,11 +171,13 @@ export class NextScript extends Component {
|
|||
|
||||
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}`}
|
||||
src={`${assetPrefix}/_next/${bundle.file}${_devOnlyInvalidateCacheQueryString}`}
|
||||
nonce={this.props.nonce}
|
||||
crossOrigin={this.props.crossOrigin || process.crossOrigin}
|
||||
/>
|
||||
|
@ -171,9 +186,10 @@ export class NextScript extends Component {
|
|||
|
||||
getScripts () {
|
||||
const { assetPrefix, files } = this.context._documentProps
|
||||
if(!files || files.length === 0) {
|
||||
if (!files || files.length === 0) {
|
||||
return null
|
||||
}
|
||||
const { _devOnlyInvalidateCacheQueryString } = this.context
|
||||
|
||||
return files.map((file) => {
|
||||
// Only render .js files here
|
||||
|
@ -183,7 +199,7 @@ export class NextScript extends Component {
|
|||
|
||||
return <script
|
||||
key={file}
|
||||
src={`${assetPrefix}/_next/${file}`}
|
||||
src={`${assetPrefix}/_next/${file}${_devOnlyInvalidateCacheQueryString}`}
|
||||
nonce={this.props.nonce}
|
||||
async
|
||||
crossOrigin={this.props.crossOrigin || process.crossOrigin}
|
||||
|
@ -206,6 +222,7 @@ export class NextScript extends Component {
|
|||
|
||||
render () {
|
||||
const { staticMarkup, assetPrefix, devFiles, __NEXT_DATA__ } = this.context._documentProps
|
||||
const { _devOnlyInvalidateCacheQueryString } = this.context
|
||||
const { page, buildId } = __NEXT_DATA__
|
||||
const pagePathname = getPagePathname(page)
|
||||
|
||||
|
@ -214,12 +231,12 @@ export class NextScript extends Component {
|
|||
}
|
||||
|
||||
return <Fragment>
|
||||
{devFiles ? devFiles.map((file) => <script key={file} src={`${assetPrefix}/_next/${file}`} nonce={this.props.nonce} crossOrigin={this.props.crossOrigin || process.crossOrigin} />) : null}
|
||||
{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${pagePathname}`} nonce={this.props.nonce} crossOrigin={this.props.crossOrigin || process.crossOrigin} />}
|
||||
<script async id={`__NEXT_PAGE__/_app`} src={`${assetPrefix}/_next/static/${buildId}/pages/_app.js`} nonce={this.props.nonce} crossOrigin={this.props.crossOrigin || process.crossOrigin} />
|
||||
{page !== '/_error' && <script async id={`__NEXT_PAGE__${page}`} src={`${assetPrefix}/_next/static/${buildId}/pages${pagePathname}${_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()}
|
||||
</Fragment>
|
||||
|
|
|
@ -67,6 +67,22 @@ export default function ({ app }, suiteName, render, fetch) {
|
|||
expect($('#render-page-enhance-app').text().includes(nonce)).toBe(true)
|
||||
expect($('#render-page-enhance-component').text().includes(nonce)).toBe(true)
|
||||
})
|
||||
|
||||
// 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.
|
||||
test('It adds a timestamp to link tags with preload attribute to invalidate the cache (DEV only)', async () => {
|
||||
const $ = await get$('/')
|
||||
$('link[rel=preload]').each((index, element) => {
|
||||
const href = $(element).attr('href')
|
||||
expect(href.match(/\?/g)).toHaveLength(1)
|
||||
expect(href).toMatch(/\?ts=/)
|
||||
})
|
||||
$('script[src]').each((index, element) => {
|
||||
const src = $(element).attr('src')
|
||||
expect(src.match(/\?/g)).toHaveLength(1)
|
||||
expect(src).toMatch(/\?ts=/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('_app', () => {
|
||||
|
|
|
@ -241,6 +241,27 @@ describe('Production Usage', () => {
|
|||
browser.close()
|
||||
})
|
||||
|
||||
// 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.
|
||||
it('It does not add a timestamp to link tags with preload attribute', async () => {
|
||||
const browser = await webdriver(appPort, '/prefetch')
|
||||
const links = await browser.elementsByCss('link[rel=preload]')
|
||||
await Promise.all(
|
||||
links.map(async (element) => {
|
||||
const href = await element.getAttribute('href')
|
||||
expect(href).not.toMatch(/\?ts=/)
|
||||
})
|
||||
)
|
||||
const scripts = await browser.elementsByCss('script[src]')
|
||||
await Promise.all(
|
||||
scripts.map(async (element) => {
|
||||
const src = await element.getAttribute('src')
|
||||
expect(src).not.toMatch(/\?ts=/)
|
||||
})
|
||||
)
|
||||
browser.close()
|
||||
})
|
||||
|
||||
it('should reload the page on page script error with prefetch', async () => {
|
||||
const browser = await webdriver(appPort, '/counter')
|
||||
const counter = await browser
|
||||
|
|
Loading…
Reference in a new issue