1
0
Fork 0
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:
Arunoda Susiripala 2017-05-25 21:58:08 +05:30 committed by Tim Neutkens
parent 3c95f21d8c
commit 9121a9d22e
5 changed files with 32 additions and 20 deletions

View file

@ -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

View file

@ -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}`)
}

View file

@ -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))

View file

@ -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)
})
})
}

View file

@ -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', () => {