Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement "Immutable build artifacts" feature #745

Merged
merged 5 commits into from
Jan 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/prefetch.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* global __NEXT_DATA__ */

import React from 'react'
import Link, { isLocal } from './link'
import { parse as urlParse } from 'url'
Expand Down Expand Up @@ -108,7 +110,7 @@ if (hasServiceWorkerSupport()) {

function getPrefetchUrl (href) {
let { pathname } = urlParse(href)
const url = `/_next/pages${pathname}`
const url = `/_next/${__NEXT_DATA__.buildId}/pages${pathname}`

return url
}
Expand Down
4 changes: 3 additions & 1 deletion lib/router/router.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* global __NEXT_DATA__ */

import { parse, format } from 'url'
import evalScript from '../eval-script'
import shallowEquals from '../shallow-equals'
Expand Down Expand Up @@ -210,7 +212,7 @@ export default class Router extends EventEmitter {
}
}

const url = `/_next/pages${route}`
const url = `/_next/${__NEXT_DATA__.buildId}/pages${route}`
const xhr = loadComponent(url, (err, data) => {
if (err) return reject(err)
resolve({
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"strip-ansi": "3.0.1",
"styled-jsx": "0.4.1",
"url": "0.11.0",
"uuid": "3.0.1",
"webpack": "2.2.0-rc.3",
"webpack-dev-middleware": "1.9.0",
"webpack-hot-middleware": "2.15.0",
Expand Down
10 changes: 10 additions & 0 deletions server/build/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import fs from 'mz/fs'
import uuid from 'uuid'
import path from 'path'
import webpack from './webpack'
import clean from './clean'
import gzipAssets from './gzip'
Expand All @@ -10,6 +13,7 @@ export default async function build (dir) {

await runCompiler(compiler)
await gzipAssets(dir)
await writeBuildId(dir)
}

function runCompiler (compiler) {
Expand All @@ -29,3 +33,9 @@ function runCompiler (compiler) {
})
})
}

async function writeBuildId (dir) {
const buildIdPath = path.resolve(dir, '.next', 'BUILD_ID')
const buildId = uuid.v4()
await fs.writeFile(buildIdPath, buildId, 'utf8')
}
7 changes: 4 additions & 3 deletions server/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ export class NextScript extends Component {
}

render () {
const { staticMarkup } = this.context._documentProps
const { staticMarkup, __NEXT_DATA__ } = this.context._documentProps
let { buildId } = __NEXT_DATA__

return <div>
{ staticMarkup ? null : <script type='text/javascript' src='/_next/commons.js' /> }
{ staticMarkup ? null : <script type='text/javascript' src='/_next/main.js' /> }
{ staticMarkup ? null : <script type='text/javascript' src={`/_next/${buildId}/commons.js`} /> }
{ staticMarkup ? null : <script type='text/javascript' src={`/_next/${buildId}/main.js`} /> }
</div>
}
}
37 changes: 34 additions & 3 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { resolve, join } from 'path'
import { parse } from 'url'
import fs from 'mz/fs'
import http from 'http'
import {
renderToHTML,
Expand Down Expand Up @@ -46,6 +47,8 @@ export default class Server {
if (this.hotReloader) {
await this.hotReloader.start()
}

this.renderOpts.buildId = await this.readBuildId()
}

async close () {
Expand All @@ -60,17 +63,20 @@ export default class Server {
await serveStatic(req, res, p)
})

this.router.get('/_next/main.js', async (req, res, params) => {
this.router.get('/_next/:buildId/main.js', async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const p = join(this.dir, '.next/main.js')
await serveStaticWithGzip(req, res, p)
})

this.router.get('/_next/commons.js', async (req, res, params) => {
this.router.get('/_next/:buildId/commons.js', async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const p = join(this.dir, '.next/commons.js')
await serveStaticWithGzip(req, res, p)
})

this.router.get('/_next/pages/:path*', async (req, res, params) => {
this.router.get('/_next/:buildId/pages/:path*', async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const paths = params.path || ['index']
const pathname = `/${paths.join('/')}`
await this.renderJSON(req, res, pathname)
Expand Down Expand Up @@ -237,6 +243,31 @@ export default class Server {
}
}

async readBuildId () {
const buildIdPath = join(this.dir, '.next', 'BUILD_ID')
try {
const buildId = await fs.readFile(buildIdPath, 'utf8')
return buildId.trim()
} catch (err) {
if (err.code === 'ENOENT') {
return '-'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it difficult to create BUILD_ID on dev mode too? I think it should work the same on dev and production as much as possible otherwise you might find problems on production.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite not sure how to deal it with HMR and others. That's why I didn't do it.
Anyway, #786 has no relation to this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, it's a bit complicated but we can notify new buildId to client when finishing recompilation. Maybe we can fix it later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkzawa that's what I thought. May be after 2.0

} else {
throw err
}
}
}

handleBuildId (buildId, res) {
if (this.dev) return
if (buildId !== this.renderOpts.buildId) {
const errorMessage = 'Build id mismatch!' +
'Seems like the server and the client version of files are not the same.'
throw new Error(errorMessage)
}

res.setHeader('Cache-Control', 'max-age=365000000, immutable')
}

getCompilationError (page) {
if (!this.hotReloader) return

Expand Down
2 changes: 2 additions & 0 deletions server/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
async function doRender (req, res, pathname, query, {
err,
page,
buildId,
dir = process.cwd(),
dev = false,
staticMarkup = false
Expand Down Expand Up @@ -88,6 +89,7 @@ async function doRender (req, res, pathname, query, {
props,
pathname,
query,
buildId,
err: (err && dev) ? errorToJSON(err) : null
},
dev,
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -733,9 +733,9 @@ babel-plugin-transform-strict-mode@^6.18.0:
babel-runtime "^6.0.0"
babel-types "^6.18.0"

babel-preset-env@1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.1.6.tgz#83ce1402088e661cb5799e680d20c5a432b2873b"
babel-preset-env@1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.1.8.tgz#c46734c6233c3f87d177513773db3cf3c1758aaa"
dependencies:
babel-plugin-check-es2015-constants "^6.3.13"
babel-plugin-syntax-trailing-function-commas "^6.13.0"
Expand Down Expand Up @@ -5028,7 +5028,7 @@ util@^0.10.3, util@0.10.3:
dependencies:
inherits "2.0.1"

uuid@^3.0.0:
uuid, uuid@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"

Expand Down