mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Never cache assets and HTML in the dev mode. (#2045)
* Never cache assets and HTML in the dev mode. * Move etags test to the production. Now it won't work in dev because of no-cache settings.
This commit is contained in:
parent
3c95f21d8c
commit
9121a9d22e
|
@ -36,8 +36,8 @@ export class Head extends Component {
|
|||
|
||||
getChunkPreloadLink (filename) {
|
||||
const { __NEXT_DATA__ } = this.context._documentProps
|
||||
let { buildStats, assetPrefix } = __NEXT_DATA__
|
||||
const hash = buildStats ? buildStats[filename].hash : '-'
|
||||
let { buildStats, assetPrefix, buildId } = __NEXT_DATA__
|
||||
const hash = buildStats ? buildStats[filename].hash : buildId
|
||||
|
||||
return (
|
||||
<link
|
||||
|
@ -103,8 +103,8 @@ export class NextScript extends Component {
|
|||
|
||||
getChunkScript (filename, additionalProps = {}) {
|
||||
const { __NEXT_DATA__ } = this.context._documentProps
|
||||
let { buildStats, assetPrefix } = __NEXT_DATA__
|
||||
const hash = buildStats ? buildStats[filename].hash : '-'
|
||||
let { buildStats, assetPrefix, buildId } = __NEXT_DATA__
|
||||
const hash = buildStats ? buildStats[filename].hash : buildId
|
||||
|
||||
return (
|
||||
<script
|
||||
|
|
|
@ -233,7 +233,7 @@ export default class Server {
|
|||
res.setHeader('X-Powered-By', `Next.js ${pkg.version}`)
|
||||
}
|
||||
const html = await this.renderToHTML(req, res, pathname, query)
|
||||
return sendHTML(req, res, html, req.method)
|
||||
return sendHTML(req, res, html, req.method, this.renderOpts)
|
||||
}
|
||||
|
||||
async renderToHTML (req, res, pathname, query) {
|
||||
|
@ -261,7 +261,7 @@ export default class Server {
|
|||
|
||||
async renderError (err, req, res, pathname, query) {
|
||||
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
|
||||
return sendHTML(req, res, html, req.method)
|
||||
return sendHTML(req, res, html, req.method, this.renderOpts)
|
||||
}
|
||||
|
||||
async renderErrorToHTML (err, req, res, pathname, query) {
|
||||
|
@ -343,6 +343,7 @@ export default class Server {
|
|||
|
||||
handleBuildHash (filename, hash, res) {
|
||||
if (this.dev) return
|
||||
|
||||
if (hash !== this.buildStats[filename].hash) {
|
||||
throw new Error(`Invalid Build File Hash(${hash}) for chunk: ${filename}`)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import ErrorDebug from '../lib/error-debug'
|
|||
|
||||
export async function render (req, res, pathname, query, opts) {
|
||||
const html = await renderToHTML(req, res, pathname, opts)
|
||||
sendHTML(req, res, html, req.method)
|
||||
sendHTML(req, res, html, req.method, opts)
|
||||
}
|
||||
|
||||
export function renderToHTML (req, res, pathname, query, opts) {
|
||||
|
@ -24,7 +24,7 @@ export function renderToHTML (req, res, pathname, query, opts) {
|
|||
|
||||
export async function renderError (err, req, res, pathname, query, opts) {
|
||||
const html = await renderErrorToHTML(err, req, res, query, opts)
|
||||
sendHTML(req, res, html, req.method)
|
||||
sendHTML(req, res, html, req.method, opts)
|
||||
}
|
||||
|
||||
export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
|
||||
|
@ -87,6 +87,11 @@ async function doRender (req, res, pathname, query, {
|
|||
}
|
||||
|
||||
const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage })
|
||||
// While developing, we should not cache any assets.
|
||||
// So, we use a different buildId for each page load.
|
||||
// With that we can ensure, we have unique URL for assets per every page load.
|
||||
// So, it'll prevent issues like this: https://git.io/vHLtb
|
||||
const devBuildId = Date.now()
|
||||
|
||||
if (res.finished) return
|
||||
|
||||
|
@ -96,7 +101,7 @@ async function doRender (req, res, pathname, query, {
|
|||
props,
|
||||
pathname,
|
||||
query,
|
||||
buildId,
|
||||
buildId: dev ? devBuildId : buildId,
|
||||
buildStats,
|
||||
assetPrefix,
|
||||
err: (err) ? serializeError(dev, err) : null
|
||||
|
@ -156,7 +161,7 @@ export async function renderScriptError (req, res, page, error, customFields, op
|
|||
`)
|
||||
}
|
||||
|
||||
export function sendHTML (req, res, html, method) {
|
||||
export function sendHTML (req, res, html, method, { dev }) {
|
||||
if (res.finished) return
|
||||
const etag = generateETag(html)
|
||||
|
||||
|
@ -166,6 +171,12 @@ export function sendHTML (req, res, html, method) {
|
|||
return
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
// In dev, we should not cache pages for any reason.
|
||||
// That's why we do this.
|
||||
res.setHeader('Cache-Control', 'no-store, must-revalidate')
|
||||
}
|
||||
|
||||
res.setHeader('ETag', etag)
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.setHeader('Content-Length', Buffer.byteLength(html))
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* global describe, test, expect */
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
export default function (context) {
|
||||
describe('Misc', () => {
|
||||
|
@ -13,14 +12,5 @@ export default function (context) {
|
|||
const html = await context.app.renderToHTML({}, res, '/finish-response', {})
|
||||
expect(html).toBeFalsy()
|
||||
})
|
||||
|
||||
test('allow etag header support', async () => {
|
||||
const url = `http://localhost:${context.appPort}/stateless`
|
||||
const etag = (await fetch(url)).headers.get('ETag')
|
||||
|
||||
const headers = { 'If-None-Match': etag }
|
||||
const res2 = await fetch(url, { headers })
|
||||
expect(res2.status).toBe(304)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
renderViaHTTP
|
||||
} from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
const appDir = join(__dirname, '../')
|
||||
let appPort
|
||||
|
@ -35,6 +36,15 @@ describe('Production Usage', () => {
|
|||
const html = await renderViaHTTP(appPort, '/')
|
||||
expect(html).toMatch(/Hello World/)
|
||||
})
|
||||
|
||||
it('should allow etag header support', async () => {
|
||||
const url = `http://localhost:${appPort}/`
|
||||
const etag = (await fetch(url)).headers.get('ETag')
|
||||
|
||||
const headers = { 'If-None-Match': etag }
|
||||
const res2 = await fetch(url, { headers })
|
||||
expect(res2.status).toBe(304)
|
||||
})
|
||||
})
|
||||
|
||||
describe('With navigation', () => {
|
||||
|
|
Loading…
Reference in a new issue