rsnext/packages/next/server/hot-reloader.ts

555 lines
16 KiB
TypeScript
Raw Normal View History

import fs from 'fs'
import { IncomingMessage, ServerResponse } from 'http'
import { join, normalize, relative as relativePath, sep } from 'path'
import { promisify } from 'util'
import webpack from 'webpack'
import WebpackDevMiddleware from 'webpack-dev-middleware'
import WebpackHotMiddleware from 'webpack-hot-middleware'
import { createEntrypoints, createPagesMapping } from '../build/entries'
import { watchCompilers } from '../build/output'
import getBaseWebpackConfig from '../build/webpack-config'
import { NEXT_PROJECT_ROOT_DIST_CLIENT } from '../lib/constants'
import { fileExists } from '../lib/file-exists'
import { recursiveDelete } from '../lib/recursive-delete'
import {
BLOCKED_PAGES,
CLIENT_STATIC_FILES_RUNTIME_AMP,
IS_BUNDLED_PAGE_REGEX,
ROUTE_NAME_REGEX,
} from '../next-server/lib/constants'
import { route } from '../next-server/server/router'
import errorOverlayMiddleware from './lib/error-overlay-middleware'
import { findPageFile } from './lib/find-page-file'
import onDemandEntryHandler, { normalizePage } from './on-demand-entry-handler'
import { NextHandleFunction } from 'connect'
import { UrlObject } from 'url'
const access = promisify(fs.access)
const readFile = promisify(fs.readFile)
export async function renderScriptError(res: ServerResponse, error: Error) {
// Asks CDNs and others to not to cache the errored page
res.setHeader(
'Cache-Control',
'no-cache, no-store, max-age=0, must-revalidate'
)
if (
(error as any).code === 'ENOENT' ||
error.message === 'INVALID_BUILD_ID'
) {
res.statusCode = 404
res.end('404 - Not Found')
return
}
console.error(error.stack)
res.statusCode = 500
res.end('500 - Internal Error')
}
2018-10-02 00:55:31 +02:00
function addCorsSupport(req: IncomingMessage, res: ServerResponse) {
2018-10-02 00:55:31 +02:00
if (!req.headers.origin) {
return { preflight: false }
}
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET')
// Based on https://github.com/primus/access-control/blob/4cf1bc0e54b086c91e6aa44fb14966fa5ef7549c/index.js#L158
if (req.headers['access-control-request-headers']) {
res.setHeader('Access-Control-Allow-Headers', req.headers[
'access-control-request-headers'
] as string)
2018-10-02 00:55:31 +02:00
}
if (req.method === 'OPTIONS') {
res.writeHead(200)
res.end()
return { preflight: true }
}
return { preflight: false }
}
const matchNextPageBundleRequest = route(
'/_next/static/:buildId/pages/:path*.js(.map)?'
)
// Recursively look up the issuer till it ends up at the root
function findEntryModule(issuer: any): any {
if (issuer.issuer) {
return findEntryModule(issuer.issuer)
}
return issuer
}
function erroredPages(
compilation: webpack.compilation.Compilation,
options = { enhanceName: (name: string) => name }
) {
const failedPages: { [page: string]: any[] } = {}
for (const error of compilation.errors) {
if (!error.origin) {
continue
}
const entryModule = findEntryModule(error.origin)
const { name } = entryModule
if (!name) {
continue
}
// Only pages have to be reloaded
if (!IS_BUNDLED_PAGE_REGEX.test(name)) {
continue
}
const enhancedName = options.enhanceName(name)
if (!failedPages[enhancedName]) {
failedPages[enhancedName] = []
}
failedPages[enhancedName].push(error)
}
return failedPages
}
2016-10-14 17:05:08 +02:00
export default class HotReloader {
private dir: string
private buildId: string
private middlewares: any[]
private pagesDir: string
private webpackDevMiddleware: WebpackDevMiddleware.WebpackDevMiddleware | null
private webpackHotMiddleware:
| (NextHandleFunction & WebpackHotMiddleware.EventStream)
| null
private initialized: boolean
private config: any
private stats: any
private serverPrevDocumentHash: string | null
private prevChunkNames?: Set<any>
private onDemandEntries: any
constructor(
dir: string,
{
config,
pagesDir,
buildId,
}: { config: object; pagesDir: string; buildId: string }
) {
this.buildId = buildId
2016-10-17 09:05:46 +02:00
this.dir = dir
this.middlewares = []
this.pagesDir = pagesDir
this.webpackDevMiddleware = null
this.webpackHotMiddleware = null
this.initialized = false
2016-10-19 14:41:45 +02:00
this.stats = null
this.serverPrevDocumentHash = null
this.config = config
2016-10-17 09:05:46 +02:00
}
async run(req: IncomingMessage, res: ServerResponse, parsedUrl: UrlObject) {
Universal Webpack (#3578) * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css
2018-01-30 16:40:52 +01:00
// Usually CORS support is not needed for the hot-reloader (this is dev only feature)
// With when the app runs for multi-zones support behind a proxy,
// the current page is trying to access this URL via assetPrefix.
// That's when the CORS support is needed.
const { preflight } = addCorsSupport(req, res)
if (preflight) {
return
}
// When a request comes in that is a page bundle, e.g. /_next/static/<buildid>/pages/index.js
// we have to compile the page using on-demand-entries, this middleware will handle doing that
// by adding the page to on-demand-entries, waiting till it's done
// and then the bundle will be served like usual by the actual route in server/index.js
const handlePageBundleRequest = async (
res: ServerResponse,
parsedUrl: UrlObject
) => {
const { pathname } = parsedUrl
const params = matchNextPageBundleRequest(pathname)
if (!params) {
return {}
}
if (params.buildId !== this.buildId) {
return
}
const page = `/${params.path.join('/')}`
if (page === '/_error' || BLOCKED_PAGES.indexOf(page) === -1) {
try {
await this.ensurePage(page)
} catch (error) {
await renderScriptError(res, error)
return { finished: true }
}
const bundlePath = join(
this.dir,
this.config.distDir,
'static/development/pages',
page + '.js'
)
// make sure to 404 for AMP bundles in case they weren't removed
try {
await access(bundlePath)
const data = await readFile(bundlePath, 'utf8')
if (data.includes('__NEXT_DROP_CLIENT_FILE__')) {
res.statusCode = 404
res.end()
return { finished: true }
}
} catch (_) {}
const errors = await this.getCompilationErrors(page)
if (errors.length > 0) {
await renderScriptError(res, errors[0])
return { finished: true }
}
}
return {}
}
const { finished } = (await handlePageBundleRequest(res, parsedUrl)) as any
for (const fn of this.middlewares) {
await new Promise((resolve, reject) => {
fn(req, res, (err: Error) => {
if (err) return reject(err)
resolve()
})
})
}
return { finished }
2016-10-17 09:05:46 +02:00
}
async clean() {
return recursiveDelete(join(this.dir, this.config.distDir))
}
async getWebpackConfig() {
const pagePaths = await Promise.all([
findPageFile(this.pagesDir, '/_app', this.config.pageExtensions),
findPageFile(this.pagesDir, '/_document', this.config.pageExtensions),
])
const pages = createPagesMapping(
pagePaths.filter(i => i !== null) as string[],
this.config.pageExtensions
)
const entrypoints = createEntrypoints(
pages,
'server',
this.buildId,
this.config
)
let additionalClientEntrypoints: { [file: string]: string } = {}
additionalClientEntrypoints[CLIENT_STATIC_FILES_RUNTIME_AMP] =
`.${sep}` +
relativePath(
this.dir,
join(NEXT_PROJECT_ROOT_DIST_CLIENT, 'dev', 'amp-dev')
)
return Promise.all([
getBaseWebpackConfig(this.dir, {
dev: true,
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,
}),
])
}
async start() {
await this.clean()
Universal Webpack (#3578) * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css
2018-01-30 16:40:52 +01:00
const configs = await this.getWebpackConfig()
const multiCompiler = webpack(configs)
Universal Webpack (#3578) * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css
2018-01-30 16:40:52 +01:00
const buildTools = await this.prepareBuildTools(multiCompiler)
this.assignBuildTools(buildTools)
this.stats = ((await this.waitUntilValid()) as any).stats[0]
2016-10-17 09:05:46 +02:00
}
async stop(webpackDevMiddleware?: WebpackDevMiddleware.WebpackDevMiddleware) {
const middleware = webpackDevMiddleware || this.webpackDevMiddleware
if (middleware) {
return new Promise((resolve, reject) => {
;(middleware.close as any)((err: any) => {
if (err) return reject(err)
resolve()
})
})
}
}
async reload() {
this.stats = null
await this.clean()
Universal Webpack (#3578) * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css
2018-01-30 16:40:52 +01:00
const configs = await this.getWebpackConfig()
Universal Webpack (#3578) * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css
2018-01-30 16:40:52 +01:00
const compiler = webpack(configs)
const buildTools = await this.prepareBuildTools(compiler)
this.stats = await this.waitUntilValid(buildTools.webpackDevMiddleware)
const oldWebpackDevMiddleware = this.webpackDevMiddleware
this.assignBuildTools(buildTools)
await this.stop(oldWebpackDevMiddleware!)
}
assignBuildTools({
webpackDevMiddleware,
webpackHotMiddleware,
onDemandEntries,
}: {
webpackDevMiddleware: WebpackDevMiddleware.WebpackDevMiddleware
webpackHotMiddleware: NextHandleFunction & WebpackHotMiddleware.EventStream
onDemandEntries: any
}) {
this.webpackDevMiddleware = webpackDevMiddleware
this.webpackHotMiddleware = webpackHotMiddleware
this.onDemandEntries = onDemandEntries
this.middlewares = [
webpackDevMiddleware,
// must come before hotMiddleware
onDemandEntries.middleware(),
webpackHotMiddleware,
errorOverlayMiddleware({ dir: this.dir }),
]
}
async prepareBuildTools(multiCompiler: webpack.MultiCompiler) {
const tsConfigPath = join(this.dir, 'tsconfig.json')
const useTypeScript = await fileExists(tsConfigPath)
watchCompilers(
multiCompiler.compilers[0],
multiCompiler.compilers[1],
useTypeScript,
({ errors, warnings }) => this.send('typeChecked', { errors, warnings })
)
// This plugin watches for changes to _document.js and notifies the client side that it should reload the page
multiCompiler.compilers[1].hooks.done.tap(
'NextjsHotReloaderForServer',
stats => {
if (!this.initialized) {
return
}
2016-10-24 09:22:15 +02:00
const { compilation } = stats
// We only watch `_document` for changes on the server compilation
// the rest of the files will be triggered by the client compilation
const documentChunk = compilation.chunks.find(
c => c.name === normalize(`static/${this.buildId}/pages/_document.js`)
)
// If the document chunk can't be found we do nothing
if (!documentChunk) {
console.warn('_document.js chunk not found')
return
}
// Initial value
if (this.serverPrevDocumentHash === null) {
this.serverPrevDocumentHash = documentChunk.hash
return
}
// If _document.js didn't change we don't trigger a reload
if (documentChunk.hash === this.serverPrevDocumentHash) {
return
}
// Notify reload to reload the page, as _document.js was changed (different hash)
this.send('reloadPage')
this.serverPrevDocumentHash = documentChunk.hash
}
)
2016-10-14 17:05:08 +02:00
multiCompiler.compilers[0].hooks.done.tap(
'NextjsHotReloaderForClient',
stats => {
const { compilation } = stats
const chunkNames = new Set(
compilation.chunks
.map(c => c.name)
.filter(name => IS_BUNDLED_PAGE_REGEX.test(name))
)
if (this.initialized) {
// detect chunks which have to be replaced with a new template
// e.g, pages/index.js <-> pages/_error.js
const addedPages = diff(chunkNames, this.prevChunkNames!)
const removedPages = diff(this.prevChunkNames!, chunkNames)
if (addedPages.size > 0) {
for (const addedPage of addedPages) {
let page =
'/' + ROUTE_NAME_REGEX.exec(addedPage)![1].replace(/\\/g, '/')
page = page === '/index' ? '/' : page
this.send('addedPage', page)
}
}
if (removedPages.size > 0) {
for (const removedPage of removedPages) {
let page =
'/' + ROUTE_NAME_REGEX.exec(removedPage)![1].replace(/\\/g, '/')
page = page === '/index' ? '/' : page
this.send('removedPage', page)
}
}
}
2016-10-24 17:20:50 +02:00
this.initialized = true
this.stats = stats
this.prevChunkNames = chunkNames
}
)
2016-10-19 14:41:45 +02:00
// We dont watch .git/ .next/ and node_modules for changes
const ignored = [
/[\\/]\.git[\\/]/,
/[\\/]\.next[\\/]/,
/[\\/]node_modules[\\/]/,
]
let webpackDevMiddlewareConfig = {
publicPath: `/_next/static/webpack`,
2016-10-17 09:05:46 +02:00
noInfo: true,
logLevel: 'silent',
watchOptions: { ignored },
writeToDisk: true,
}
if (this.config.webpackDevMiddleware) {
console.log(
`> Using "webpackDevMiddleware" config function defined in ${
this.config.configOrigin
}.`
)
webpackDevMiddlewareConfig = this.config.webpackDevMiddleware(
webpackDevMiddlewareConfig
)
}
const webpackDevMiddleware = WebpackDevMiddleware(
multiCompiler,
webpackDevMiddlewareConfig
)
const webpackHotMiddleware = WebpackHotMiddleware(
multiCompiler.compilers[0],
{
path: '/_next/webpack-hmr',
log: false,
heartbeat: 2500,
}
)
Universal Webpack (#3578) * Speed up next build * Document webpack config * Speed up next build * Remove comment * Add comment * Clean up rules * Add comments * Run in parallel * Push plugins seperately * Create a new chunk for react * Don’t uglify react since it’s already uglified. Move react to commons in development * Use the minified version directly * Re-add globpattern * Move loaders into a separate variable * Add comment linking to Dan’s explanation * Remove dot * Add universal webpack * Initial dev support * Fix linting * Add changes from Arunoda's work * Made next dev works. But super slow and no HMR support. * Fix client side hot reload * Server side hmr * Only in dev * Add on-demand-entries client + hot-middleware * Add .babelrc support * Speed up on demand entries by running in parallel * Serve static generated files * Add missing config in dev * Add sass support * Add support for .map * Add cssloader config and fix .jsx support * Rename * use same defaults as css-loader. Fix linting * Add NoEmitErrorsPlugin * Add clientBootstrap * Use webpackhotmiddleware on the multi compiler * alpha.3 * Use babel 16.2.x * Fix reloading after error * Remove comment * Release 5.0.0-univeral-alpha.1 * Remove check for React 16 * Release 5.0.0-universal-alpha.2 * React hot loader v4 * Use our static file rendering machanism to serve pages. This should work well since the file path for a page is predictable. * Release 5.0.0-universal-alpha.3 * Remove optional loaders * Release 5.0.0-universal-alpha.4 * Remove clientBootstrap * Remove renderScript * Make sure pages bundles are served correctly * Remove unused import * Revert to using the same code as canary * Fix hot loader * Release 5.0.0-universal-alpha.5 * Check if externals dir exist before applying config * Add typescript support * Add support for transpiling certain packages in node_modules Thanks to @giuseppeg’s work in https://github.com/zeit/next.js/pull/3319 * Add BABEL_DISABLE_CACHE support * Make sourcemaps in production opt-in * Revert "Add support for transpiling certain packages in node_modules" This reverts commit d4b1d9babfb4b9ed4f4b12d56d52dee233e862da. In favor of a better api around this. * Support typescript through next.config.js * Remove comments * Bring back commons.js calculation * Remove unused dependencies * Move base.config.js to webpack.js * Make sure to only invalidate webpackDevMiddleware one after other. * Allow babel-loder caching by default. * Add comment about preact support * Bring back buildir replace * Remove obsolete plugin * Remove build replace, speed up build * Resolve page entries like pages/day/index.js to pages/day.js * Add componentDidCatch back * Compile to bundles * Use config.distDir everywhere * Make sure the file is an array * Remove console.log * Apply optimization to uglifyjs * Add comment pointing to source * Create entries the same way in dev and production * Remove unused and broken pagesGlobPattern * day/index.js is automatically turned into day.js at build time * Remove poweredByHeader option * Load pages with the correct path. * Release 5.0.0-universal-alpha.6 * Make sure react-dom/server can be overwritten by module-alias * Only add react-hot-loader babel plugin in dev * Release 5.0.0-universal-alpha.7 * Revert tests * Release 5.0.0-universal-alpha.10 * Make sure next/head is working properly. * Add wepack alias for 'next' back. * Make sure overriding className in next/head works * Alias react too * Add missing r * Fragment fallback has to wrap the children * Use min.js * Remove css.js * Remove wallaby.js * Release 5.0.0-universal-alpha.11 * Resolve relative to workdir instead of next * Make sure we touch the right file * Resolve next modules * Remove dotjsx removal plugins since we use webpack on the server * Revert "Resolve relative to workdir instead of next" This reverts commit a13f3e4ab565df9e2c9a3dfc8eb4009c0c2e02ed. * Externalize any locally loaded module lives outside of app dir. * Remove server aliases * Check node_modules reliably * Add symlink to next for tests * Make sure dynamic imports work locally. This is why we need it: https://github.com/webpack/webpack/blob/b545b519b2024e3f8be3041385bd326bf5d24449/lib/MainTemplate.js#L68 We need to have the finally clause in the above in __webpack_require__. webpack output option strictModuleExceptionHandling does that. * dynmaic -> dynamic * Remove webpack-node-externals * Make sure dynamic imports support SSR. * Remove css support in favor of next-css * Make sure we load path from `/` since it’s included in the path matching * Catch when ensurepage couldn’t be fulfilled for `.js.map` * Register require cache flusher for both client and server * Add comment explaining this is to facilitate hot reloading * Only load module when needed * Remove unused modules * Release 5.0.0-universal-alpha.12 * Only log the `found babel` message once * Make sure ondemand entries working correctly. Now we are just using a single instance of OnDemandEntryHandler. * Better sourcemaps * Release 5.0.0-universal-alpha.13 * Lock uglify version to 1.1.6 * Release 5.0.0-universal-alpha.14 * Fix a typo. * Introduce multi-zones support for mircofrontends * Add section on css
2018-01-30 16:40:52 +01:00
const onDemandEntries = onDemandEntryHandler(
webpackDevMiddleware,
multiCompiler,
{
dir: this.dir,
buildId: this.buildId,
pagesDir: this.pagesDir,
distDir: this.config.distDir,
reload: this.reload.bind(this),
pageExtensions: this.config.pageExtensions,
publicRuntimeConfig: this.config.publicRuntimeConfig,
serverRuntimeConfig: this.config.serverRuntimeConfig,
...this.config.onDemandEntries,
}
)
return {
webpackDevMiddleware,
webpackHotMiddleware,
onDemandEntries,
}
2016-10-14 17:05:08 +02:00
}
waitUntilValid(
webpackDevMiddleware?: WebpackDevMiddleware.WebpackDevMiddleware
) {
const middleware = webpackDevMiddleware || this.webpackDevMiddleware
return new Promise(resolve => {
middleware!.waitUntilValid(resolve)
2016-10-14 17:05:08 +02:00
})
}
async getCompilationErrors(page: string) {
const normalizedPage = normalizePage(page)
// When we are reloading, we need to wait until it's reloaded properly.
await this.onDemandEntries.waitUntilReloaded()
if (this.stats.hasErrors()) {
const { compilation } = this.stats
const failedPages = erroredPages(compilation, {
enhanceName(name) {
return '/' + ROUTE_NAME_REGEX.exec(name)![1]
},
})
// If there is an error related to the requesting page we display it instead of the first error
if (
failedPages[normalizedPage] &&
failedPages[normalizedPage].length > 0
) {
return failedPages[normalizedPage]
2016-10-19 14:41:45 +02:00
}
// If none were found we still have to show the other errors
return this.stats.compilation.errors
2016-10-19 14:41:45 +02:00
}
return []
2016-10-19 14:41:45 +02:00
}
send = (action: string, ...args: any[]) => {
this.webpackHotMiddleware!.publish({ action, data: args })
2016-10-24 09:22:15 +02:00
}
async ensurePage(page: string) {
// Make sure we don't re-build or dispose prebuilt pages
if (page !== '/_error' && BLOCKED_PAGES.indexOf(page) !== -1) {
return
}
return this.onDemandEntries.ensurePage(page)
}
2016-10-14 17:05:08 +02:00
}
2016-10-19 14:41:45 +02:00
function diff(a: Set<any>, b: Set<any>) {
return new Set([...a].filter(v => !b.has(v)))
2016-10-24 09:22:15 +02:00
}