diff --git a/babel.js b/babel.js
index 88817fc616c8b..1bbe4f360f180 100644
--- a/babel.js
+++ b/babel.js
@@ -1 +1 @@
-module.exports = require('./dist/server/build/babel/preset')
+module.exports = require('./dist/build/babel/preset')
diff --git a/bin/next-build b/bin/next-build
index eb60720e6ab36..7d518777565bf 100755
--- a/bin/next-build
+++ b/bin/next-build
@@ -2,7 +2,7 @@
import { resolve, join } from 'path'
import { existsSync } from 'fs'
import parseArgs from 'minimist'
-import build from '../server/build'
+import build from '../build'
import { printAndExit } from '../lib/utils'
const argv = parseArgs(process.argv.slice(2), {
diff --git a/server/build/babel/plugins/handle-import.js b/build/babel/plugins/handle-import.js
similarity index 100%
rename from server/build/babel/plugins/handle-import.js
rename to build/babel/plugins/handle-import.js
diff --git a/server/build/babel/preset.js b/build/babel/preset.js
similarity index 100%
rename from server/build/babel/preset.js
rename to build/babel/preset.js
diff --git a/server/build/index.js b/build/index.js
similarity index 93%
rename from server/build/index.js
rename to build/index.js
index 809240b6aa4b3..2e0a7dd55f3c1 100644
--- a/server/build/index.js
+++ b/build/index.js
@@ -2,8 +2,8 @@ import { join } from 'path'
import promisify from '../lib/promisify'
import fs from 'fs'
import webpack from 'webpack'
-import loadConfig from '../config'
-import { PHASE_PRODUCTION_BUILD, BUILD_ID_FILE } from '../../lib/constants'
+import loadConfig from '../server/config'
+import { PHASE_PRODUCTION_BUILD, BUILD_ID_FILE } from '../lib/constants'
import getBaseWebpackConfig from './webpack'
const access = promisify(fs.access)
diff --git a/server/build/loaders/emit-file-loader.js b/build/loaders/emit-file-loader.js
similarity index 100%
rename from server/build/loaders/emit-file-loader.js
rename to build/loaders/emit-file-loader.js
diff --git a/server/build/loaders/hot-self-accept-loader.js b/build/loaders/hot-self-accept-loader.js
similarity index 64%
rename from server/build/loaders/hot-self-accept-loader.js
rename to build/loaders/hot-self-accept-loader.js
index 76a658650afb0..db095819d9fac 100644
--- a/server/build/loaders/hot-self-accept-loader.js
+++ b/build/loaders/hot-self-accept-loader.js
@@ -1,11 +1,17 @@
-import { resolve, relative } from 'path'
+// @flow
+import { relative } from 'path'
import loaderUtils from 'loader-utils'
-module.exports = function (content, sourceMap) {
+type Options = {|
+ extensions: RegExp,
+ include: Array
+|}
+
+module.exports = function (content: string, sourceMap: any) {
this.cacheable()
- const options = loaderUtils.getOptions(this)
- const route = getRoute(this, options)
+ const options: Options = loaderUtils.getOptions(this)
+ const route = getRoute(this.resourcePath, options)
// Webpack has a built in system to prevent default from colliding, giving it a random letter per export.
// We can safely check if Component is undefined since all other pages imported into the entrypoint don't have __webpack_exports__.default
@@ -30,18 +36,21 @@ module.exports = function (content, sourceMap) {
`, sourceMap)
}
-const nextPagesDir = resolve(__dirname, '..', '..', '..', 'pages')
-
-function getRoute (loaderContext, options) {
- const pagesDir = resolve(loaderContext.options.context, 'pages')
- const { resourcePath } = loaderContext
- const dir = [pagesDir, nextPagesDir]
- .find((d) => resourcePath.indexOf(d) === 0)
-
+function getRoute (resourcePath: string, options: Options) {
if (!options.extensions) {
throw new Error('extensions is not provided to hot-self-accept-loader. Please upgrade all next-plugins to the latest version.')
}
+ if (!options.include) {
+ throw new Error('include option is not provided to hot-self-accept-loader. Please upgrade all next-plugins to the latest version.')
+ }
+
+ const dir = options.include.find((d) => resourcePath.indexOf(d) === 0)
+
+ if (!dir) {
+ throw new Error(`'hot-self-accept-loader' was called on a file that isn't a page.`)
+ }
+
const path = relative(dir, resourcePath).replace(options.extensions, '.js')
return '/' + path.replace(/((^|\/)index)?\.js$/, '')
}
diff --git a/server/build/loaders/next-babel-loader.js b/build/loaders/next-babel-loader.js
similarity index 100%
rename from server/build/loaders/next-babel-loader.js
rename to build/loaders/next-babel-loader.js
diff --git a/server/build/plugins/build-manifest-plugin.js b/build/plugins/build-manifest-plugin.js
similarity index 95%
rename from server/build/plugins/build-manifest-plugin.js
rename to build/plugins/build-manifest-plugin.js
index be2e5fee26ff7..3336eb3d6a66f 100644
--- a/server/build/plugins/build-manifest-plugin.js
+++ b/build/plugins/build-manifest-plugin.js
@@ -1,6 +1,6 @@
// @flow
import { RawSource } from 'webpack-sources'
-import {BUILD_MANIFEST} from '../../../lib/constants'
+import {BUILD_MANIFEST} from '../../lib/constants'
// This plugin creates a build-manifest.json for all assets that are being output
// It has a mapping of "entry" filename to real filename. Because the real filename can be hashed in production
diff --git a/server/build/plugins/dynamic-chunks-plugin.js b/build/plugins/dynamic-chunks-plugin.js
similarity index 100%
rename from server/build/plugins/dynamic-chunks-plugin.js
rename to build/plugins/dynamic-chunks-plugin.js
diff --git a/server/build/plugins/nextjs-ssr-import.js b/build/plugins/nextjs-ssr-import.js
similarity index 100%
rename from server/build/plugins/nextjs-ssr-import.js
rename to build/plugins/nextjs-ssr-import.js
diff --git a/server/build/plugins/pages-manifest-plugin.js b/build/plugins/pages-manifest-plugin.js
similarity index 85%
rename from server/build/plugins/pages-manifest-plugin.js
rename to build/plugins/pages-manifest-plugin.js
index 8f9e265b4d063..0304f6704c52e 100644
--- a/server/build/plugins/pages-manifest-plugin.js
+++ b/build/plugins/pages-manifest-plugin.js
@@ -1,7 +1,6 @@
// @flow
import { RawSource } from 'webpack-sources'
-import { MATCH_ROUTE_NAME } from '../../utils'
-import {PAGES_MANIFEST} from '../../../lib/constants'
+import {PAGES_MANIFEST, ROUTE_NAME_REGEX} from '../../lib/constants'
// This plugin creates a pages-manifest.json from page entrypoints.
// This is used for mapping paths like `/` to `.next/dist/bundles/pages/index.js` when doing SSR
@@ -13,7 +12,7 @@ export default class PagesManifestPlugin {
const pages = {}
for (const entry of entries) {
- const result = MATCH_ROUTE_NAME.exec(entry.name)
+ const result = ROUTE_NAME_REGEX.exec(entry.name)
if (!result) {
continue
}
diff --git a/server/build/plugins/pages-plugin.js b/build/plugins/pages-plugin.js
similarity index 86%
rename from server/build/plugins/pages-plugin.js
rename to build/plugins/pages-plugin.js
index c838df2a3d192..f645341a9fffc 100644
--- a/server/build/plugins/pages-plugin.js
+++ b/build/plugins/pages-plugin.js
@@ -1,17 +1,17 @@
import { ConcatSource } from 'webpack-sources'
import {
- IS_BUNDLED_PAGE,
- MATCH_ROUTE_NAME
-} from '../../utils'
+ IS_BUNDLED_PAGE_REGEX,
+ ROUTE_NAME_REGEX
+} from '../../lib/constants'
class PageChunkTemplatePlugin {
apply (chunkTemplate) {
chunkTemplate.plugin('render', function (modules, chunk) {
- if (!IS_BUNDLED_PAGE.test(chunk.name)) {
+ if (!IS_BUNDLED_PAGE_REGEX.test(chunk.name)) {
return modules
}
- let routeName = MATCH_ROUTE_NAME.exec(chunk.name)[1]
+ let routeName = ROUTE_NAME_REGEX.exec(chunk.name)[1]
// We need to convert \ into / when we are in windows
// to get the proper route name
diff --git a/server/build/plugins/unlink-file-plugin.js b/build/plugins/unlink-file-plugin.js
similarity index 83%
rename from server/build/plugins/unlink-file-plugin.js
rename to build/plugins/unlink-file-plugin.js
index 096bda98a8bea..475e448d5e097 100644
--- a/server/build/plugins/unlink-file-plugin.js
+++ b/build/plugins/unlink-file-plugin.js
@@ -1,7 +1,7 @@
import { join } from 'path'
import promisify from '../../lib/promisify'
import fs from 'fs'
-import { IS_BUNDLED_PAGE } from '../../utils'
+import { IS_BUNDLED_PAGE_REGEX } from '../../lib/constants'
const unlink = promisify(fs.unlink)
@@ -13,7 +13,7 @@ export default class UnlinkFilePlugin {
apply (compiler) {
compiler.plugin('after-emit', (compilation, callback) => {
const removed = Object.keys(this.prevAssets)
- .filter((a) => IS_BUNDLED_PAGE.test(a) && !compilation.assets[a])
+ .filter((a) => IS_BUNDLED_PAGE_REGEX.test(a) && !compilation.assets[a])
this.prevAssets = compilation.assets
diff --git a/server/build/webpack.js b/build/webpack.js
similarity index 88%
rename from server/build/webpack.js
rename to build/webpack.js
index 40c34bc2a7445..5e188cea33ac2 100644
--- a/server/build/webpack.js
+++ b/build/webpack.js
@@ -12,11 +12,7 @@ import DynamicChunksPlugin from './plugins/dynamic-chunks-plugin'
import UnlinkFilePlugin from './plugins/unlink-file-plugin'
import PagesManifestPlugin from './plugins/pages-manifest-plugin'
import BuildManifestPlugin from './plugins/build-manifest-plugin'
-import {SERVER_DIRECTORY} from '../../lib/constants'
-
-const nextDir = path.join(__dirname, '..', '..', '..')
-const nextNodeModulesDir = path.join(nextDir, 'node_modules')
-const nextPagesDir = path.join(nextDir, 'pages')
+import {SERVER_DIRECTORY, NEXT_PROJECT_ROOT, NEXT_PROJECT_ROOT_NODE_MODULES, NEXT_PROJECT_ROOT_DIST, DEFAULT_PAGES_DIR} from '../lib/constants'
function externalsConfig (dir, isServer) {
const externals = []
@@ -57,6 +53,15 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
babel: {
loader: 'next-babel-loader',
options: {dev, isServer}
+ },
+ hotSelfAccept: {
+ loader: 'hot-self-accept-loader',
+ options: {
+ include: [
+ path.join(dir, 'pages')
+ ],
+ extensions: /\.(js|jsx)$/
+ }
}
}
@@ -65,13 +70,13 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
.split(process.platform === 'win32' ? ';' : ':')
.filter((p) => !!p)
- const pagesEntries = await getPages(dir, {dev, isServer, pageExtensions: config.pageExtensions.join('|')})
+ const pagesEntries = await getPages(dir, {nextPagesDir: DEFAULT_PAGES_DIR, dev, isServer, pageExtensions: config.pageExtensions.join('|')})
const totalPages = Object.keys(pagesEntries).length
const clientEntries = !isServer ? {
'main.js': [
- dev && !isServer && path.join(__dirname, '..', '..', 'client', 'webpack-hot-middleware-client'),
- dev && !isServer && path.join(__dirname, '..', '..', 'client', 'on-demand-entries-client'),
- require.resolve(`../../client/next${dev ? '-dev' : ''}`)
+ dev && !isServer && path.join(NEXT_PROJECT_ROOT_DIST, 'client', 'webpack-hot-middleware-client'),
+ dev && !isServer && path.join(NEXT_PROJECT_ROOT_DIST, 'client', 'on-demand-entries-client'),
+ path.join(NEXT_PROJECT_ROOT_DIST, 'client', (dev ? `next-dev` : 'next'))
].filter(Boolean)
} : {}
@@ -102,17 +107,17 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
resolve: {
extensions: ['.js', '.jsx', '.json'],
modules: [
- nextNodeModulesDir,
+ NEXT_PROJECT_ROOT_NODE_MODULES,
'node_modules',
...nodePathList // Support for NODE_PATH environment variable
],
alias: {
- next: nextDir
+ next: NEXT_PROJECT_ROOT
}
},
resolveLoader: {
modules: [
- nextNodeModulesDir,
+ NEXT_PROJECT_ROOT_NODE_MODULES,
'node_modules',
path.join(__dirname, 'loaders'),
...nodePathList // Support for NODE_PATH environment variable
@@ -122,14 +127,8 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
rules: [
dev && !isServer && {
test: /\.(js|jsx)$/,
- loader: 'hot-self-accept-loader',
- include: [
- path.join(dir, 'pages'),
- nextPagesDir
- ],
- options: {
- extensions: /\.(js|jsx)$/
- }
+ include: defaultLoaders.hotSelfAccept.options.include,
+ use: defaultLoaders.hotSelfAccept
},
{
test: /\.(js|jsx)$/,
@@ -206,7 +205,6 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
return true
}
- // commons
// If there are one or two pages, only move modules to common if they are
// used in all of the pages. Otherwise, move modules used in at-least
// 1/2 of the total pages into commons.
@@ -214,7 +212,6 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
return count >= totalPages
}
return count >= totalPages * 0.5
- // commons end
}
}),
// We use a manifest file in development to speed up HMR
diff --git a/server/build/webpack/utils.js b/build/webpack/utils.js
similarity index 90%
rename from server/build/webpack/utils.js
rename to build/webpack/utils.js
index 960226543feea..76f752710669f 100644
--- a/server/build/webpack/utils.js
+++ b/build/webpack/utils.js
@@ -4,12 +4,10 @@ import globModule from 'glob'
const glob = promisify(globModule)
-const nextPagesDir = path.join(__dirname, '..', '..', '..', 'pages')
-
-export async function getPages (dir, {dev, isServer, pageExtensions}) {
+export async function getPages (dir, {nextPagesDir, dev, isServer, pageExtensions}) {
const pageFiles = await getPagePaths(dir, {dev, isServer, pageExtensions})
- return getPageEntries(pageFiles, {isServer, pageExtensions})
+ return getPageEntries(pageFiles, {nextPagesDir, isServer, pageExtensions})
}
export async function getPagePaths (dir, {dev, isServer, pageExtensions}) {
@@ -50,7 +48,7 @@ export function createEntry (filePath, {name, pageExtensions} = {}) {
}
// Convert page paths into entries
-export function getPageEntries (pagePaths, {isServer = false, pageExtensions} = {}) {
+export function getPageEntries (pagePaths, {nextPagesDir, isServer = false, pageExtensions} = {}) {
const entries = {}
for (const filePath of pagePaths) {
diff --git a/flow-typed/npm/loader-utils_vx.x.x.js b/flow-typed/npm/loader-utils_vx.x.x.js
new file mode 100644
index 0000000000000..617e83d2db327
--- /dev/null
+++ b/flow-typed/npm/loader-utils_vx.x.x.js
@@ -0,0 +1,102 @@
+// flow-typed signature: fbec9bc08efb50bade7bd6c2bab84e41
+// flow-typed version: <>/loader-utils_v1.1.0/flow_v0.73.0
+
+/**
+ * This is an autogenerated libdef stub for:
+ *
+ * 'loader-utils'
+ *
+ * Fill this stub out by replacing all the `any` types.
+ *
+ * Once filled out, we encourage you to share your work with the
+ * community by sending a pull request to:
+ * https://github.com/flowtype/flow-typed
+ */
+
+declare module 'loader-utils' {
+ declare module.exports: any;
+}
+
+/**
+ * We include stubs for each file inside this npm package in case you need to
+ * require those files directly. Feel free to delete any files that aren't
+ * needed.
+ */
+declare module 'loader-utils/lib/getCurrentRequest' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/getHashDigest' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/getOptions' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/getRemainingRequest' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/index' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/interpolateName' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/isUrlRequest' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/parseQuery' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/parseString' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/stringifyRequest' {
+ declare module.exports: any;
+}
+
+declare module 'loader-utils/lib/urlToRequest' {
+ declare module.exports: any;
+}
+
+// Filename aliases
+declare module 'loader-utils/lib/getCurrentRequest.js' {
+ declare module.exports: $Exports<'loader-utils/lib/getCurrentRequest'>;
+}
+declare module 'loader-utils/lib/getHashDigest.js' {
+ declare module.exports: $Exports<'loader-utils/lib/getHashDigest'>;
+}
+declare module 'loader-utils/lib/getOptions.js' {
+ declare module.exports: $Exports<'loader-utils/lib/getOptions'>;
+}
+declare module 'loader-utils/lib/getRemainingRequest.js' {
+ declare module.exports: $Exports<'loader-utils/lib/getRemainingRequest'>;
+}
+declare module 'loader-utils/lib/index.js' {
+ declare module.exports: $Exports<'loader-utils/lib/index'>;
+}
+declare module 'loader-utils/lib/interpolateName.js' {
+ declare module.exports: $Exports<'loader-utils/lib/interpolateName'>;
+}
+declare module 'loader-utils/lib/isUrlRequest.js' {
+ declare module.exports: $Exports<'loader-utils/lib/isUrlRequest'>;
+}
+declare module 'loader-utils/lib/parseQuery.js' {
+ declare module.exports: $Exports<'loader-utils/lib/parseQuery'>;
+}
+declare module 'loader-utils/lib/parseString.js' {
+ declare module.exports: $Exports<'loader-utils/lib/parseString'>;
+}
+declare module 'loader-utils/lib/stringifyRequest.js' {
+ declare module.exports: $Exports<'loader-utils/lib/stringifyRequest'>;
+}
+declare module 'loader-utils/lib/urlToRequest.js' {
+ declare module.exports: $Exports<'loader-utils/lib/urlToRequest'>;
+}
diff --git a/lib/constants.js b/lib/constants.js
index 6888a5f2b5186..cd73adc2f9d5e 100644
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -1,3 +1,4 @@
+import {join} from 'path'
export const PHASE_EXPORT = 'phase-export'
export const PHASE_PRODUCTION_BUILD = 'phase-production-build'
export const PHASE_PRODUCTION_SERVER = 'phase-production-server'
@@ -12,3 +13,9 @@ export const BLOCKED_PAGES = [
'/_app',
'/_error'
]
+export const IS_BUNDLED_PAGE_REGEX = /^bundles[/\\]pages.*\.js$/
+export const ROUTE_NAME_REGEX = /^bundles[/\\]pages[/\\](.*)\.js$/
+export const NEXT_PROJECT_ROOT = join(__dirname, '..', '..')
+export const NEXT_PROJECT_ROOT_DIST = join(NEXT_PROJECT_ROOT, 'dist')
+export const NEXT_PROJECT_ROOT_NODE_MODULES = join(NEXT_PROJECT_ROOT, 'node_modules')
+export const DEFAULT_PAGES_DIR = join(NEXT_PROJECT_ROOT_DIST, 'pages')
diff --git a/server/lib/promisify.js b/lib/promisify.js
similarity index 100%
rename from server/lib/promisify.js
rename to lib/promisify.js
diff --git a/package.json b/package.json
index 25187785f4f7b..1964a04a89e99 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"test": "cross-env npm run testall || npm run testall",
"coveralls": "nyc --instrument=false --source-map=false report --temp-directory=./coverage --reporter=text-lcov | coveralls",
"flow": "flow check",
- "lint": "standard 'bin/*' 'client/**/*.js' 'examples/**/*.js' 'lib/**/*.js' 'pages/**/*.js' 'server/**/*.js' 'test/**/*.js'",
+ "lint": "standard 'bin/*' 'client/**/*.js' 'examples/**/*.js' 'lib/**/*.js' 'pages/**/*.js' 'server/**/*.js' 'build/**/*.js' 'test/**/*.js'",
"prepublish": "npm run release",
"precommit": "lint-staged"
},
diff --git a/readme.md b/readme.md
index 0bd4aa2b5f9b5..17e72c2b59144 100644
--- a/readme.md
+++ b/readme.md
@@ -1235,54 +1235,82 @@ module.exports = {
+Some commonly asked for features are available as modules:
+
+- [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css)
+- [@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass)
+- [@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less)
+- [@zeit/next-preact](https://github.com/zeit/next-plugins/tree/master/packages/next-preact)
+- [@zeit/next-typescript](https://github.com/zeit/next-plugins/tree/master/packages/next-typescript)
+
+*Warning: The `webpack` function is executed twice, once for the server and once for the client. This allows you to distinguish between client and server configuration using the `isServer` property*
+
+Multiple configurations can be combined together with function composition. For example:
+
+```js
+const withTypescript = require('@zeit/next-typescript')
+const withSass = require('@zeit/next-sass')
+
+module.exports = withTypescript(withSass({
+ webpack(config, options) {
+ // Further custom configuration here
+ return config
+ }
+}))
+```
+
In order to extend our usage of `webpack`, you can define a function that extends its config via `next.config.js`.
```js
-// This file is not going through babel transformation.
-// So, we write it in vanilla JS
-// (But you could use ES2015 features supported by your Node.js version)
+// next.config.js is not transformed by Babel. So you can only use javascript features supported by your version of Node.js.
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
// Perform customizations to webpack config
-
// Important: return the modified config
return config
},
webpackDevMiddleware: config => {
// Perform customizations to webpack dev middleware config
-
// Important: return the modified config
return config
}
}
```
-Some commonly asked for features are available as modules:
+The second argument to `webpack` is an object containing properties useful when customing the WebPack configuration:
-- [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css)
-- [@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass)
-- [@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less)
-- [@zeit/next-preact](https://github.com/zeit/next-plugins/tree/master/packages/next-preact)
-- [@zeit/next-typescript](https://github.com/zeit/next-plugins/tree/master/packages/next-typescript)
-
-*Warning: The `webpack` function is executed twice, once for the server and once for the client. This allows you to distinguish between client and server configuration using the `isServer` property*
+- `buildId` - `String` the build id used as a unique identifier between builds
+- `dev` - `Boolean` shows if the compilation is done in development mode
+- `isServer` - `Boolean` shows if the resulting configuration will be used for server side (`true`), or client size compilation (`false`).
+- `defaultLoaders` - `Object` Holds loader objects Next.js uses internally, so that you can use them in custom configuration
+ - `babel` - `Object` the `babel-loader` configuration for Next.js.
+ - `hotSelfAccept` - `Object` the `hot-self-accept-loader` configuration. This loader should only be used for advanced use cases. For example [`@zeit/next-typescript`](https://github.com/zeit/next-plugins/tree/master/packages/next-typescript) adds it for top-level typescript pages.
-Multiple configurations can be combined together with function composition. For example:
+Example usage of `defaultLoaders.babel`:
```js
-const withTypescript = require('@zeit/next-typescript')
-const withSass = require('@zeit/next-sass')
+// Example next.config.js for adding a loader that depends on babel-loader
+// This source was taken from the @zeit/next-mdx plugin source:
+// https://github.com/zeit/next-plugins/blob/master/packages/next-mdx
+module.exports = {
+ webpack: (config, {}) => {
+ config.module.rules.push({
+ test: /\.mdx/,
+ use: [
+ options.defaultLoaders.babel,
+ {
+ loader: '@mdx-js/loader',
+ options: pluginOptions.options
+ }
+ ]
+ })
-module.exports = withTypescript(withSass({
- webpack(config, options) {
- // Further custom configuration here
return config
}
-}))
+}
```
-
### Customizing babel config
diff --git a/server/hot-reloader.js b/server/hot-reloader.js
index 4fb1b0fb88663..44a4869c16671 100644
--- a/server/hot-reloader.js
+++ b/server/hot-reloader.js
@@ -4,12 +4,12 @@ import WebpackHotMiddleware from 'webpack-hot-middleware'
import del from 'del'
import onDemandEntryHandler from './on-demand-entry-handler'
import webpack from 'webpack'
-import getBaseWebpackConfig from './build/webpack'
+import getBaseWebpackConfig from '../build/webpack'
import UUID from 'uuid'
import {
- IS_BUNDLED_PAGE,
addCorsSupport
} from './utils'
+import {IS_BUNDLED_PAGE_REGEX} from '../lib/constants'
export default class HotReloader {
constructor (dir, { quiet, config } = {}) {
@@ -145,7 +145,7 @@ export default class HotReloader {
const chunkNames = new Set(
compilation.chunks
.map((c) => c.name)
- .filter(name => IS_BUNDLED_PAGE.test(name))
+ .filter(name => IS_BUNDLED_PAGE_REGEX.test(name))
)
const failedChunkNames = new Set(compilation.errors
@@ -157,7 +157,7 @@ export default class HotReloader {
const chunkHashes = new Map(
compilation.chunks
- .filter(c => IS_BUNDLED_PAGE.test(c.name))
+ .filter(c => IS_BUNDLED_PAGE_REGEX.test(c.name))
.map((c) => [c.name, c.hash])
)
diff --git a/server/index.js b/server/index.js
index cc52dc7d64657..3f362b8bbae66 100644
--- a/server/index.js
+++ b/server/index.js
@@ -4,7 +4,7 @@ import { parse as parseUrl } from 'url'
import { parse as parseQs } from 'querystring'
import fs from 'fs'
import http, { STATUS_CODES } from 'http'
-import promisify from './lib/promisify'
+import promisify from '../lib/promisify'
import {
renderToHTML,
renderErrorToHTML,
diff --git a/server/lib/source-map-support.js b/server/lib/source-map-support.js
index fdd6c466719a4..1d0bb9120bee8 100644
--- a/server/lib/source-map-support.js
+++ b/server/lib/source-map-support.js
@@ -28,7 +28,7 @@ async function rewriteTraceLine (trace: string): Promise {
// Load these on demand.
const fs = require('fs')
- const promisify = require('./promisify')
+ const promisify = require('../../lib/promisify')
const readFile = promisify(fs.readFile)
const access = promisify(fs.access)
diff --git a/server/on-demand-entry-handler.js b/server/on-demand-entry-handler.js
index 66e83a3bb97ab..0ca994c752dda 100644
--- a/server/on-demand-entry-handler.js
+++ b/server/on-demand-entry-handler.js
@@ -3,11 +3,11 @@ import { EventEmitter } from 'events'
import { join } from 'path'
import { parse } from 'url'
import touch from 'touch'
-import promisify from './lib/promisify'
+import promisify from '../lib/promisify'
import globModule from 'glob'
import {normalizePagePath, pageNotFoundError} from './require'
-import {createEntry} from './build/webpack/utils'
-import { MATCH_ROUTE_NAME, IS_BUNDLED_PAGE } from './utils'
+import {createEntry} from '../build/webpack/utils'
+import { ROUTE_NAME_REGEX, IS_BUNDLED_PAGE_REGEX } from '../lib/constants'
const ADDED = Symbol('added')
const BUILDING = Symbol('building')
@@ -63,7 +63,7 @@ export default function onDemandEntryHandler (devMiddleware, compilers, {
if (!hasNoModuleFoundError) return false
// The page itself is missing. So this is a failed page.
- if (IS_BUNDLED_PAGE.test(e.module.name)) return true
+ if (IS_BUNDLED_PAGE_REGEX.test(e.module.name)) return true
// No dependencies means this is a top level page.
// So this is a failed page.
@@ -72,7 +72,7 @@ export default function onDemandEntryHandler (devMiddleware, compilers, {
.map(e => e.module.chunks)
.reduce((a, b) => [...a, ...b], [])
.map(c => {
- const pageName = MATCH_ROUTE_NAME.exec(c.name)[1]
+ const pageName = ROUTE_NAME_REGEX.exec(c.name)[1]
return normalizePage(`/${pageName}`)
})
diff --git a/server/utils.js b/server/utils.js
index d66ddd1602ff2..4b6339c65c630 100644
--- a/server/utils.js
+++ b/server/utils.js
@@ -1,9 +1,6 @@
import { join } from 'path'
import { readdirSync, existsSync } from 'fs'
-export const IS_BUNDLED_PAGE = /^bundles[/\\]pages.*\.js$/
-export const MATCH_ROUTE_NAME = /^bundles[/\\]pages[/\\](.*)\.js$/
-
export function getChunkNameFromFilename (filename, dev) {
if (dev) {
return filename.replace(/.[^.]*$/, '')
diff --git a/taskfile.js b/taskfile.js
index 577a0fcd3d2e8..0edd131d77738 100644
--- a/taskfile.js
+++ b/taskfile.js
@@ -5,7 +5,7 @@ const mkdirp = require('mkdirp')
const isWindows = /^win/.test(process.platform)
export async function compile (task) {
- await task.parallel(['bin', 'server', 'lib', 'client'])
+ await task.parallel(['bin', 'server', 'nextbuild', 'lib', 'client'])
}
export async function bin (task, opts) {
@@ -23,6 +23,11 @@ export async function server (task, opts) {
notify('Compiled server files')
}
+export async function nextbuild (task, opts) {
+ await task.source(opts.src || 'build/**/*.js').babel().target('dist/build')
+ notify('Compiled build files')
+}
+
export async function client (task, opts) {
await task.source(opts.src || 'client/**/*.js').babel().target('dist/client')
notify('Compiled client files')
@@ -50,6 +55,7 @@ export default async function (task) {
await task.watch('bin/*', 'bin')
await task.watch('pages/**/*.js', 'copy')
await task.watch('server/**/*.js', 'server')
+ await task.watch('build/**/*.js', 'nextbuild')
await task.watch('client/**/*.js', 'client')
await task.watch('lib/**/*.js', 'lib')
}
diff --git a/test/isolated/webpack-utils.test.js b/test/isolated/webpack-utils.test.js
index f73de78d8ec88..e206061ad20b2 100644
--- a/test/isolated/webpack-utils.test.js
+++ b/test/isolated/webpack-utils.test.js
@@ -1,7 +1,7 @@
/* global describe, it, expect */
-import {normalize} from 'path'
-import {getPageEntries, createEntry} from '../../dist/server/build/webpack/utils'
+import {normalize, join} from 'path'
+import {getPageEntries, createEntry} from '../../dist/build/webpack/utils'
describe('createEntry', () => {
it('Should turn a path into a page entry', () => {
@@ -48,33 +48,35 @@ describe('createEntry', () => {
})
describe('getPageEntries', () => {
+ const nextPagesDir = join(__dirname, '..', '..', 'dist', 'pages')
+
it('Should return paths', () => {
const pagePaths = ['pages/index.js']
- const pageEntries = getPageEntries(pagePaths)
+ const pageEntries = getPageEntries(pagePaths, {nextPagesDir})
expect(pageEntries[normalize('bundles/pages/index.js')][0]).toBe('./pages/index.js')
})
it('Should include default _error', () => {
const pagePaths = ['pages/index.js']
- const pageEntries = getPageEntries(pagePaths)
+ const pageEntries = getPageEntries(pagePaths, {nextPagesDir})
expect(pageEntries[normalize('bundles/pages/_error.js')][0]).toMatch(/dist[/\\]pages[/\\]_error\.js/)
})
it('Should not include default _error when _error.js is inside the pages directory', () => {
const pagePaths = ['pages/index.js', 'pages/_error.js']
- const pageEntries = getPageEntries(pagePaths)
+ const pageEntries = getPageEntries(pagePaths, {nextPagesDir})
expect(pageEntries[normalize('bundles/pages/_error.js')][0]).toBe('./pages/_error.js')
})
it('Should include default _document when isServer is true', () => {
const pagePaths = ['pages/index.js']
- const pageEntries = getPageEntries(pagePaths, {isServer: true})
+ const pageEntries = getPageEntries(pagePaths, {nextPagesDir, isServer: true})
expect(pageEntries[normalize('bundles/pages/_document.js')][0]).toMatch(/dist[/\\]pages[/\\]_document\.js/)
})
it('Should not include default _document when _document.js is inside the pages directory', () => {
const pagePaths = ['pages/index.js', 'pages/_document.js']
- const pageEntries = getPageEntries(pagePaths, {isServer: true})
+ const pageEntries = getPageEntries(pagePaths, {nextPagesDir, isServer: true})
expect(pageEntries[normalize('bundles/pages/_document.js')][0]).toBe('./pages/_document.js')
})
})
diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js
index 174b55b5e99fc..d2c54d461de04 100644
--- a/test/lib/next-test-utils.js
+++ b/test/lib/next-test-utils.js
@@ -9,7 +9,7 @@ import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'
import fkill from 'fkill'
import server from '../../dist/server/next'
-import build from '../../dist/server/build'
+import build from '../../dist/build'
import _export from '../../dist/server/export'
import _pkg from '../../package.json'
diff --git a/test/unit/handle-import-babel-plugin.test.js b/test/unit/handle-import-babel-plugin.test.js
index 48fb8a58b177a..543b27b6543ad 100644
--- a/test/unit/handle-import-babel-plugin.test.js
+++ b/test/unit/handle-import-babel-plugin.test.js
@@ -1,5 +1,5 @@
/* global describe, it, expect */
-import { getModulePath } from '../../dist/server/build/babel/plugins/handle-import'
+import { getModulePath } from '../../dist/build/babel/plugins/handle-import'
function cleanPath (mPath) {
return mPath