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

Clean up references to this.dir and this.dist everywhere (#4535)

This was spread around the server. Now it's set in one place and passed around.
This commit is contained in:
Tim Neutkens 2018-06-04 15:45:39 +02:00 committed by GitHub
parent 18676e0870
commit a7bb9175eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 68 deletions

View file

@ -6,3 +6,9 @@ export const PAGES_MANIFEST = 'pages-manifest.json'
export const BUILD_MANIFEST = 'build-manifest.json' export const BUILD_MANIFEST = 'build-manifest.json'
export const SERVER_DIRECTORY = 'server' export const SERVER_DIRECTORY = 'server'
export const CONFIG_FILE = 'next.config.js' export const CONFIG_FILE = 'next.config.js'
export const BUILD_ID_FILE = 'BUILD_ID'
export const BLOCKED_PAGES = [
'/_document',
'/_app',
'/_error'
]

View file

@ -3,7 +3,7 @@ import promisify from '../lib/promisify'
import fs from 'fs' import fs from 'fs'
import webpack from 'webpack' import webpack from 'webpack'
import loadConfig from '../config' import loadConfig from '../config'
import { PHASE_PRODUCTION_BUILD } from '../../lib/constants' import { PHASE_PRODUCTION_BUILD, BUILD_ID_FILE } from '../../lib/constants'
import getBaseWebpackConfig from './webpack' import getBaseWebpackConfig from './webpack'
const access = promisify(fs.access) const access = promisify(fs.access)
@ -12,6 +12,7 @@ const writeFile = promisify(fs.writeFile)
export default async function build (dir, conf = null) { export default async function build (dir, conf = null) {
const config = loadConfig(PHASE_PRODUCTION_BUILD, dir, conf) const config = loadConfig(PHASE_PRODUCTION_BUILD, dir, conf)
const buildId = await config.generateBuildId() // defaults to a uuid const buildId = await config.generateBuildId() // defaults to a uuid
const distDir = join(dir, config.distDir)
try { try {
await access(dir, (fs.constants || fs).W_OK) await access(dir, (fs.constants || fs).W_OK)
@ -28,7 +29,7 @@ export default async function build (dir, conf = null) {
await runCompiler(configs) await runCompiler(configs)
await writeBuildId(dir, buildId, config) await writeBuildId(distDir, buildId)
} catch (err) { } catch (err) {
console.error(`> Failed to build`) console.error(`> Failed to build`)
throw err throw err
@ -55,7 +56,7 @@ function runCompiler (compiler) {
}) })
} }
async function writeBuildId (dir, buildId, config) { async function writeBuildId (distDir, buildId) {
const buildIdPath = join(dir, config.distDir, 'BUILD_ID') const buildIdPath = join(distDir, BUILD_ID_FILE)
await writeFile(buildIdPath, buildId, 'utf8') await writeFile(buildIdPath, buildId, 'utf8')
} }

View file

@ -5,7 +5,7 @@ import walk from 'walk'
import { extname, resolve, join, dirname, sep } from 'path' import { extname, resolve, join, dirname, sep } from 'path'
import { existsSync, readFileSync, writeFileSync } from 'fs' import { existsSync, readFileSync, writeFileSync } from 'fs'
import loadConfig from './config' import loadConfig from './config'
import {PHASE_EXPORT, SERVER_DIRECTORY, PAGES_MANIFEST, CONFIG_FILE} from '../lib/constants' import {PHASE_EXPORT, SERVER_DIRECTORY, PAGES_MANIFEST, CONFIG_FILE, BUILD_ID_FILE} from '../lib/constants'
import { renderToHTML } from './render' import { renderToHTML } from './render'
import { getAvailableChunks } from './utils' import { getAvailableChunks } from './utils'
import { setAssetPrefix } from '../lib/asset' import { setAssetPrefix } from '../lib/asset'
@ -14,16 +14,16 @@ import * as envConfig from '../lib/runtime-config'
export default async function (dir, options, configuration) { export default async function (dir, options, configuration) {
dir = resolve(dir) dir = resolve(dir)
const nextConfig = configuration || loadConfig(PHASE_EXPORT, dir) const nextConfig = configuration || loadConfig(PHASE_EXPORT, dir)
const nextDir = join(dir, nextConfig.distDir) const distDir = join(dir, nextConfig.distDir)
log(`> using build directory: ${nextDir}`) log(`> using build directory: ${distDir}`)
if (!existsSync(nextDir)) { if (!existsSync(distDir)) {
throw new Error(`Build directory ${nextDir} does not exist. Make sure you run "next build" before running "next start" or "next export".`) throw new Error(`Build directory ${distDir} does not exist. Make sure you run "next build" before running "next start" or "next export".`)
} }
const buildId = readFileSync(join(nextDir, 'BUILD_ID'), 'utf8') const buildId = readFileSync(join(distDir, BUILD_ID_FILE), 'utf8')
const pagesManifest = require(join(nextDir, SERVER_DIRECTORY, PAGES_MANIFEST)) const pagesManifest = require(join(distDir, SERVER_DIRECTORY, PAGES_MANIFEST))
const pages = Object.keys(pagesManifest) const pages = Object.keys(pagesManifest)
const defaultPathMap = {} const defaultPathMap = {}
@ -52,26 +52,26 @@ export default async function (dir, options, configuration) {
} }
// Copy .next/static directory // Copy .next/static directory
if (existsSync(join(nextDir, 'static'))) { if (existsSync(join(distDir, 'static'))) {
log(' copying "static build" directory') log(' copying "static build" directory')
await cp( await cp(
join(nextDir, 'static'), join(distDir, 'static'),
join(outDir, '_next', 'static') join(outDir, '_next', 'static')
) )
} }
// Copy dynamic import chunks // Copy dynamic import chunks
if (existsSync(join(nextDir, 'chunks'))) { if (existsSync(join(distDir, 'chunks'))) {
log(' copying dynamic import chunks') log(' copying dynamic import chunks')
await mkdirp(join(outDir, '_next', 'webpack')) await mkdirp(join(outDir, '_next', 'webpack'))
await cp( await cp(
join(nextDir, 'chunks'), join(distDir, 'chunks'),
join(outDir, '_next', 'webpack', 'chunks') join(outDir, '_next', 'webpack', 'chunks')
) )
} }
await copyPages(nextDir, outDir, buildId) await copyPages(distDir, outDir, buildId)
// Get the exportPathMap from the config file // Get the exportPathMap from the config file
if (typeof nextConfig.exportPathMap !== 'function') { if (typeof nextConfig.exportPathMap !== 'function') {
@ -84,14 +84,14 @@ export default async function (dir, options, configuration) {
// Start the rendering process // Start the rendering process
const renderOpts = { const renderOpts = {
dir, dir,
dist: nextConfig.distDir,
buildId, buildId,
nextExport: true, nextExport: true,
assetPrefix: nextConfig.assetPrefix.replace(/\/$/, ''), assetPrefix: nextConfig.assetPrefix.replace(/\/$/, ''),
distDir,
dev: false, dev: false,
staticMarkup: false, staticMarkup: false,
hotReloader: null, hotReloader: null,
availableChunks: getAvailableChunks(dir, nextConfig.distDir) availableChunks: getAvailableChunks(distDir)
} }
const {serverRuntimeConfig, publicRuntimeConfig} = nextConfig const {serverRuntimeConfig, publicRuntimeConfig} = nextConfig
@ -152,10 +152,10 @@ export default async function (dir, options, configuration) {
} }
} }
function copyPages (nextDir, outDir, buildId) { function copyPages (distDir, outDir, buildId) {
// TODO: do some proper error handling // TODO: do some proper error handling
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const nextBundlesDir = join(nextDir, 'bundles', 'pages') const nextBundlesDir = join(distDir, 'bundles', 'pages')
const walker = walk.walk(nextBundlesDir, { followLinks: false }) const walker = walk.walk(nextBundlesDir, { followLinks: false })
walker.on('file', (root, stat, next) => { walker.on('file', (root, stat, next) => {

View file

@ -15,7 +15,7 @@ import {
import Router from './router' import Router from './router'
import { getAvailableChunks, isInternalUrl } from './utils' import { getAvailableChunks, isInternalUrl } from './utils'
import loadConfig from './config' import loadConfig from './config'
import {PHASE_PRODUCTION_SERVER, PHASE_DEVELOPMENT_SERVER} from '../lib/constants' import {PHASE_PRODUCTION_SERVER, PHASE_DEVELOPMENT_SERVER, BLOCKED_PAGES, BUILD_ID_FILE} from '../lib/constants'
import * as asset from '../lib/asset' import * as asset from '../lib/asset'
import * as envConfig from '../lib/runtime-config' import * as envConfig from '../lib/runtime-config'
import { isResSent } from '../lib/utils' import { isResSent } from '../lib/utils'
@ -26,12 +26,6 @@ import pkg from '../../package'
const access = promisify(fs.access) const access = promisify(fs.access)
const blockedPages = {
'/_document': true,
'/_app': true,
'/_error': true
}
export default class Server { export default class Server {
constructor ({ dir = '.', dev = false, staticMarkup = false, quiet = false, conf = null } = {}) { constructor ({ dir = '.', dev = false, staticMarkup = false, quiet = false, conf = null } = {}) {
this.dir = resolve(dir) this.dir = resolve(dir)
@ -41,7 +35,7 @@ export default class Server {
this.http = null this.http = null
const phase = dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER const phase = dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER
this.nextConfig = loadConfig(phase, this.dir, conf) this.nextConfig = loadConfig(phase, this.dir, conf)
this.dist = this.nextConfig.distDir this.distDir = join(dir, this.nextConfig.distDir)
this.hotReloader = dev ? this.getHotReloader(this.dir, { quiet, config: this.nextConfig }) : null this.hotReloader = dev ? this.getHotReloader(this.dir, { quiet, config: this.nextConfig }) : null
@ -49,19 +43,18 @@ export default class Server {
// publicRuntimeConfig gets it's default in client/index.js // publicRuntimeConfig gets it's default in client/index.js
const {serverRuntimeConfig = {}, publicRuntimeConfig, assetPrefix, generateEtags} = this.nextConfig const {serverRuntimeConfig = {}, publicRuntimeConfig, assetPrefix, generateEtags} = this.nextConfig
if (!dev && !fs.existsSync(resolve(dir, this.dist, 'BUILD_ID'))) { if (!dev && !fs.existsSync(resolve(this.distDir, BUILD_ID_FILE))) {
console.error(`> Could not find a valid build in the '${this.dist}' directory! Try building your app with 'next build' before starting the server.`) console.error(`> Could not find a valid build in the '${this.distDir}' directory! Try building your app with 'next build' before starting the server.`)
process.exit(1) process.exit(1)
} }
this.buildId = !dev ? this.readBuildId() : '-' this.buildId = !dev ? this.readBuildId() : '-'
this.renderOpts = { this.renderOpts = {
dev, dev,
staticMarkup, staticMarkup,
dir: this.dir, distDir: this.distDir,
dist: this.dist,
hotReloader: this.hotReloader, hotReloader: this.hotReloader,
buildId: this.buildId, buildId: this.buildId,
availableChunks: dev ? {} : getAvailableChunks(this.dir, this.dist), availableChunks: dev ? {} : getAvailableChunks(this.distDir),
generateEtags generateEtags
} }
@ -159,13 +152,13 @@ export default class Server {
if (!this.dev) { if (!this.dev) {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable') res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
} }
const p = join(this.dir, this.dist, 'chunks', params.name) const p = join(this.distDir, 'chunks', params.name)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
// This is to support, webpack dynamic import support with HMR // This is to support, webpack dynamic import support with HMR
'/_next/webpack/:id': async (req, res, params) => { '/_next/webpack/:id': async (req, res, params) => {
const p = join(this.dir, this.dist, 'chunks', params.id) const p = join(this.distDir, 'chunks', params.id)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
@ -181,7 +174,7 @@ export default class Server {
} }
} }
const path = join(this.dir, this.dist, 'bundles', 'pages', `${page}.js.map`) const path = join(this.distDir, 'bundles', 'pages', `${page}.js.map`)
await serveStatic(req, res, path) await serveStatic(req, res, path)
}, },
@ -207,7 +200,7 @@ export default class Server {
} }
} }
const p = join(this.dir, this.dist, 'bundles', 'pages', `${page}.js`) const p = join(this.distDir, 'bundles', 'pages', `${page}.js`)
// [production] If the page is not exists, we need to send a proper Next.js style 404 // [production] If the page is not exists, we need to send a proper Next.js style 404
// Otherwise, it'll affect the multi-zones feature. // Otherwise, it'll affect the multi-zones feature.
@ -230,7 +223,7 @@ export default class Server {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable') res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
} }
} }
const p = join(this.dir, this.dist, 'static', ...(params.path || [])) const p = join(this.distDir, 'static', ...(params.path || []))
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
@ -315,7 +308,7 @@ export default class Server {
return this.handleRequest(req, res, parsedUrl) return this.handleRequest(req, res, parsedUrl)
} }
if (blockedPages[pathname]) { if (BLOCKED_PAGES.indexOf(pathname) !== -1) {
return await this.render404(req, res, parsedUrl) return await this.render404(req, res, parsedUrl)
} }
@ -408,7 +401,7 @@ export default class Server {
isServeableUrl (path) { isServeableUrl (path) {
const resolved = resolve(path) const resolved = resolve(path)
if ( if (
resolved.indexOf(join(this.dir, this.dist) + sep) !== 0 && resolved.indexOf(join(this.distDir) + sep) !== 0 &&
resolved.indexOf(join(this.dir, 'static') + sep) !== 0 resolved.indexOf(join(this.dir, 'static') + sep) !== 0
) { ) {
// Seems like the user is trying to traverse the filesystem. // Seems like the user is trying to traverse the filesystem.
@ -419,7 +412,7 @@ export default class Server {
} }
readBuildId () { readBuildId () {
const buildIdPath = join(this.dir, this.dist, 'BUILD_ID') const buildIdPath = join(this.distDir, BUILD_ID_FILE)
const buildId = fs.readFileSync(buildIdPath, 'utf8') const buildId = fs.readFileSync(buildIdPath, 'utf8')
return buildId.trim() return buildId.trim()
} }

View file

@ -42,8 +42,8 @@ async function doRender (req, res, pathname, query, {
assetPrefix, assetPrefix,
runtimeConfig, runtimeConfig,
availableChunks, availableChunks,
dist, distDir,
dir = process.cwd(), dir,
dev = false, dev = false,
staticMarkup = false, staticMarkup = false,
nextExport = false nextExport = false
@ -56,11 +56,11 @@ async function doRender (req, res, pathname, query, {
await ensurePage(page, { dir, hotReloader }) await ensurePage(page, { dir, hotReloader })
} }
const documentPath = join(dir, dist, SERVER_DIRECTORY, 'bundles', 'pages', '_document') const documentPath = join(distDir, SERVER_DIRECTORY, 'bundles', 'pages', '_document')
const appPath = join(dir, dist, SERVER_DIRECTORY, 'bundles', 'pages', '_app') const appPath = join(distDir, SERVER_DIRECTORY, 'bundles', 'pages', '_app')
const buildManifest = require(join(dir, dist, BUILD_MANIFEST)) const buildManifest = require(join(distDir, BUILD_MANIFEST))
let [Component, Document, App] = await Promise.all([ let [Component, Document, App] = await Promise.all([
requirePage(page, {dir, dist}), requirePage(page, {distDir}),
require(documentPath), require(documentPath),
require(appPath) require(appPath)
]) ])
@ -105,7 +105,7 @@ async function doRender (req, res, pathname, query, {
} finally { } finally {
head = Head.rewind() || defaultHead() head = Head.rewind() || defaultHead()
} }
const chunks = loadChunks({ dev, dir, dist, availableChunks }) const chunks = loadChunks({ dev, distDir, availableChunks })
return { html, head, errorHtml, chunks, buildManifest } return { html, head, errorHtml, chunks, buildManifest }
} }
@ -230,7 +230,7 @@ async function ensurePage (page, { dir, hotReloader }) {
await hotReloader.ensurePage(page) await hotReloader.ensurePage(page)
} }
function loadChunks ({ dev, dir, dist, availableChunks }) { function loadChunks ({ dev, distDir, availableChunks }) {
const flushedChunks = flushChunks() const flushedChunks = flushChunks()
const response = { const response = {
names: [], names: [],
@ -238,7 +238,7 @@ function loadChunks ({ dev, dir, dist, availableChunks }) {
} }
if (dev) { if (dev) {
availableChunks = getAvailableChunks(dir, dist) availableChunks = getAvailableChunks(distDir)
} }
for (var chunk of flushedChunks) { for (var chunk of flushedChunks) {

View file

@ -27,8 +27,8 @@ export function normalizePagePath (page) {
return page return page
} }
export function getPagePath (page, {dir, dist}) { export function getPagePath (page, {distDir}) {
const serverBuildPath = join(dir, dist, SERVER_DIRECTORY) const serverBuildPath = join(distDir, SERVER_DIRECTORY)
const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST)) const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST))
try { try {
@ -45,7 +45,7 @@ export function getPagePath (page, {dir, dist}) {
return join(serverBuildPath, pagesManifest[page]) return join(serverBuildPath, pagesManifest[page])
} }
export default async function requirePage (page, {dir, dist}) { export default async function requirePage (page, {distDir}) {
const pagePath = getPagePath(page, {dir, dist}) const pagePath = getPagePath(page, {distDir})
return require(pagePath) return require(pagePath)
} }

View file

@ -4,8 +4,8 @@ import { readdirSync, existsSync } from 'fs'
export const IS_BUNDLED_PAGE = /^bundles[/\\]pages.*\.js$/ export const IS_BUNDLED_PAGE = /^bundles[/\\]pages.*\.js$/
export const MATCH_ROUTE_NAME = /^bundles[/\\]pages[/\\](.*)\.js$/ export const MATCH_ROUTE_NAME = /^bundles[/\\]pages[/\\](.*)\.js$/
export function getAvailableChunks (dir, dist) { export function getAvailableChunks (distDir) {
const chunksDir = join(dir, dist, 'chunks') const chunksDir = join(distDir, 'chunks')
if (!existsSync(chunksDir)) return {} if (!existsSync(chunksDir)) return {}
const chunksMap = {} const chunksMap = {}

View file

@ -2,6 +2,7 @@
import { join } from 'path' import { join } from 'path'
import { existsSync } from 'fs' import { existsSync } from 'fs'
import {BUILD_ID_FILE} from 'next/constants'
import { import {
nextServer, nextServer,
nextBuild, nextBuild,
@ -39,10 +40,10 @@ describe('Production Usage', () => {
describe('File locations', () => { describe('File locations', () => {
it('should build the app within the given `dist` directory', () => { it('should build the app within the given `dist` directory', () => {
expect(existsSync(join(__dirname, '/../dist/BUILD_ID'))).toBeTruthy() expect(existsSync(join(__dirname, `/../dist/${BUILD_ID_FILE}`))).toBeTruthy()
}) })
it('should not build the app within the default `.next` directory', () => { it('should not build the app within the default `.next` directory', () => {
expect(existsSync(join(__dirname, '/../.next/BUILD_ID'))).toBeFalsy() expect(existsSync(join(__dirname, `/../.next/${BUILD_ID_FILE}`))).toBeFalsy()
}) })
}) })
}) })

View file

@ -5,7 +5,8 @@ import {SERVER_DIRECTORY} from 'next/constants'
import requirePage, {getPagePath, normalizePagePath, pageNotFoundError} from '../../dist/server/require' import requirePage, {getPagePath, normalizePagePath, pageNotFoundError} from '../../dist/server/require'
const sep = '/' const sep = '/'
const pathToBundles = join(__dirname, '_resolvedata', SERVER_DIRECTORY, 'bundles', 'pages') const distDir = join(__dirname, '_resolvedata')
const pathToBundles = join(distDir, SERVER_DIRECTORY, 'bundles', 'pages')
describe('pageNotFoundError', () => { describe('pageNotFoundError', () => {
it('Should throw error with ENOENT code', () => { it('Should throw error with ENOENT code', () => {
@ -41,39 +42,39 @@ describe('normalizePagePath', () => {
describe('getPagePath', () => { describe('getPagePath', () => {
it('Should append /index to the / page', () => { it('Should append /index to the / page', () => {
const pagePath = getPagePath('/', {dir: __dirname, dist: '_resolvedata'}) const pagePath = getPagePath('/', {distDir})
expect(pagePath).toBe(join(pathToBundles, `${sep}index.js`)) expect(pagePath).toBe(join(pathToBundles, `${sep}index.js`))
}) })
it('Should prepend / when a page does not have it', () => { it('Should prepend / when a page does not have it', () => {
const pagePath = getPagePath('_error', {dir: __dirname, dist: '_resolvedata'}) const pagePath = getPagePath('_error', {distDir})
expect(pagePath).toBe(join(pathToBundles, `${sep}_error.js`)) expect(pagePath).toBe(join(pathToBundles, `${sep}_error.js`))
}) })
it('Should throw with paths containing ../', () => { it('Should throw with paths containing ../', () => {
expect(() => getPagePath('/../../package.json', {dir: __dirname, dist: '_resolvedata'})).toThrow() expect(() => getPagePath('/../../package.json', {distDir})).toThrow()
}) })
}) })
describe('requirePage', () => { describe('requirePage', () => {
it('Should require /index.js when using /', async () => { it('Should require /index.js when using /', async () => {
const page = await requirePage('/', {dir: __dirname, dist: '_resolvedata'}) const page = await requirePage('/', {distDir})
expect(page.test).toBe('hello') expect(page.test).toBe('hello')
}) })
it('Should require /index.js when using /index', async () => { it('Should require /index.js when using /index', async () => {
const page = await requirePage('/index', {dir: __dirname, dist: '_resolvedata'}) const page = await requirePage('/index', {distDir})
expect(page.test).toBe('hello') expect(page.test).toBe('hello')
}) })
it('Should require /world.js when using /world', async () => { it('Should require /world.js when using /world', async () => {
const page = await requirePage('/world', {dir: __dirname, dist: '_resolvedata'}) const page = await requirePage('/world', {distDir})
expect(page.test).toBe('world') expect(page.test).toBe('world')
}) })
it('Should throw when using /../../test.js', async () => { it('Should throw when using /../../test.js', async () => {
try { try {
await requirePage('/../../test', {dir: __dirname, dist: '_resolvedata'}) await requirePage('/../../test', {distDir})
} catch (err) { } catch (err) {
expect(err.code).toBe('ENOENT') expect(err.code).toBe('ENOENT')
} }
@ -81,7 +82,7 @@ describe('requirePage', () => {
it('Should throw when using non existent pages like /non-existent.js', async () => { it('Should throw when using non existent pages like /non-existent.js', async () => {
try { try {
await requirePage('/non-existent', {dir: __dirname, dist: '_resolvedata'}) await requirePage('/non-existent', {distDir})
} catch (err) { } catch (err) {
expect(err.code).toBe('ENOENT') expect(err.code).toBe('ENOENT')
} }
@ -89,7 +90,7 @@ describe('requirePage', () => {
it('Should bubble up errors in the child component', async () => { it('Should bubble up errors in the child component', async () => {
try { try {
await requirePage('/non-existent-child', {dir: __dirname, dist: '_resolvedata'}) await requirePage('/non-existent-child', {distDir})
} catch (err) { } catch (err) {
expect(err.code).toBe('MODULE_NOT_FOUND') expect(err.code).toBe('MODULE_NOT_FOUND')
} }