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