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

Add src directory support #8735

Merged
merged 8 commits into from
Sep 24, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions errors/conflicting-public-file-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ One of your public files has the exact same path as a page file which is not sup
Rename either the public file or page file that is causing the conflict.

Example conflict between public file and page file

```
public/
hello
Expand All @@ -17,6 +18,7 @@ pages/
```

Non-conflicting public file and page file

```
public/
hello.txt
Expand Down
12 changes: 9 additions & 3 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
import getBaseWebpackConfig from './webpack-config'
import { getPageChunks } from './webpack/plugins/chunk-graph-plugin'
import { writeBuildId } from './write-build-id'
import { findPagesDir } from '../lib/find-pages-dir'
import createSpinner from './spinner'
import { PUBLIC_DIR_MIDDLEWARE_CONFLICT } from '../lib/constants'

Expand All @@ -65,8 +66,6 @@ export default async function build(dir: string, conf = null): Promise<void> {
)
}

await verifyTypeScriptSetup(dir)

let backgroundWork: (Promise<any> | undefined)[] = []
backgroundWork.push(
recordVersion({ cliCommand: 'build' }),
Expand All @@ -81,10 +80,15 @@ export default async function build(dir: string, conf = null): Promise<void> {
const { target } = config
const buildId = await generateBuildId(config.generateBuildId, nanoid)
const distDir = path.join(dir, config.distDir)
const pagesDir = path.join(dir, 'pages')
const publicDir = path.join(dir, 'public')
const pagesDir = findPagesDir(dir)
let publicFiles: string[] = []

await verifyTypeScriptSetup(dir, pagesDir)

console.log('Creating an optimized production build ...')
console.log()

if (config.experimental.publicDirectory) {
publicFiles = await recursiveReadDir(publicDir, /.*/)
}
Expand Down Expand Up @@ -147,6 +151,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
isServer: false,
config,
target,
pagesDir,
entrypoints: entrypoints.client,
}),
getBaseWebpackConfig(dir, {
Expand All @@ -155,6 +160,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
isServer: true,
config,
target,
pagesDir,
entrypoints: entrypoints.server,
}),
])
Expand Down
17 changes: 10 additions & 7 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,22 @@ const escapePathVariables = (value: any) => {
export default async function getBaseWebpackConfig(
dir: string,
{
dev = false,
isServer = false,
buildId,
config,
dev = false,
isServer = false,
pagesDir,
tracer,
target = 'server',
entrypoints,
tracer,
}: {
tracer?: any
dev?: boolean
isServer?: boolean
buildId: string
config: any
dev?: boolean
isServer?: boolean
pagesDir: string
target?: string
tracer?: any
entrypoints: WebpackEntrypoints
}
): Promise<webpack.Configuration> {
Expand All @@ -72,6 +74,7 @@ export default async function getBaseWebpackConfig(
isServer,
hasModern: !!config.experimental.modern,
distDir,
pagesDir,
cwd: dir,
cache: true,
},
Expand Down Expand Up @@ -151,7 +154,7 @@ export default async function getBaseWebpackConfig(
'next/config': 'next/dist/next-server/lib/runtime-config.js',
'next/dynamic': 'next/dist/next-server/lib/dynamic.js',
next: NEXT_PROJECT_ROOT,
[PAGES_DIR_ALIAS]: path.join(dir, 'pages'),
[PAGES_DIR_ALIAS]: pagesDir,
[DOT_NEXT_ALIAS]: distDir,
},
mainFields: isServer ? ['main', 'module'] : ['browser', 'module', 'main'],
Expand Down
7 changes: 4 additions & 3 deletions packages/next/build/webpack/loaders/next-babel-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ module.exports = babelLoader.custom(babel => {
const custom = {
isServer: opts.isServer,
isModern: opts.isModern,
pagesDir: opts.pagesDir,
hasModern: opts.hasModern
}
const filename = join(opts.cwd, 'noop.js')
Expand Down Expand Up @@ -86,19 +87,19 @@ module.exports = babelLoader.custom(babel => {
delete loader.distDir
delete loader.isModern
delete loader.hasModern
delete loader.pagesDir
return { loader, custom }
},
config (
cfg,
{
source,
customOptions: { isServer, isModern, hasModern }
customOptions: { isServer, isModern, hasModern, pagesDir }
}
) {
const { cwd } = cfg.options
const filename = this.resourcePath
const options = Object.assign({}, cfg.options)
const isPageFile = filename.startsWith(join(cwd, 'pages'))
const isPageFile = filename.startsWith(pagesDir)

if (cfg.hasFilesystemConfig()) {
for (const file of [cfg.babelrc, cfg.config]) {
Expand Down
14 changes: 0 additions & 14 deletions packages/next/cli/next-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,6 @@ const nextBuild: cliCommand = argv => {
printAndExit(`> No such directory exists as the project root: ${dir}`)
}

// Check if the pages directory exists
if (!existsSync(join(dir, 'pages'))) {
// Check one level down the tree to see if the pages directory might be there
if (existsSync(join(dir, '..', 'pages'))) {
printAndExit(
'> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?'
)
}

printAndExit(
"> Couldn't find a `pages` directory. Please create one under the project root"
)
}

build(dir)
.then(() => process.exit(0))
.catch(err => {
Expand Down
12 changes: 0 additions & 12 deletions packages/next/cli/next-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,6 @@ const nextDev: cliCommand = argv => {
printAndExit(`> No such directory exists as the project root: ${dir}`)
}

if (!existsSync(join(dir, 'pages'))) {
if (existsSync(join(dir, '..', 'pages'))) {
printAndExit(
'> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?'
)
}

printAndExit(
"> Couldn't find a `pages` directory. Please create one under the project root"
)
}

const port = args['--port'] || 3000
const appUrl = `http://${args['--hostname'] || 'localhost'}:${port}`

Expand Down
12 changes: 0 additions & 12 deletions packages/next/cli/next-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,6 @@ const nextExport: cliCommand = argv => {
printAndExit(`> No such directory exists as the project root: ${dir}`)
}

if (!existsSync(join(dir, 'pages'))) {
if (existsSync(join(dir, '..', 'pages'))) {
printAndExit(
'> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?'
)
}

printAndExit(
"> Couldn't find a `pages` directory. Please create one under the project root"
)
}

const options = {
silent: args['--silent'] || false,
threads: args['--threads'],
Expand Down
1 change: 0 additions & 1 deletion packages/next/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const NEXT_PROJECT_ROOT_NODE_MODULES = join(
NEXT_PROJECT_ROOT,
'node_modules'
)
export const DEFAULT_PAGES_DIR = join(NEXT_PROJECT_ROOT_DIST, 'pages')
export const NEXT_PROJECT_ROOT_DIST_CLIENT = join(
NEXT_PROJECT_ROOT_DIST,
'client'
Expand Down
31 changes: 31 additions & 0 deletions packages/next/lib/find-pages-dir.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import fs from 'fs'
import path from 'path'

const existsSync = (f: string): boolean => {
try {
fs.accessSync(f, fs.constants.F_OK)
return true
} catch (_) {
return false
}
}

export function findPagesDir(dir: string): string {
// prioritize ./pages over ./src/pages
let curDir = path.join(dir, 'pages')
if (existsSync(curDir)) return curDir

curDir = path.join(dir, 'src/pages')
if (existsSync(curDir)) return curDir

// Check one level down the tree to see if the pages directory might be there
ijjk marked this conversation as resolved.
Show resolved Hide resolved
if (existsSync(path.join(dir, '..', 'pages'))) {
throw new Error(
'> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?'
)
}

throw new Error(
"> Couldn't find a `pages` directory. Please create one under the project root"
)
}
9 changes: 6 additions & 3 deletions packages/next/lib/verifyTypeScriptSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function writeJson(fileName: string, object: object): Promise<void> {

async function hasTypeScript(dir: string): Promise<boolean> {
const typescriptFiles = await recursiveReadDir(
path.join(dir, 'pages'),
dir,
/.*\.(ts|tsx)$/,
/(node_modules|.*\.d\.ts)/
)
Expand Down Expand Up @@ -94,7 +94,10 @@ async function checkDependencies({
process.exit(1)
}

export async function verifyTypeScriptSetup(dir: string): Promise<void> {
export async function verifyTypeScriptSetup(
dir: string,
pagesDir: string
): Promise<void> {
const tsConfigPath = path.join(dir, 'tsconfig.json')
const yarnLockFile = path.join(dir, 'yarn.lock')

Expand All @@ -108,7 +111,7 @@ export async function verifyTypeScriptSetup(dir: string): Promise<void> {
)
firstTimeSetup = tsConfig === '' || tsConfig === '{}'
} else {
const hasTypeScriptFiles = await hasTypeScript(dir)
const hasTypeScriptFiles = await hasTypeScript(pagesDir)
if (hasTypeScriptFiles) {
firstTimeSetup = true
} else {
Expand Down
4 changes: 3 additions & 1 deletion packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import Router, { Params, route, Route, RouteMatch } from './router'
import { sendHTML } from './send-html'
import { serveStatic } from './serve-static'
import { isBlockedPage, isInternalUrl } from './utils'
import { findPagesDir } from '../../lib/find-pages-dir'

type NextConfig = any

Expand Down Expand Up @@ -63,6 +64,7 @@ export default class Server {
quiet: boolean
nextConfig: NextConfig
distDir: string
pagesDir: string
publicDir: string
pagesManifest: string
buildId: string
Expand Down Expand Up @@ -91,9 +93,9 @@ export default class Server {
this.dir = resolve(dir)
this.quiet = quiet
const phase = this.currentPhase()
this.pagesDir = findPagesDir(this.dir)
this.nextConfig = loadConfig(phase, this.dir, conf)
this.distDir = join(this.dir, this.nextConfig.distDir)
// this.pagesDir = join(this.dir, 'pages')
this.publicDir = join(this.dir, CLIENT_PUBLIC_FILES_PATH)
this.pagesManifest = join(
this.distDir,
Expand Down
11 changes: 7 additions & 4 deletions packages/next/server/hot-reloader.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@ function erroredPages (compilation, options = { enhanceName: name => name }) {
}

export default class HotReloader {
constructor (dir, { config, buildId } = {}) {
constructor (dir, { config, pagesDir, buildId } = {}) {
this.buildId = buildId
this.dir = dir
this.middlewares = []
this.pagesDir = pagesDir
this.webpackDevMiddleware = null
this.webpackHotMiddleware = null
this.initialized = false
Expand Down Expand Up @@ -204,10 +205,9 @@ export default class HotReloader {
}

async getWebpackConfig () {
const pagesDir = join(this.dir, 'pages')
const pagePaths = await Promise.all([
findPageFile(pagesDir, '/_app', this.config.pageExtensions),
findPageFile(pagesDir, '/_document', this.config.pageExtensions)
findPageFile(this.pagesDir, '/_app', this.config.pageExtensions),
findPageFile(this.pagesDir, '/_document', this.config.pageExtensions)
])

const pages = createPagesMapping(
Expand Down Expand Up @@ -235,13 +235,15 @@ export default class HotReloader {
isServer: false,
config: this.config,
buildId: this.buildId,
pagesDir: this.pagesDir,
entrypoints: { ...entrypoints.client, ...additionalClientEntrypoints }
}),
getBaseWebpackConfig(this.dir, {
dev: true,
isServer: true,
config: this.config,
buildId: this.buildId,
pagesDir: this.pagesDir,
entrypoints: entrypoints.server
})
])
Expand Down Expand Up @@ -442,6 +444,7 @@ export default class HotReloader {
{
dir: this.dir,
buildId: this.buildId,
pagesDir: this.pagesDir,
distDir: this.config.distDir,
reload: this.reload.bind(this),
pageExtensions: this.config.pageExtensions,
Expand Down
8 changes: 5 additions & 3 deletions packages/next/server/next-dev-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import React from 'react'
import { findPageFile } from './lib/find-page-file'
import { normalizePagePath } from '../next-server/server/normalize-page-path'
import { PUBLIC_DIR_MIDDLEWARE_CONFLICT } from '../lib/constants'
import { findPagesDir } from '../lib/find-pages-dir'

if (typeof React.Suspense === 'undefined') {
throw new Error(
Expand Down Expand Up @@ -51,7 +52,7 @@ export default class DevServer extends Server {
)
})
}
this.pagesDir = join(this.dir, 'pages')
this.pagesDir = findPagesDir(this.dir)
}

currentPhase () {
Expand Down Expand Up @@ -110,7 +111,7 @@ export default class DevServer extends Server {

let resolved = false
return new Promise(resolve => {
const pagesDir = join(this.dir, 'pages')
const pagesDir = this.pagesDir

// Watchpack doesn't emit an event for an empty directory
fs.readdir(pagesDir, (_, files) => {
Expand Down Expand Up @@ -174,9 +175,10 @@ export default class DevServer extends Server {
}

async prepare () {
await verifyTypeScriptSetup(this.dir)
await verifyTypeScriptSetup(this.dir, this.pagesDir)

this.hotReloader = new HotReloader(this.dir, {
pagesDir: this.pagesDir,
config: this.nextConfig,
buildId: this.buildId
})
Expand Down