1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Specify a different build directory for #1513 (#1599)

* Update references to `.next`

* Remove console logs and extraneous semi colons

* Remove lint errors

* Update references to .next and update docs

* Update options from nested to flat with `distDir`

* Add integration tests, and update `.gitignore`

* Rename integration folder to dist-dir to match standards
This commit is contained in:
alex newman 2017-04-06 11:09:26 +01:00 committed by Arunoda Susiripala
parent 12a7610d9a
commit 9347c8bdd0
15 changed files with 128 additions and 34 deletions

2
.gitignore vendored
View file

@ -11,3 +11,5 @@ npm-debug.log
# coverage # coverage
.nyc_output .nyc_output
coverage coverage
.DS_Store

View file

@ -22,8 +22,9 @@ if (argv.help) {
Usage Usage
$ next build <dir> $ next build <dir>
<dir> represents where the compiled .next folder should go. <dir> represents where the compiled dist folder should go.
If no directory is provided, .next will be created in the current directory If no directory is provided, the dist folder will be created in the current directory.
You can set a custom folder in config https://github.com/zeit/next.js#custom-configuration, otherwise it will be created inside '.next'
`) `)
process.exit(0) process.exit(0)
} }

View file

@ -29,8 +29,9 @@ if (argv.help) {
Usage Usage
$ next dev <dir> -p <port number> $ next dev <dir> -p <port number>
<dir> represents where the compiled .next folder should go. <dir> represents where the compiled folder should go.
If no directory is provided, .next will be created in the current directory If no directory is provided, the folder will be created in the current directory.
You can set a custom folder in config https://github.com/zeit/next.js#custom-configuration.
Options Options
--port, -p A port number on which to start the application --port, -p A port number on which to start the application

View file

@ -4,6 +4,7 @@ import { resolve } from 'path'
import parseArgs from 'minimist' import parseArgs from 'minimist'
import Server from '../server' import Server from '../server'
import { existsSync } from 'fs' import { existsSync } from 'fs'
import getConfig from '../server/config'
process.env.NODE_ENV = process.env.NODE_ENV || 'production' process.env.NODE_ENV = process.env.NODE_ENV || 'production'
@ -32,9 +33,10 @@ if (argv.help) {
Usage Usage
$ next start <dir> -p <port> $ next start <dir> -p <port>
<dir> is the directory that contains the compiled .next folder <dir> is the directory that contains the compiled dist folder
created by running \`next build\`. created by running \`next build\`.
If no directory is provided, the current directory will be assumed. If no directory is provided, the current directory will be assumed.
You can set a custom dist folder in config https://github.com/zeit/next.js#custom-configuration
Options Options
--port, -p A port number on which to start the application --port, -p A port number on which to start the application
@ -45,11 +47,12 @@ if (argv.help) {
} }
const dir = resolve(argv._[0] || '.') const dir = resolve(argv._[0] || '.')
const dist = getConfig(dir).distDir
const srv = new Server({ dir }) const srv = new Server({ dir })
if (!existsSync(resolve(dir, '.next', 'BUILD_ID'))) { if (!existsSync(resolve(dir, dist, 'BUILD_ID'))) {
console.error(`> Could not find a valid build in the '.next' directory! Try building your app with 'next build' before starting the server.`) console.error(`> Could not find a valid build in the '${dist}' directory! Try building your app with 'next build' before starting the server.`)
process.exit(1) process.exit(1)
} }

View file

@ -644,6 +644,17 @@ module.exports = {
} }
``` ```
#### Setting a custom build directory
You can specify a name to use for a custom build directory. For example, the following config will create a `build` folder instead of a `.next` folder. If no configuration is specified then next will create a `.next` folder.
```javascript
// next.config.js
module.exports = {
distDir: 'build'
}
```
### Customizing webpack config ### Customizing webpack config
In order to extend our usage of `webpack`, you can define a function that extends its config via `next.config.js`. In order to extend our usage of `webpack`, you can define a function that extends its config via `next.config.js`.
@ -718,7 +729,7 @@ Then run `now` and enjoy!
Next.js can be deployed to other hosting solutions too. Please have a look at the ['Deployment'](https://github.com/zeit/next.js/wiki/Deployment) section of the wiki. Next.js can be deployed to other hosting solutions too. Please have a look at the ['Deployment'](https://github.com/zeit/next.js/wiki/Deployment) section of the wiki.
Note: we recommend putting `.next` in `.npmignore` or `.gitignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy (and obviously exclude `.next`) Note: we recommend putting `.next`, or your custom dist folder (Please have a look at ['Custom Config'](You can set a custom folder in config https://github.com/zeit/next.js#custom-configuration.)), in `.npmignore` or `.gitignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy (and obviously exclude `.next` or your custom dist folder)
## FAQ ## FAQ

View file

@ -1,6 +1,8 @@
import { resolve } from 'path' import { resolve } from 'path'
import del from 'del' import del from 'del'
import getConfig from '../config'
export default function clean (dir) { export default function clean (dir) {
return del(resolve(dir, '.next')) const dist = getConfig(dir).distDir
return del(resolve(dir, dist))
} }

View file

@ -1,5 +1,6 @@
import { tmpdir } from 'os' import { tmpdir } from 'os'
import { join } from 'path' import { join } from 'path'
import getConfig from '../config'
import fs from 'mz/fs' import fs from 'mz/fs'
import uuid from 'uuid' import uuid from 'uuid'
import del from 'del' import del from 'del'
@ -13,8 +14,10 @@ export default async function build (dir) {
try { try {
await runCompiler(compiler) await runCompiler(compiler)
await writeBuildStats(buildDir)
await writeBuildId(buildDir) // Pass in both the buildDir and the dir to retrieve config
await writeBuildStats(buildDir, dir)
await writeBuildId(buildDir, dir)
} catch (err) { } catch (err) {
console.error(`> Failed to build on ${buildDir}`) console.error(`> Failed to build on ${buildDir}`)
throw err throw err
@ -45,22 +48,24 @@ function runCompiler (compiler) {
}) })
} }
async function writeBuildStats (dir) { async function writeBuildStats (buildDir, dir) {
const dist = getConfig(dir).distDir
// Here we can't use hashes in webpack chunks. // Here we can't use hashes in webpack chunks.
// That's because the "app.js" is not tied to a chunk. // That's because the "app.js" is not tied to a chunk.
// It's created by merging a few assets. (commons.js and main.js) // It's created by merging a few assets. (commons.js and main.js)
// So, we need to generate the hash ourself. // So, we need to generate the hash ourself.
const assetHashMap = { const assetHashMap = {
'app.js': { 'app.js': {
hash: await md5File(join(dir, '.next', 'app.js')) hash: await md5File(join(buildDir, dist, 'app.js'))
} }
} }
const buildStatsPath = join(dir, '.next', 'build-stats.json') const buildStatsPath = join(buildDir, dist, 'build-stats.json')
await fs.writeFile(buildStatsPath, JSON.stringify(assetHashMap), 'utf8') await fs.writeFile(buildStatsPath, JSON.stringify(assetHashMap), 'utf8')
} }
async function writeBuildId (dir) { async function writeBuildId (buildDir, dir) {
const buildIdPath = join(dir, '.next', 'BUILD_ID') const dist = getConfig(dir).distDir
const buildIdPath = join(buildDir, dist, 'BUILD_ID')
const buildId = uuid.v4() const buildId = uuid.v4()
await fs.writeFile(buildIdPath, buildId, 'utf8') await fs.writeFile(buildIdPath, buildId, 'utf8')
} }

View file

@ -1,10 +1,13 @@
import mv from 'mv' import mv from 'mv'
import { join } from 'path' import { join } from 'path'
import getConfig from '../config'
export default async function replaceCurrentBuild (dir, buildDir) { export default async function replaceCurrentBuild (dir, buildDir) {
const _dir = join(dir, '.next') const dist = getConfig(dir).distDir
const _buildDir = join(buildDir, '.next') const buildDist = getConfig(buildDir).distDir
const oldDir = join(buildDir, '.next.old') const _dir = join(dir, dist)
const _buildDir = join(buildDir, dist)
const oldDir = join(buildDir, `${buildDist}.old`)
try { try {
await move(_dir, oldDir) await move(_dir, oldDir)

View file

@ -265,7 +265,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false,
context: dir, context: dir,
entry, entry,
output: { output: {
path: join(buildDir || dir, '.next'), path: join(buildDir || dir, config.distDir),
filename: '[name]', filename: '[name]',
libraryTarget: 'commonjs2', libraryTarget: 'commonjs2',
publicPath: '/_webpack/', publicPath: '/_webpack/',

View file

@ -5,7 +5,8 @@ const cache = new Map()
const defaultConfig = { const defaultConfig = {
webpack: null, webpack: null,
poweredByHeader: true poweredByHeader: true,
distDir: '.next'
} }
export default function getConfig (dir) { export default function getConfig (dir) {

View file

@ -27,7 +27,8 @@ export default class Server {
this.hotReloader = dev ? new HotReloader(this.dir, { quiet }) : null this.hotReloader = dev ? new HotReloader(this.dir, { quiet }) : null
this.http = null this.http = null
this.config = getConfig(this.dir) this.config = getConfig(this.dir)
this.buildStats = !dev ? require(join(this.dir, '.next', 'build-stats.json')) : null this.dist = this.config.distDir
this.buildStats = !dev ? require(join(this.dir, this.dist, 'build-stats.json')) : null
this.buildId = !dev ? this.readBuildId() : '-' this.buildId = !dev ? this.readBuildId() : '-'
this.renderOpts = { this.renderOpts = {
dev, dev,
@ -92,25 +93,25 @@ export default class Server {
'/_next/:hash/manifest.js': async (req, res, params) => { '/_next/:hash/manifest.js': async (req, res, params) => {
this.handleBuildHash('manifest.js', params.hash, res) this.handleBuildHash('manifest.js', params.hash, res)
const p = join(this.dir, '.next/manifest.js') const p = join(this.dir, `${this.dist}/manifest.js`)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
'/_next/:hash/main.js': async (req, res, params) => { '/_next/:hash/main.js': async (req, res, params) => {
this.handleBuildHash('main.js', params.hash, res) this.handleBuildHash('main.js', params.hash, res)
const p = join(this.dir, '.next/main.js') const p = join(this.dir, `${this.dist}/main.js`)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
'/_next/:hash/commons.js': async (req, res, params) => { '/_next/:hash/commons.js': async (req, res, params) => {
this.handleBuildHash('commons.js', params.hash, res) this.handleBuildHash('commons.js', params.hash, res)
const p = join(this.dir, '.next/commons.js') const p = join(this.dir, `${this.dist}/commons.js`)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
'/_next/:hash/app.js': async (req, res, params) => { '/_next/:hash/app.js': async (req, res, params) => {
this.handleBuildHash('app.js', params.hash, res) this.handleBuildHash('app.js', params.hash, res)
const p = join(this.dir, '.next/app.js') const p = join(this.dir, `${this.dist}/app.js`)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
@ -291,7 +292,7 @@ export default class Server {
} }
readBuildId () { readBuildId () {
const buildIdPath = join(this.dir, '.next', 'BUILD_ID') const buildIdPath = join(this.dir, this.dist, 'BUILD_ID')
const buildId = fs.readFileSync(buildIdPath, 'utf8') const buildId = fs.readFileSync(buildIdPath, 'utf8')
return buildId.trim() return buildId.trim()
} }
@ -312,7 +313,7 @@ export default class Server {
const errors = this.hotReloader.getCompilationErrors() const errors = this.hotReloader.getCompilationErrors()
if (!errors.size) return if (!errors.size) return
const id = join(this.dir, '.next', 'bundles', 'pages', page) const id = join(this.dir, this.dist, 'bundles', 'pages', page)
const p = resolveFromList(id, errors.keys()) const p = resolveFromList(id, errors.keys())
if (p) return errors.get(p)[0] if (p) return errors.get(p)[0]
} }

View file

@ -3,6 +3,7 @@ import { createElement } from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server' import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import send from 'send' import send from 'send'
import requireModule from './require' import requireModule from './require'
import getConfig from './config'
import resolvePath from './resolve' import resolvePath from './resolve'
import readPage from './read-page' import readPage from './read-page'
import { Router } from '../lib/router' import { Router } from '../lib/router'
@ -43,9 +44,11 @@ async function doRender (req, res, pathname, query, {
await ensurePage(page, { dir, hotReloader }) await ensurePage(page, { dir, hotReloader })
const dist = getConfig(dir).distDir
let [Component, Document] = await Promise.all([ let [Component, Document] = await Promise.all([
requireModule(join(dir, '.next', 'dist', 'pages', page)), requireModule(join(dir, dist, 'dist', 'pages', page)),
requireModule(join(dir, '.next', 'dist', 'pages', '_document')) requireModule(join(dir, dist, 'dist', 'pages', '_document'))
]) ])
Component = Component.default || Component Component = Component.default || Component
Document = Document.default || Document Document = Document.default || Document
@ -57,8 +60,8 @@ async function doRender (req, res, pathname, query, {
errorComponent errorComponent
] = await Promise.all([ ] = await Promise.all([
loadGetInitialProps(Component, ctx), loadGetInitialProps(Component, ctx),
readPage(join(dir, '.next', 'bundles', 'pages', page)), readPage(join(dir, dist, 'bundles', 'pages', page)),
readPage(join(dir, '.next', 'bundles', 'pages', '_error')) readPage(join(dir, dist, 'bundles', 'pages', '_error'))
]) ])
// the response might be finshed on the getinitialprops call // the response might be finshed on the getinitialprops call
@ -113,13 +116,15 @@ async function doRender (req, res, pathname, query, {
} }
export async function renderJSON (req, res, page, { dir = process.cwd(), hotReloader } = {}) { export async function renderJSON (req, res, page, { dir = process.cwd(), hotReloader } = {}) {
const dist = getConfig(dir).distDir
await ensurePage(page, { dir, hotReloader }) await ensurePage(page, { dir, hotReloader })
const pagePath = await resolvePath(join(dir, '.next', 'bundles', 'pages', page)) const pagePath = await resolvePath(join(dir, dist, 'bundles', 'pages', page))
return serveStatic(req, res, pagePath) return serveStatic(req, res, pagePath)
} }
export async function renderErrorJSON (err, req, res, { dir = process.cwd(), dev = false } = {}) { export async function renderErrorJSON (err, req, res, { dir = process.cwd(), dev = false } = {}) {
const component = await readPage(join(dir, '.next', 'bundles', 'pages', '_error')) const dist = getConfig(dir).distDir
const component = await readPage(join(dir, dist, 'bundles', 'pages', '_error'))
sendJSON(res, { sendJSON(res, {
component, component,

View file

@ -0,0 +1,7 @@
module.exports = {
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60
},
distDir: 'dist'
}

View file

@ -0,0 +1,3 @@
export default () => (
<div>Hello World</div>
)

View file

@ -0,0 +1,49 @@
/* global jasmine, describe, it, expect, beforeAll, afterAll */
import { join } from 'path'
import { existsSync } from 'fs'
import {
nextServer,
nextBuild,
startApp,
stopApp,
renderViaHTTP
} from 'next-test-utils'
const appDir = join(__dirname, '../')
let appPort
let server
let app
jasmine.DEFAULT_TIMEOUT_INTERVAL = 40000
describe('Production Usage', () => {
beforeAll(async () => {
await nextBuild(appDir)
app = nextServer({
dir: join(__dirname, '../'),
dev: false,
quiet: true
})
server = await startApp(app)
appPort = server.address().port
})
afterAll(() => stopApp(server))
describe('With basic usage', () => {
it('should render the page', async () => {
const html = await renderViaHTTP(appPort, '/')
expect(html).toMatch(/Hello World/)
})
})
describe('File locations', () => {
it('should build the app within the given `dist` directory', () => {
expect(existsSync(join(__dirname, '/../dist/app.js'))).toBeTruthy()
})
it('should not build the app within the default `.next` directory', () => {
expect(existsSync(join(__dirname, '/../.next/app.js'))).toBeFalsy()
})
})
})