From 5c5108fe0de231ceec7c5cb74dafccad9d7176a7 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Tue, 29 Dec 2020 22:21:35 +0100 Subject: [PATCH] Add profiling to webpack loaders (#20392) Follow-up to #20357 with additional tracers. --- .vscode/launch.json | 3 +- .vscode/settings.json | 3 +- .../webpack/loaders}/babel-loader/LICENSE | 0 .../webpack/loaders/babel-loader/src/Error.js | 35 +++ .../webpack/loaders/babel-loader/src/cache.js | 57 ++++ .../webpack/loaders/babel-loader/src/index.js | 168 ++++++++++ .../loaders/babel-loader/src/transform.js | 29 ++ .../webpack/loaders/next-babel-loader.js | 7 +- .../loaders/next-client-pages-loader.ts | 33 +- .../loaders/next-serverless-loader/index.ts | 286 +++++++++--------- .../webpack/plugins/build-manifest-plugin.ts | 219 +++++++------- packages/next/compiled/babel-loader/index.js | 1 - .../next/compiled/babel-loader/package.json | 1 - .../next/compiled/find-cache-dir/index.js | 2 +- packages/next/package.json | 1 - packages/next/taskfile.js | 9 - test/unit/next-babel-loader.unit.test.js | 8 +- yarn.lock | 12 +- 18 files changed, 587 insertions(+), 287 deletions(-) rename packages/next/{compiled => build/webpack/loaders}/babel-loader/LICENSE (100%) create mode 100644 packages/next/build/webpack/loaders/babel-loader/src/Error.js create mode 100644 packages/next/build/webpack/loaders/babel-loader/src/cache.js create mode 100644 packages/next/build/webpack/loaders/babel-loader/src/index.js create mode 100644 packages/next/build/webpack/loaders/babel-loader/src/transform.js delete mode 100644 packages/next/compiled/babel-loader/index.js delete mode 100644 packages/next/compiled/babel-loader/package.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 512d385b8e434..e7cd5522232f3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,8 @@ "runtimeExecutable": "yarn", "runtimeArgs": ["run", "debug", "build", "test/integration/basic"], "skipFiles": ["/**"], - "port": 9229 + "port": 9229, + "outFiles": ["${workspaceFolder}/packages/next/dist/**/*"] }, { "name": "Launch app production", diff --git a/.vscode/settings.json b/.vscode/settings.json index e521849f2cdba..9b9d414d6ec53 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ "javascriptreact", { "language": "typescript", "autoFix": true }, { "language": "typescriptreact", "autoFix": true } - ] + ], + "debug.javascript.unmapMissingSources": true } diff --git a/packages/next/compiled/babel-loader/LICENSE b/packages/next/build/webpack/loaders/babel-loader/LICENSE similarity index 100% rename from packages/next/compiled/babel-loader/LICENSE rename to packages/next/build/webpack/loaders/babel-loader/LICENSE diff --git a/packages/next/build/webpack/loaders/babel-loader/src/Error.js b/packages/next/build/webpack/loaders/babel-loader/src/Error.js new file mode 100644 index 0000000000000..e0916371a47f0 --- /dev/null +++ b/packages/next/build/webpack/loaders/babel-loader/src/Error.js @@ -0,0 +1,35 @@ +const STRIP_FILENAME_RE = /^[^:]+: / + +const format = (err) => { + if (err instanceof SyntaxError) { + err.name = 'SyntaxError' + err.message = err.message.replace(STRIP_FILENAME_RE, '') + + err.hideStack = true + } else if (err instanceof TypeError) { + err.name = null + err.message = err.message.replace(STRIP_FILENAME_RE, '') + + err.hideStack = true + } + + return err +} + +class LoaderError extends Error { + constructor(err) { + super() + + const { name, message, codeFrame, hideStack } = format(err) + + this.name = 'BabelLoaderError' + + this.message = `${name ? `${name}: ` : ''}${message}\n\n${codeFrame}\n` + + this.hideStack = hideStack + + Error.captureStackTrace(this, this.constructor) + } +} + +export default LoaderError diff --git a/packages/next/build/webpack/loaders/babel-loader/src/cache.js b/packages/next/build/webpack/loaders/babel-loader/src/cache.js new file mode 100644 index 0000000000000..1c577e2eb5bc0 --- /dev/null +++ b/packages/next/build/webpack/loaders/babel-loader/src/cache.js @@ -0,0 +1,57 @@ +import { createHash } from 'crypto' +import { tracer, traceAsyncFn } from '../../../../tracer' +import transform from './transform' +import cacache from 'next/dist/compiled/cacache' + +async function read(cacheDirectory, etag) { + const cachedResult = await traceAsyncFn( + tracer.startSpan('read-cache-file'), + async () => await cacache.get(cacheDirectory, etag) + ) + + return JSON.parse(cachedResult.data) +} + +function write(cacheDirectory, etag, data) { + return cacache.put(cacheDirectory, etag, JSON.stringify(data)) +} + +const etag = function (source, identifier, options) { + const hash = createHash('md4') + + const contents = JSON.stringify({ source, options, identifier }) + + hash.update(contents) + + return hash.digest('hex') +} + +export default async function handleCache(params) { + const span = tracer.startSpan('handle-cache') + return traceAsyncFn(span, async () => { + const { source, options = {}, cacheIdentifier, cacheDirectory } = params + + const file = etag(source, cacheIdentifier) + + try { + // No errors mean that the file was previously cached + // we just need to return it + const res = await read(cacheDirectory, file) + span.setAttribute('cache', res ? 'HIT' : 'MISS') + return res + } catch (err) {} + + // Otherwise just transform the file + // return it to the user asap and write it in cache + const result = await traceAsyncFn( + tracer.startSpan('transform'), + async () => { + return transform(source, options) + } + ) + + await write(cacheDirectory, file, result) + + return result + }) +} diff --git a/packages/next/build/webpack/loaders/babel-loader/src/index.js b/packages/next/build/webpack/loaders/babel-loader/src/index.js new file mode 100644 index 0000000000000..4aabed3cfc45f --- /dev/null +++ b/packages/next/build/webpack/loaders/babel-loader/src/index.js @@ -0,0 +1,168 @@ +// import babel from 'next/dist/compiled/babel/core' +import loaderUtils from 'loader-utils' +import { tracer, traceAsyncFn, traceFn } from '../../../../tracer' +import cache from './cache' +import transform from './transform' + +// When using `import` Babel will be undefined +const babel = require('next/dist/compiled/babel/core') + +export default function makeLoader(callback) { + const overrides = callback(babel) + + return function (source, inputSourceMap) { + // Make the loader async + const cb = this.async() + + loader.call(this, source, inputSourceMap, overrides).then( + (args) => cb(null, ...args), + (err) => cb(err) + ) + } +} + +async function loader(source, inputSourceMap, overrides) { + const span = tracer.startSpan('babel-loader') + return traceAsyncFn(span, async () => { + const filename = this.resourcePath + span.setAttribute('filename', filename) + + let loaderOptions = loaderUtils.getOptions(this) || {} + + let customOptions + if (overrides && overrides.customOptions) { + const result = await traceAsyncFn( + tracer.startSpan('loader-overrides-customoptions'), + async () => + await overrides.customOptions.call(this, loaderOptions, { + source, + map: inputSourceMap, + }) + ) + customOptions = result.custom + loaderOptions = result.loader + } + + // Standardize on 'sourceMaps' as the key passed through to Webpack, so that + // users may safely use either one alongside our default use of + // 'this.sourceMap' below without getting error about conflicting aliases. + if ( + Object.prototype.hasOwnProperty.call(loaderOptions, 'sourceMap') && + !Object.prototype.hasOwnProperty.call(loaderOptions, 'sourceMaps') + ) { + loaderOptions = Object.assign({}, loaderOptions, { + sourceMaps: loaderOptions.sourceMap, + }) + delete loaderOptions.sourceMap + } + + const programmaticOptions = Object.assign({}, loaderOptions, { + filename, + inputSourceMap: inputSourceMap || undefined, + + // Set the default sourcemap behavior based on Webpack's mapping flag, + // but allow users to override if they want. + sourceMaps: + loaderOptions.sourceMaps === undefined + ? this.sourceMap + : loaderOptions.sourceMaps, + + // Ensure that Webpack will get a full absolute path in the sourcemap + // so that it can properly map the module back to its internal cached + // modules. + sourceFileName: filename, + caller: { + name: 'babel-loader', + + // Provide plugins with insight into webpack target. + // https://github.com/babel/babel-loader/issues/787 + target: this.target, + + // Webpack >= 2 supports ESM and dynamic import. + supportsStaticESM: true, + supportsDynamicImport: true, + + // Webpack 5 supports TLA behind a flag. We enable it by default + // for Babel, and then webpack will throw an error if the experimental + // flag isn't enabled. + supportsTopLevelAwait: true, + ...loaderOptions.caller, + }, + }) + // Remove loader related options + delete programmaticOptions.cacheDirectory + delete programmaticOptions.cacheIdentifier + + const config = traceFn( + tracer.startSpan('babel-load-partial-config-async'), + () => { + return babel.loadPartialConfig(programmaticOptions) + } + ) + + if (config) { + let options = config.options + if (overrides && overrides.config) { + options = await traceAsyncFn( + tracer.startSpan('loader-overrides-config'), + async () => + await overrides.config.call(this, config, { + source, + map: inputSourceMap, + customOptions, + }) + ) + } + + if (options.sourceMaps === 'inline') { + // Babel has this weird behavior where if you set "inline", we + // inline the sourcemap, and set 'result.map = null'. This results + // in bad behavior from Babel since the maps get put into the code, + // which Webpack does not expect, and because the map we return to + // Webpack is null, which is also bad. To avoid that, we override the + // behavior here so "inline" just behaves like 'true'. + options.sourceMaps = true + } + + const { cacheDirectory, cacheIdentifier } = loaderOptions + + let result + if (cacheDirectory) { + result = await cache({ + source, + options, + cacheDirectory, + cacheIdentifier, + cacheCompression: false, + }) + } else { + result = await traceAsyncFn( + tracer.startSpan('transform', { + attributes: { + filename, + cache: 'DISABLED', + }, + }), + async () => { + return transform(source, options) + } + ) + } + + // TODO: Babel should really provide the full list of config files that + // were used so that this can also handle files loaded with 'extends'. + if (typeof config.babelrc === 'string') { + this.addDependency(config.babelrc) + } + + if (result) { + const { code, map } = result + + return [code, map] + } + } + + // If the file was ignored, pass through the original content. + return [source, inputSourceMap] + }) +} diff --git a/packages/next/build/webpack/loaders/babel-loader/src/transform.js b/packages/next/build/webpack/loaders/babel-loader/src/transform.js new file mode 100644 index 0000000000000..4f86c2cb48679 --- /dev/null +++ b/packages/next/build/webpack/loaders/babel-loader/src/transform.js @@ -0,0 +1,29 @@ +import { transform as _transform } from 'next/dist/compiled/babel/core' +import { promisify } from 'util' +import LoaderError from './Error' + +const transform = promisify(_transform) + +export default async function (source, options) { + let result + try { + result = await transform(source, options) + } catch (err) { + throw err.message && err.codeFrame ? new LoaderError(err) : err + } + + if (!result) return null + + // We don't return the full result here because some entries are not + // really serializable. For a full list of properties see here: + // https://github.com/babel/babel/blob/main/packages/babel-core/src/transformation/index.js + // For discussion on this topic see here: + // https://github.com/babel/babel-loader/pull/629 + const { ast, code, map, metadata, sourceType } = result + + if (map && (!map.sourcesContent || !map.sourcesContent.length)) { + map.sourcesContent = [source] + } + + return { ast, code, map, metadata, sourceType } +} diff --git a/packages/next/build/webpack/loaders/next-babel-loader.js b/packages/next/build/webpack/loaders/next-babel-loader.js index cdffddc1bd589..c1ba84b6b8a81 100644 --- a/packages/next/build/webpack/loaders/next-babel-loader.js +++ b/packages/next/build/webpack/loaders/next-babel-loader.js @@ -1,4 +1,4 @@ -import babelLoader from 'next/dist/compiled/babel-loader' +import babelLoader from './babel-loader/src/index' import hash from 'next/dist/compiled/string-hash' import { basename, join } from 'path' import * as Log from '../../output/log' @@ -8,7 +8,7 @@ import * as Log from '../../output/log' const cacheKey = 'babel-cache-' + 'o' + '-' const nextBabelPreset = require('../../babel/preset') -module.exports = babelLoader.custom((babel) => { +const customBabelLoader = babelLoader((babel) => { const presetItem = babel.createConfigItem(nextBabelPreset, { type: 'preset', }) @@ -37,7 +37,6 @@ module.exports = babelLoader.custom((babel) => { const loader = Object.assign( opts.cache ? { - cacheCompression: false, cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'), cacheIdentifier: cacheKey + @@ -210,3 +209,5 @@ module.exports = babelLoader.custom((babel) => { }, } }) + +export default customBabelLoader diff --git a/packages/next/build/webpack/loaders/next-client-pages-loader.ts b/packages/next/build/webpack/loaders/next-client-pages-loader.ts index 3d338cabb0c63..5fe4a77d9811c 100644 --- a/packages/next/build/webpack/loaders/next-client-pages-loader.ts +++ b/packages/next/build/webpack/loaders/next-client-pages-loader.ts @@ -1,5 +1,6 @@ import { loader } from 'webpack' import loaderUtils from 'loader-utils' +import { tracer, traceFn } from '../../tracer' export type ClientPagesLoaderOptions = { absolutePagePath: string @@ -7,20 +8,26 @@ export type ClientPagesLoaderOptions = { } const nextClientPagesLoader: loader.Loader = function () { - const { absolutePagePath, page } = loaderUtils.getOptions( - this - ) as ClientPagesLoaderOptions - const stringifiedAbsolutePagePath = JSON.stringify(absolutePagePath) - const stringifiedPage = JSON.stringify(page) + const span = tracer.startSpan('next-client-pages-loader') + return traceFn(span, () => { + const { absolutePagePath, page } = loaderUtils.getOptions( + this + ) as ClientPagesLoaderOptions - return ` - (window.__NEXT_P = window.__NEXT_P || []).push([ - ${stringifiedPage}, - function () { - return require(${stringifiedAbsolutePagePath}); - } - ]); - ` + span.setAttribute('absolutePagePath', absolutePagePath) + + const stringifiedAbsolutePagePath = JSON.stringify(absolutePagePath) + const stringifiedPage = JSON.stringify(page) + + return ` + (window.__NEXT_P = window.__NEXT_P || []).push([ + ${stringifiedPage}, + function () { + return require(${stringifiedAbsolutePagePath}); + } + ]); + ` + }) } export default nextClientPagesLoader diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/index.ts b/packages/next/build/webpack/loaders/next-serverless-loader/index.ts index fcbee8c3dc53e..159ab84744c96 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader/index.ts @@ -11,6 +11,7 @@ import { ROUTES_MANIFEST, REACT_LOADABLE_MANIFEST, } from '../../../../next-server/lib/constants' +import { tracer, traceFn } from '../../../tracer' export type ServerlessLoaderQuery = { page: string @@ -33,81 +34,158 @@ export type ServerlessLoaderQuery = { } const nextServerlessLoader: loader.Loader = function () { - const { - distDir, - absolutePagePath, - page, - buildId, - canonicalBase, - assetPrefix, - absoluteAppPath, - absoluteDocumentPath, - absoluteErrorPath, - absolute404Path, - generateEtags, - poweredByHeader, - basePath, - runtimeConfig, - previewProps, - loadedEnvFiles, - i18n, - }: ServerlessLoaderQuery = - typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query - - const buildManifest = join(distDir, BUILD_MANIFEST).replace(/\\/g, '/') - const reactLoadableManifest = join(distDir, REACT_LOADABLE_MANIFEST).replace( - /\\/g, - '/' - ) - const routesManifest = join(distDir, ROUTES_MANIFEST).replace(/\\/g, '/') - - const escapedBuildId = escapeRegexp(buildId) - const pageIsDynamicRoute = isDynamicRoute(page) - - const encodedPreviewProps = devalue( - JSON.parse(previewProps) as __ApiPreviewProps - ) - - const envLoading = ` - const { processEnv } = require('@next/env') - processEnv(${Buffer.from(loadedEnvFiles, 'base64').toString()}) - ` - - const runtimeConfigImports = runtimeConfig - ? ` - const { setConfig } = require('next/config') - ` - : '' - - const runtimeConfigSetter = runtimeConfig - ? ` - const runtimeConfig = ${runtimeConfig} - setConfig(runtimeConfig) + const span = tracer.startSpan('next-serverless-loader') + return traceFn(span, () => { + const { + distDir, + absolutePagePath, + page, + buildId, + canonicalBase, + assetPrefix, + absoluteAppPath, + absoluteDocumentPath, + absoluteErrorPath, + absolute404Path, + generateEtags, + poweredByHeader, + basePath, + runtimeConfig, + previewProps, + loadedEnvFiles, + i18n, + }: ServerlessLoaderQuery = + typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query + + const buildManifest = join(distDir, BUILD_MANIFEST).replace(/\\/g, '/') + const reactLoadableManifest = join( + distDir, + REACT_LOADABLE_MANIFEST + ).replace(/\\/g, '/') + const routesManifest = join(distDir, ROUTES_MANIFEST).replace(/\\/g, '/') + + const escapedBuildId = escapeRegexp(buildId) + const pageIsDynamicRoute = isDynamicRoute(page) + + const encodedPreviewProps = devalue( + JSON.parse(previewProps) as __ApiPreviewProps + ) + + const envLoading = ` + const { processEnv } = require('@next/env') + processEnv(${Buffer.from(loadedEnvFiles, 'base64').toString()}) ` - : 'const runtimeConfig = {}' - if (page.match(API_ROUTE)) { - return ` + const runtimeConfigImports = runtimeConfig + ? ` + const { setConfig } = require('next/config') + ` + : '' + + const runtimeConfigSetter = runtimeConfig + ? ` + const runtimeConfig = ${runtimeConfig} + setConfig(runtimeConfig) + ` + : 'const runtimeConfig = {}' + + if (page.match(API_ROUTE)) { + return ` + ${envLoading} + ${runtimeConfigImports} + ${ + /* + this needs to be called first so its available for any other imports + */ + runtimeConfigSetter + } + import initServer from 'next-plugin-loader?middleware=on-init-server!' + import onError from 'next-plugin-loader?middleware=on-error-server!' + import 'next/dist/next-server/server/node-polyfill-fetch' + import routesManifest from '${routesManifest}' + + import { getApiHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/api-handler' + + const apiHandler = getApiHandler({ + pageModule: require("${absolutePagePath}"), + rewrites: routesManifest.rewrites, + i18n: ${i18n || 'undefined'}, + page: "${page}", + basePath: "${basePath}", + pageIsDynamic: ${pageIsDynamicRoute}, + encodedPreviewProps: ${encodedPreviewProps}, + experimental: { + onError, + initServer, + } + }) + export default apiHandler + ` + } else { + return ` + import initServer from 'next-plugin-loader?middleware=on-init-server!' + import onError from 'next-plugin-loader?middleware=on-error-server!' + import 'next/dist/next-server/server/node-polyfill-fetch' + import routesManifest from '${routesManifest}' + import buildManifest from '${buildManifest}' + import reactLoadableManifest from '${reactLoadableManifest}' + ${envLoading} ${runtimeConfigImports} ${ - /* - this needs to be called first so its available for any other imports - */ + // this needs to be called first so its available for any other imports runtimeConfigSetter } - import initServer from 'next-plugin-loader?middleware=on-init-server!' - import onError from 'next-plugin-loader?middleware=on-error-server!' - import 'next/dist/next-server/server/node-polyfill-fetch' - import routesManifest from '${routesManifest}' - - import { getApiHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/api-handler' - - const apiHandler = getApiHandler({ - pageModule: require("${absolutePagePath}"), + import { getPageHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/page-handler' + + const appMod = require('${absoluteAppPath}') + let App = appMod.default || appMod.then && appMod.then(mod => mod.default); + + const compMod = require('${absolutePagePath}') + + const Component = compMod.default || compMod.then && compMod.then(mod => mod.default) + export default Component + export const getStaticProps = compMod['getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['getStaticProp' + 's']) + export const getStaticPaths = compMod['getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['getStaticPath' + 's']) + export const getServerSideProps = compMod['getServerSideProp' + 's'] || compMod.then && compMod.then(mod => mod['getServerSideProp' + 's']) + + // kept for detecting legacy exports + export const unstable_getStaticParams = compMod['unstable_getStaticParam' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticParam' + 's']) + export const unstable_getStaticProps = compMod['unstable_getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticProp' + 's']) + export const unstable_getStaticPaths = compMod['unstable_getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticPath' + 's']) + export const unstable_getServerProps = compMod['unstable_getServerProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getServerProp' + 's']) + + export let config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {} + export const _app = App + + const { renderReqToHTML, render } = getPageHandler({ + pageModule: compMod, + pageComponent: Component, + pageConfig: config, + appModule: App, + documentModule: require("${absoluteDocumentPath}"), + errorModule: require("${absoluteErrorPath}"), + notFoundModule: ${ + absolute404Path ? `require("${absolute404Path}")` : undefined + }, + pageGetStaticProps: getStaticProps, + pageGetStaticPaths: getStaticPaths, + pageGetServerSideProps: getServerSideProps, + + assetPrefix: "${assetPrefix}", + canonicalBase: "${canonicalBase}", + generateEtags: ${generateEtags || 'false'}, + poweredByHeader: ${poweredByHeader || 'false'}, + + runtimeConfig, + buildManifest, + reactLoadableManifest, + rewrites: routesManifest.rewrites, i18n: ${i18n || 'undefined'}, page: "${page}", + buildId: "${buildId}", + escapedBuildId: "${escapedBuildId}", basePath: "${basePath}", pageIsDynamic: ${pageIsDynamicRoute}, encodedPreviewProps: ${encodedPreviewProps}, @@ -116,84 +194,10 @@ const nextServerlessLoader: loader.Loader = function () { initServer, } }) - export default apiHandler + export { renderReqToHTML, render } ` - } else { - return ` - import initServer from 'next-plugin-loader?middleware=on-init-server!' - import onError from 'next-plugin-loader?middleware=on-error-server!' - import 'next/dist/next-server/server/node-polyfill-fetch' - import routesManifest from '${routesManifest}' - import buildManifest from '${buildManifest}' - import reactLoadableManifest from '${reactLoadableManifest}' - - ${envLoading} - ${runtimeConfigImports} - ${ - // this needs to be called first so its available for any other imports - runtimeConfigSetter } - import { getPageHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/page-handler' - - const appMod = require('${absoluteAppPath}') - let App = appMod.default || appMod.then && appMod.then(mod => mod.default); - - const compMod = require('${absolutePagePath}') - - const Component = compMod.default || compMod.then && compMod.then(mod => mod.default) - export default Component - export const getStaticProps = compMod['getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['getStaticProp' + 's']) - export const getStaticPaths = compMod['getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['getStaticPath' + 's']) - export const getServerSideProps = compMod['getServerSideProp' + 's'] || compMod.then && compMod.then(mod => mod['getServerSideProp' + 's']) - - // kept for detecting legacy exports - export const unstable_getStaticParams = compMod['unstable_getStaticParam' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticParam' + 's']) - export const unstable_getStaticProps = compMod['unstable_getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticProp' + 's']) - export const unstable_getStaticPaths = compMod['unstable_getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticPath' + 's']) - export const unstable_getServerProps = compMod['unstable_getServerProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getServerProp' + 's']) - - export let config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {} - export const _app = App - - const { renderReqToHTML, render } = getPageHandler({ - pageModule: compMod, - pageComponent: Component, - pageConfig: config, - appModule: App, - documentModule: require("${absoluteDocumentPath}"), - errorModule: require("${absoluteErrorPath}"), - notFoundModule: ${ - absolute404Path ? `require("${absolute404Path}")` : undefined - }, - pageGetStaticProps: getStaticProps, - pageGetStaticPaths: getStaticPaths, - pageGetServerSideProps: getServerSideProps, - - assetPrefix: "${assetPrefix}", - canonicalBase: "${canonicalBase}", - generateEtags: ${generateEtags || 'false'}, - poweredByHeader: ${poweredByHeader || 'false'}, - - runtimeConfig, - buildManifest, - reactLoadableManifest, - - rewrites: routesManifest.rewrites, - i18n: ${i18n || 'undefined'}, - page: "${page}", - buildId: "${buildId}", - escapedBuildId: "${escapedBuildId}", - basePath: "${basePath}", - pageIsDynamic: ${pageIsDynamicRoute}, - encodedPreviewProps: ${encodedPreviewProps}, - experimental: { - onError, - initServer, - } - }) - export { renderReqToHTML, render } - ` - } + }) } export default nextServerlessLoader diff --git a/packages/next/build/webpack/plugins/build-manifest-plugin.ts b/packages/next/build/webpack/plugins/build-manifest-plugin.ts index eba337b232dbf..dfe28783c1a0b 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -14,6 +14,7 @@ import getRouteFromEntrypoint from '../../../next-server/server/get-route-from-e import { ampFirstEntryNamesMap } from './next-drop-client-page-plugin' import { Rewrite } from '../../../lib/load-custom-routes' import { getSortedRoutes } from '../../../next-server/lib/router/utils' +import { tracer, traceFn } from '../../tracer' // @ts-ignore: TODO: remove ignore when webpack 5 is stable const { RawSource } = webpack.sources || sources @@ -30,31 +31,36 @@ function generateClientManifest( assetMap: BuildManifest, rewrites: Rewrite[] ): string { - const clientManifest: ClientBuildManifest = { - // TODO: update manifest type to include rewrites - __rewrites: rewrites as any, - } - const appDependencies = new Set(assetMap.pages['/_app']) - const sortedPageKeys = getSortedRoutes(Object.keys(assetMap.pages)) - - sortedPageKeys.forEach((page) => { - const dependencies = assetMap.pages[page] - - if (page === '/_app') return - // Filter out dependencies in the _app entry, because those will have already - // been loaded by the client prior to a navigation event - const filteredDeps = dependencies.filter((dep) => !appDependencies.has(dep)) - - // The manifest can omit the page if it has no requirements - if (filteredDeps.length) { - clientManifest[page] = filteredDeps + const span = tracer.startSpan('NextJsBuildManifest-generateClientManifest') + return traceFn(span, () => { + const clientManifest: ClientBuildManifest = { + // TODO: update manifest type to include rewrites + __rewrites: rewrites as any, } - }) - // provide the sorted pages as an array so we don't rely on the object's keys - // being in order and we don't slow down look-up time for page assets - clientManifest.sortedPages = sortedPageKeys + const appDependencies = new Set(assetMap.pages['/_app']) + const sortedPageKeys = getSortedRoutes(Object.keys(assetMap.pages)) + + sortedPageKeys.forEach((page) => { + const dependencies = assetMap.pages[page] + + if (page === '/_app') return + // Filter out dependencies in the _app entry, because those will have already + // been loaded by the client prior to a navigation event + const filteredDeps = dependencies.filter( + (dep) => !appDependencies.has(dep) + ) + + // The manifest can omit the page if it has no requirements + if (filteredDeps.length) { + clientManifest[page] = filteredDeps + } + }) + // provide the sorted pages as an array so we don't rely on the object's keys + // being in order and we don't slow down look-up time for page assets + clientManifest.sortedPages = sortedPageKeys - return devalue(clientManifest) + return devalue(clientManifest) + }) } function isJsFile(file: string): boolean { @@ -95,113 +101,120 @@ export default class BuildManifestPlugin { } createAssets(compilation: any, assets: any) { - const namedChunks: Map = - compilation.namedChunks - const assetMap: DeepMutable = { - polyfillFiles: [], - devFiles: [], - ampDevFiles: [], - lowPriorityFiles: [], - pages: { '/_app': [] }, - ampFirstPages: [], - } + const span = tracer.startSpan('NextJsBuildManifest-createassets') + return traceFn(span, () => { + const namedChunks: Map = + compilation.namedChunks + const assetMap: DeepMutable = { + polyfillFiles: [], + devFiles: [], + ampDevFiles: [], + lowPriorityFiles: [], + pages: { '/_app': [] }, + ampFirstPages: [], + } - const ampFirstEntryNames = ampFirstEntryNamesMap.get(compilation) - if (ampFirstEntryNames) { - for (const entryName of ampFirstEntryNames) { - const pagePath = getRouteFromEntrypoint(entryName) - if (!pagePath) { - continue - } + const ampFirstEntryNames = ampFirstEntryNamesMap.get(compilation) + if (ampFirstEntryNames) { + for (const entryName of ampFirstEntryNames) { + const pagePath = getRouteFromEntrypoint(entryName) + if (!pagePath) { + continue + } - assetMap.ampFirstPages.push(pagePath) + assetMap.ampFirstPages.push(pagePath) + } } - } - const mainJsChunk = namedChunks.get(CLIENT_STATIC_FILES_RUNTIME_MAIN) + const mainJsChunk = namedChunks.get(CLIENT_STATIC_FILES_RUNTIME_MAIN) - const mainJsFiles: string[] = getFilesArray(mainJsChunk?.files).filter( - isJsFile - ) + const mainJsFiles: string[] = getFilesArray(mainJsChunk?.files).filter( + isJsFile + ) - const polyfillChunk = namedChunks.get(CLIENT_STATIC_FILES_RUNTIME_POLYFILLS) + const polyfillChunk = namedChunks.get( + CLIENT_STATIC_FILES_RUNTIME_POLYFILLS + ) - // Create a separate entry for polyfills - assetMap.polyfillFiles = getFilesArray(polyfillChunk?.files).filter( - isJsFile - ) + // Create a separate entry for polyfills + assetMap.polyfillFiles = getFilesArray(polyfillChunk?.files).filter( + isJsFile + ) - const reactRefreshChunk = namedChunks.get( - CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH - ) - assetMap.devFiles = getFilesArray(reactRefreshChunk?.files).filter(isJsFile) + const reactRefreshChunk = namedChunks.get( + CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH + ) + assetMap.devFiles = getFilesArray(reactRefreshChunk?.files).filter( + isJsFile + ) - for (const entrypoint of compilation.entrypoints.values()) { - const isAmpRuntime = entrypoint.name === CLIENT_STATIC_FILES_RUNTIME_AMP + for (const entrypoint of compilation.entrypoints.values()) { + const isAmpRuntime = entrypoint.name === CLIENT_STATIC_FILES_RUNTIME_AMP - if (isAmpRuntime) { - for (const file of entrypoint.getFiles()) { - if (!(isJsFile(file) || file.endsWith('.css'))) { - continue + if (isAmpRuntime) { + for (const file of entrypoint.getFiles()) { + if (!(isJsFile(file) || file.endsWith('.css'))) { + continue + } + + assetMap.ampDevFiles.push(file.replace(/\\/g, '/')) } + continue + } + const pagePath = getRouteFromEntrypoint(entrypoint.name) - assetMap.ampDevFiles.push(file.replace(/\\/g, '/')) + if (!pagePath) { + continue } - continue - } - const pagePath = getRouteFromEntrypoint(entrypoint.name) - if (!pagePath) { - continue - } + const filesForEntry: string[] = [] - const filesForEntry: string[] = [] + // getFiles() - helper function to read the files for an entrypoint from stats object + for (const file of entrypoint.getFiles()) { + if (!(isJsFile(file) || file.endsWith('.css'))) { + continue + } - // getFiles() - helper function to read the files for an entrypoint from stats object - for (const file of entrypoint.getFiles()) { - if (!(isJsFile(file) || file.endsWith('.css'))) { - continue + filesForEntry.push(file.replace(/\\/g, '/')) } - filesForEntry.push(file.replace(/\\/g, '/')) + assetMap.pages[pagePath] = [...mainJsFiles, ...filesForEntry] } - assetMap.pages[pagePath] = [...mainJsFiles, ...filesForEntry] - } - - // Add the runtime build manifest file (generated later in this file) - // as a dependency for the app. If the flag is false, the file won't be - // downloaded by the client. - assetMap.lowPriorityFiles.push( - `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_buildManifest.js` - ) + // Add the runtime build manifest file (generated later in this file) + // as a dependency for the app. If the flag is false, the file won't be + // downloaded by the client. + assetMap.lowPriorityFiles.push( + `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_buildManifest.js` + ) - // Add the runtime ssg manifest file as a lazy-loaded file dependency. - // We also stub this file out for development mode (when it is not - // generated). - const srcEmptySsgManifest = `self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()` + // Add the runtime ssg manifest file as a lazy-loaded file dependency. + // We also stub this file out for development mode (when it is not + // generated). + const srcEmptySsgManifest = `self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()` - const ssgManifestPath = `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_ssgManifest.js` - assetMap.lowPriorityFiles.push(ssgManifestPath) - assets[ssgManifestPath] = new RawSource(srcEmptySsgManifest) + const ssgManifestPath = `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_ssgManifest.js` + assetMap.lowPriorityFiles.push(ssgManifestPath) + assets[ssgManifestPath] = new RawSource(srcEmptySsgManifest) - assetMap.pages = Object.keys(assetMap.pages) - .sort() - // eslint-disable-next-line - .reduce((a, c) => ((a[c] = assetMap.pages[c]), a), {} as any) + assetMap.pages = Object.keys(assetMap.pages) + .sort() + // eslint-disable-next-line + .reduce((a, c) => ((a[c] = assetMap.pages[c]), a), {} as any) - assets[BUILD_MANIFEST] = new RawSource(JSON.stringify(assetMap, null, 2)) + assets[BUILD_MANIFEST] = new RawSource(JSON.stringify(assetMap, null, 2)) - const clientManifestPath = `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_buildManifest.js` + const clientManifestPath = `${CLIENT_STATIC_FILES_PATH}/${this.buildId}/_buildManifest.js` - assets[clientManifestPath] = new RawSource( - `self.__BUILD_MANIFEST = ${generateClientManifest( - assetMap, - this.rewrites - )};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()` - ) + assets[clientManifestPath] = new RawSource( + `self.__BUILD_MANIFEST = ${generateClientManifest( + assetMap, + this.rewrites + )};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()` + ) - return assets + return assets + }) } apply(compiler: Compiler) { diff --git a/packages/next/compiled/babel-loader/index.js b/packages/next/compiled/babel-loader/index.js deleted file mode 100644 index 0f49ec4a2c786..0000000000000 --- a/packages/next/compiled/babel-loader/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports=(()=>{"use strict";var e={0:e=>{const t=/^[^:]+: /;const n=e=>{if(e instanceof SyntaxError){e.name="SyntaxError";e.message=e.message.replace(t,"");e.hideStack=true}else if(e instanceof TypeError){e.name=null;e.message=e.message.replace(t,"");e.hideStack=true}return e};class LoaderError extends Error{constructor(e){super();const{name:t,message:o,codeFrame:i,hideStack:r}=n(e);this.name="BabelLoaderError";this.message=`${t?`${t}: `:""}${o}\n\n${i}\n`;this.hideStack=r;Error.captureStackTrace(this,this.constructor)}}e.exports=LoaderError},420:(e,t,n)=>{function asyncGeneratorStep(e,t,n,o,i,r,a){try{var s=e[r](a);var c=s.value}catch(e){n(e);return}if(s.done){t(c)}else{Promise.resolve(c).then(o,i)}}function _asyncToGenerator(e){return function(){var t=this,n=arguments;return new Promise(function(o,i){var r=e.apply(t,n);function _next(e){asyncGeneratorStep(r,o,i,_next,_throw,"next",e)}function _throw(e){asyncGeneratorStep(r,o,i,_next,_throw,"throw",e)}_next(undefined)})}}const o=n(747);const i=n(87);const r=n(622);const a=n(761);const s=n(417);const c=n(327);const l=n(844);const p=n(677);const u=n(850);let d=null;const f=p(o.readFile);const b=p(o.writeFile);const h=p(a.gunzip);const y=p(a.gzip);const m=p(c);const g=function(){var e=_asyncToGenerator(function*(e,t){const n=yield f(e+(t?".gz":""));const o=t?yield h(n):n;return JSON.parse(o.toString())});return function read(t,n){return e.apply(this,arguments)}}();const w=function(){var e=_asyncToGenerator(function*(e,t,n){const o=JSON.stringify(n);const i=t?yield y(o):o;return yield b(e+(t?".gz":""),i)});return function write(t,n,o){return e.apply(this,arguments)}}();const x=function(e,t,n){const o=s.createHash("md4");const i=JSON.stringify({source:e,options:n,identifier:t});o.update(i);return o.digest("hex")+".json"};const _=function(){var e=_asyncToGenerator(function*(e,t){const{source:n,options:o={},cacheIdentifier:a,cacheDirectory:s,cacheCompression:c}=t;const l=r.join(e,x(n,a,o));try{return yield g(l,c)}catch(e){}const p=typeof s!=="string"&&e!==i.tmpdir();try{yield m(e)}catch(e){if(p){return _(i.tmpdir(),t)}throw e}const d=yield u(n,o);try{yield w(l,c,d)}catch(e){if(p){return _(i.tmpdir(),t)}throw e}return d});return function handleCache(t,n){return e.apply(this,arguments)}}();e.exports=function(){var e=_asyncToGenerator(function*(e){let t;if(typeof e.cacheDirectory==="string"){t=e.cacheDirectory}else{if(d===null){d=l({name:"babel-loader"})||i.tmpdir()}t=d}return yield _(t,e)});return function(t){return e.apply(this,arguments)}}()},826:(e,t,n)=>{function asyncGeneratorStep(e,t,n,o,i,r,a){try{var s=e[r](a);var c=s.value}catch(e){n(e);return}if(s.done){t(c)}else{Promise.resolve(c).then(o,i)}}function _asyncToGenerator(e){return function(){var t=this,n=arguments;return new Promise(function(o,i){var r=e.apply(t,n);function _next(e){asyncGeneratorStep(r,o,i,_next,_throw,"next",e)}function _throw(e){asyncGeneratorStep(r,o,i,_next,_throw,"throw",e)}_next(undefined)})}}let o;try{o=n(195)}catch(e){if(e.code==="MODULE_NOT_FOUND"){e.message+="\n babel-loader@8 requires Babel 7.x (the package '@babel/core'). "+"If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'."}throw e}if(/^6\./.test(o.version)){throw new Error("\n babel-loader@8 will not work with the '@babel/core@6' bridge package. "+"If you want to use Babel 6.x, install 'babel-loader@7'.")}const{version:i}=n(38);const r=n(420);const a=n(850);const s=n(159);const c=n(434);const{isAbsolute:l}=n(622);const p=n(710);const u=n(225);function subscribe(e,t,n){if(n[e]){n[e](t)}}e.exports=makeLoader();e.exports.custom=makeLoader;function makeLoader(e){const t=e?e(o):undefined;return function(e,n){const o=this.async();loader.call(this,e,n,t).then(e=>o(null,...e),e=>o(e))}}function loader(e,t,n){return _loader.apply(this,arguments)}function _loader(){_loader=_asyncToGenerator(function*(e,t,n){const d=this.resourcePath;let f=p.getOptions(this)||{};u(c,f,{name:"Babel loader"});if(f.customize!=null){if(typeof f.customize!=="string"){throw new Error("Customized loaders must be implemented as standalone modules.")}if(!l(f.customize)){throw new Error("Customized loaders must be passed as absolute paths, since "+"babel-loader has no way to know what they would be relative to.")}if(n){throw new Error("babel-loader's 'customize' option is not available when already "+"using a customized babel-loader wrapper.")}let e=require(f.customize);if(e.__esModule)e=e.default;if(typeof e!=="function"){throw new Error("Custom overrides must be functions.")}n=e(o)}let b;if(n&&n.customOptions){const o=yield n.customOptions.call(this,f,{source:e,map:t});b=o.custom;f=o.loader}if("forceEnv"in f){console.warn("The option `forceEnv` has been removed in favor of `envName` in Babel 7.")}if(typeof f.babelrc==="string"){console.warn("The option `babelrc` should not be set to a string anymore in the babel-loader config. "+"Please update your configuration and set `babelrc` to true or false.\n"+"If you want to specify a specific babel config file to inherit config from "+"please use the `extends` option.\nFor more information about this options see "+"https://babeljs.io/docs/core-packages/#options")}if(Object.prototype.hasOwnProperty.call(f,"sourceMap")&&!Object.prototype.hasOwnProperty.call(f,"sourceMaps")){f=Object.assign({},f,{sourceMaps:f.sourceMap});delete f.sourceMap}const h=Object.assign({},f,{filename:d,inputSourceMap:t||undefined,sourceMaps:f.sourceMaps===undefined?this.sourceMap:f.sourceMaps,sourceFileName:d});delete h.customize;delete h.cacheDirectory;delete h.cacheIdentifier;delete h.cacheCompression;delete h.metadataSubscribers;if(!o.loadPartialConfig){throw new Error(`babel-loader ^8.0.0-beta.3 requires @babel/core@7.0.0-beta.41, but `+`you appear to be using "${o.version}". Either update your `+`@babel/core version, or pin you babel-loader version to 8.0.0-beta.2`)}const y=o.loadPartialConfig(s(h,this.target));if(y){let o=y.options;if(n&&n.config){o=yield n.config.call(this,y,{source:e,map:t,customOptions:b})}if(o.sourceMaps==="inline"){o.sourceMaps=true}const{cacheDirectory:s=null,cacheIdentifier:c=JSON.stringify({options:o,"@babel/core":a.version,"@babel/loader":i}),cacheCompression:l=true,metadataSubscribers:p=[]}=f;let u;if(s){u=yield r({source:e,options:o,transform:a,cacheDirectory:s,cacheIdentifier:c,cacheCompression:l})}else{u=yield a(e,o)}if(typeof y.babelrc==="string"){this.addDependency(y.babelrc)}if(u){if(n&&n.result){u=yield n.result.call(this,u,{source:e,map:t,customOptions:b,config:y,options:o})}const{code:i,map:r,metadata:a}=u;p.forEach(e=>{subscribe(e,a,this)});return[i,r]}}return[e,t]});return _loader.apply(this,arguments)}},159:(e,t,n)=>{const o=n(195);e.exports=function injectCaller(e,t){if(!supportsCallerOption())return e;return Object.assign({},e,{caller:Object.assign({name:"babel-loader",target:t,supportsStaticESM:true,supportsDynamicImport:true,supportsTopLevelAwait:true},e.caller)})};let i=undefined;function supportsCallerOption(){if(i===undefined){try{o.loadPartialConfig({caller:undefined,babelrc:false,configFile:false});i=true}catch(e){i=false}}return i}},850:(e,t,n)=>{function asyncGeneratorStep(e,t,n,o,i,r,a){try{var s=e[r](a);var c=s.value}catch(e){n(e);return}if(s.done){t(c)}else{Promise.resolve(c).then(o,i)}}function _asyncToGenerator(e){return function(){var t=this,n=arguments;return new Promise(function(o,i){var r=e.apply(t,n);function _next(e){asyncGeneratorStep(r,o,i,_next,_throw,"next",e)}function _throw(e){asyncGeneratorStep(r,o,i,_next,_throw,"throw",e)}_next(undefined)})}}const o=n(195);const i=n(677);const r=n(0);const a=i(o.transform);e.exports=function(){var e=_asyncToGenerator(function*(e,t){let n;try{n=yield a(e,t)}catch(e){throw e.message&&e.codeFrame?new r(e):e}if(!n)return null;const{ast:o,code:i,map:s,metadata:c,sourceType:l}=n;if(s&&(!s.sourcesContent||!s.sourcesContent.length)){s.sourcesContent=[e]}return{ast:o,code:i,map:s,metadata:c,sourceType:l}});return function(t,n){return e.apply(this,arguments)}}();e.exports.version=o.version},677:e=>{const t=(e,t)=>(function(...n){const o=t.promiseModule;return new o((o,i)=>{if(t.multiArgs){n.push((...e)=>{if(t.errorFirst){if(e[0]){i(e)}else{e.shift();o(e)}}else{o(e)}})}else if(t.errorFirst){n.push((e,t)=>{if(e){i(e)}else{o(t)}})}else{n.push(o)}e.apply(this,n)})});e.exports=((e,n)=>{n=Object.assign({exclude:[/.+(Sync|Stream)$/],errorFirst:true,promiseModule:Promise},n);const o=typeof e;if(!(e!==null&&(o==="object"||o==="function"))){throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${e===null?"null":o}\``)}const i=e=>{const t=t=>typeof t==="string"?e===t:t.test(e);return n.include?n.include.some(t):!n.exclude.some(t)};let r;if(o==="function"){r=function(...o){return n.excludeMain?e(...o):t(e,n).apply(this,o)}}else{r=Object.create(Object.getPrototypeOf(e))}for(const o in e){const a=e[o];r[o]=typeof a==="function"&&i(o)?t(a,n):a}return r})},434:e=>{e.exports=JSON.parse('{"type":"object","properties":{"cacheDirectory":{"oneOf":[{"type":"boolean"},{"type":"string"}],"default":false},"cacheIdentifier":{"type":"string"},"cacheCompression":{"type":"boolean","default":true},"customize":{"type":"string","default":null}},"additionalProperties":true}')},38:e=>{e.exports=JSON.parse('{"name":"babel-loader","version":"8.1.0","description":"babel module loader for webpack","files":["lib"],"main":"lib/index.js","engines":{"node":">= 6.9"},"dependencies":{"find-cache-dir":"^2.1.0","loader-utils":"^1.4.0","mkdirp":"^0.5.3","pify":"^4.0.1","schema-utils":"^2.6.5"},"peerDependencies":{"@babel/core":"^7.0.0","webpack":">=2"},"devDependencies":{"@babel/cli":"^7.2.0","@babel/core":"^7.2.0","@babel/preset-env":"^7.2.0","ava":"^2.4.0","babel-eslint":"^10.0.1","babel-plugin-istanbul":"^5.1.0","babel-plugin-react-intl":"^4.1.19","cross-env":"^6.0.0","eslint":"^6.5.1","eslint-config-babel":"^9.0.0","eslint-config-prettier":"^6.3.0","eslint-plugin-flowtype":"^4.3.0","eslint-plugin-prettier":"^3.0.0","husky":"^3.0.7","lint-staged":"^9.4.1","nyc":"^14.1.1","prettier":"^1.15.3","react":"^16.0.0","react-intl":"^3.3.2","react-intl-webpack-plugin":"^0.3.0","rimraf":"^3.0.0","webpack":"^4.0.0"},"scripts":{"clean":"rimraf lib/","build":"babel src/ --out-dir lib/ --copy-files","format":"prettier --write --trailing-comma all \'src/**/*.js\' \'test/**/*.test.js\' \'test/helpers/*.js\' && prettier --write --trailing-comma es5 \'scripts/*.js\'","lint":"eslint src test","precommit":"lint-staged","prepublish":"yarn run clean && yarn run build","preversion":"yarn run test","test":"yarn run lint && cross-env BABEL_ENV=test yarn run build && yarn run test-only","test-only":"nyc ava"},"repository":{"type":"git","url":"https://github.com/babel/babel-loader.git"},"keywords":["webpack","loader","babel","es6","transpiler","module"],"author":"Luis Couto ","license":"MIT","bugs":{"url":"https://github.com/babel/babel-loader/issues"},"homepage":"https://github.com/babel/babel-loader","nyc":{"all":true,"include":["src/**/*.js"],"reporter":["text","json"],"sourceMap":false,"instrument":false},"ava":{"files":["test/**/*.test.js","!test/fixtures/**/*","!test/helpers/**/*"],"helpers":["**/helpers/**/*"],"sources":["src/**/*.js"]},"lint-staged":{"scripts/*.js":["prettier --trailing-comma es5 --write","git add"],"src/**/*.js":["prettier --trailing-comma all --write","git add"],"test/**/*.test.js":["prettier --trailing-comma all --write","git add"],"test/helpers/*.js":["prettier --trailing-comma all --write","git add"],"package.json":["node ./scripts/yarn-install.js","git add yarn.lock"]}}')},417:e=>{e.exports=require("crypto")},747:e=>{e.exports=require("fs")},710:e=>{e.exports=require("loader-utils")},195:e=>{e.exports=require("next/dist/compiled/babel/core")},844:e=>{e.exports=require("next/dist/compiled/find-cache-dir")},327:e=>{e.exports=require("next/dist/compiled/mkdirp")},225:e=>{e.exports=require("next/dist/compiled/schema-utils")},87:e=>{e.exports=require("os")},622:e=>{e.exports=require("path")},761:e=>{e.exports=require("zlib")}};var t={};function __webpack_require__(n){if(t[n]){return t[n].exports}var o=t[n]={exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete t[n]}return o.exports}__webpack_require__.ab=__dirname+"/";return __webpack_require__(826)})(); \ No newline at end of file diff --git a/packages/next/compiled/babel-loader/package.json b/packages/next/compiled/babel-loader/package.json deleted file mode 100644 index 2fafd2531ff9c..0000000000000 --- a/packages/next/compiled/babel-loader/package.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"babel-loader","main":"index.js","author":"Luis Couto ","license":"MIT"} diff --git a/packages/next/compiled/find-cache-dir/index.js b/packages/next/compiled/find-cache-dir/index.js index 05856153bf0d9..7d5712dd55b07 100644 --- a/packages/next/compiled/find-cache-dir/index.js +++ b/packages/next/compiled/find-cache-dir/index.js @@ -1 +1 @@ -module.exports=(()=>{var r={773:(r,e,t)=>{var s=t(622);r.exports=function(r,e){if(e){var t=e.map(function(e){return s.resolve(r,e)})}else{var t=r}var n=t.slice(1).reduce(function(r,e){if(!e.match(/^([A-Za-z]:)?\/|\\/)){throw new Error("relative path without a basedir")}var t=e.split(/\/+|\\+/);for(var s=0;r[s]===t[s]&&s1?n.join("/"):"/"}},449:(r,e,t)=>{"use strict";const s=t(622);const n=t(747);const o=t(773);const c=t(402);const i=t(270);const{env:a,cwd:u}=process;const d=r=>{try{n.accessSync(r,n.constants.W_OK);return true}catch(r){return false}};function useDirectory(r,e){if(e.create){i.sync(r)}if(e.thunk){return(...e)=>s.join(r,...e)}return r}function getNodeModuleDirectory(r){const e=s.join(r,"node_modules");if(!d(e)&&(n.existsSync(e)||!d(s.join(r)))){return}return e}r.exports=((r={})=>{if(a.CACHE_DIR&&!["true","false","1","0"].includes(a.CACHE_DIR)){return useDirectory(s.join(a.CACHE_DIR,"find-cache-dir"),r)}let{cwd:e=u()}=r;if(r.files){e=o(e,r.files)}e=c.sync(e);if(!e){return}const t=getNodeModuleDirectory(e);if(!t){return undefined}return useDirectory(s.join(e,"node_modules",".cache",r.name),r)})},270:(r,e,t)=>{"use strict";const s=t(747);const n=t(622);const{promisify:o}=t(669);const c=t(519);const i=c.satisfies(process.version,">=10.12.0");const a=r=>{if(process.platform==="win32"){const e=/[<>:"|?*]/.test(r.replace(n.parse(r).root,""));if(e){const e=new Error(`Path contains invalid characters: ${r}`);e.code="EINVAL";throw e}}};const u=r=>{const e={mode:511&~process.umask(),fs:s};return{...e,...r}};const d=r=>{const e=new Error(`operation not permitted, mkdir '${r}'`);e.code="EPERM";e.errno=-4048;e.path=r;e.syscall="mkdir";return e};const f=async(r,e)=>{a(r);e=u(e);const t=o(e.fs.mkdir);const c=o(e.fs.stat);if(i&&e.fs.mkdir===s.mkdir){const s=n.resolve(r);await t(s,{mode:e.mode,recursive:true});return s}const f=async r=>{try{await t(r,e.mode);return r}catch(e){if(e.code==="EPERM"){throw e}if(e.code==="ENOENT"){if(n.dirname(r)===r){throw d(r)}if(e.message.includes("null bytes")){throw e}await f(n.dirname(r));return f(r)}try{const t=await c(r);if(!t.isDirectory()){throw new Error("The path is not a directory")}}catch(r){throw e}return r}};return f(n.resolve(r))};r.exports=f;r.exports.sync=((r,e)=>{a(r);e=u(e);if(i&&e.fs.mkdirSync===s.mkdirSync){const t=n.resolve(r);s.mkdirSync(t,{mode:e.mode,recursive:true});return t}const t=r=>{try{e.fs.mkdirSync(r,e.mode)}catch(s){if(s.code==="EPERM"){throw s}if(s.code==="ENOENT"){if(n.dirname(r)===r){throw d(r)}if(s.message.includes("null bytes")){throw s}t(n.dirname(r));return t(r)}try{if(!e.fs.statSync(r).isDirectory()){throw new Error("The path is not a directory")}}catch(r){throw s}}return r};return t(n.resolve(r))})},402:(r,e,t)=>{"use strict";const s=t(622);const n=t(442);const o=async r=>{const e=await n("package.json",{cwd:r});return e&&s.dirname(e)};r.exports=o;r.exports.default=o;r.exports.sync=(r=>{const e=n.sync("package.json",{cwd:r});return e&&s.dirname(e)})},747:r=>{"use strict";r.exports=require("fs")},442:r=>{"use strict";r.exports=require("next/dist/compiled/find-up")},519:r=>{"use strict";r.exports=require("next/dist/compiled/semver")},622:r=>{"use strict";r.exports=require("path")},669:r=>{"use strict";r.exports=require("util")}};var e={};function __webpack_require__(t){if(e[t]){return e[t].exports}var s=e[t]={exports:{}};var n=true;try{r[t](s,s.exports,__webpack_require__);n=false}finally{if(n)delete e[t]}return s.exports}__webpack_require__.ab=__dirname+"/";return __webpack_require__(449)})(); \ No newline at end of file +module.exports=(()=>{var r={773:(r,e,t)=>{var s=t(622);r.exports=function(r,e){if(e){var t=e.map(function(e){return s.resolve(r,e)})}else{var t=r}var n=t.slice(1).reduce(function(r,e){if(!e.match(/^([A-Za-z]:)?\/|\\/)){throw new Error("relative path without a basedir")}var t=e.split(/\/+|\\+/);for(var s=0;r[s]===t[s]&&s1?n.join("/"):"/"}},430:(r,e,t)=>{"use strict";const s=t(622);const n=t(747);const o=t(773);const c=t(227);const i=t(618);const{env:a,cwd:u}=process;const d=r=>{try{n.accessSync(r,n.constants.W_OK);return true}catch(r){return false}};function useDirectory(r,e){if(e.create){i.sync(r)}if(e.thunk){return(...e)=>s.join(r,...e)}return r}function getNodeModuleDirectory(r){const e=s.join(r,"node_modules");if(!d(e)&&(n.existsSync(e)||!d(s.join(r)))){return}return e}r.exports=((r={})=>{if(a.CACHE_DIR&&!["true","false","1","0"].includes(a.CACHE_DIR)){return useDirectory(s.join(a.CACHE_DIR,"find-cache-dir"),r)}let{cwd:e=u()}=r;if(r.files){e=o(e,r.files)}e=c.sync(e);if(!e){return}const t=getNodeModuleDirectory(e);if(!t){return undefined}return useDirectory(s.join(e,"node_modules",".cache",r.name),r)})},618:(r,e,t)=>{"use strict";const s=t(747);const n=t(622);const{promisify:o}=t(669);const c=t(519);const i=c.satisfies(process.version,">=10.12.0");const a=r=>{if(process.platform==="win32"){const e=/[<>:"|?*]/.test(r.replace(n.parse(r).root,""));if(e){const e=new Error(`Path contains invalid characters: ${r}`);e.code="EINVAL";throw e}}};const u=r=>{const e={mode:511&~process.umask(),fs:s};return{...e,...r}};const d=r=>{const e=new Error(`operation not permitted, mkdir '${r}'`);e.code="EPERM";e.errno=-4048;e.path=r;e.syscall="mkdir";return e};const f=async(r,e)=>{a(r);e=u(e);const t=o(e.fs.mkdir);const c=o(e.fs.stat);if(i&&e.fs.mkdir===s.mkdir){const s=n.resolve(r);await t(s,{mode:e.mode,recursive:true});return s}const f=async r=>{try{await t(r,e.mode);return r}catch(e){if(e.code==="EPERM"){throw e}if(e.code==="ENOENT"){if(n.dirname(r)===r){throw d(r)}if(e.message.includes("null bytes")){throw e}await f(n.dirname(r));return f(r)}try{const t=await c(r);if(!t.isDirectory()){throw new Error("The path is not a directory")}}catch(r){throw e}return r}};return f(n.resolve(r))};r.exports=f;r.exports.sync=((r,e)=>{a(r);e=u(e);if(i&&e.fs.mkdirSync===s.mkdirSync){const t=n.resolve(r);s.mkdirSync(t,{mode:e.mode,recursive:true});return t}const t=r=>{try{e.fs.mkdirSync(r,e.mode)}catch(s){if(s.code==="EPERM"){throw s}if(s.code==="ENOENT"){if(n.dirname(r)===r){throw d(r)}if(s.message.includes("null bytes")){throw s}t(n.dirname(r));return t(r)}try{if(!e.fs.statSync(r).isDirectory()){throw new Error("The path is not a directory")}}catch(r){throw s}}return r};return t(n.resolve(r))})},227:(r,e,t)=>{"use strict";const s=t(622);const n=t(442);const o=async r=>{const e=await n("package.json",{cwd:r});return e&&s.dirname(e)};r.exports=o;r.exports.default=o;r.exports.sync=(r=>{const e=n.sync("package.json",{cwd:r});return e&&s.dirname(e)})},747:r=>{"use strict";r.exports=require("fs")},442:r=>{"use strict";r.exports=require("next/dist/compiled/find-up")},519:r=>{"use strict";r.exports=require("next/dist/compiled/semver")},622:r=>{"use strict";r.exports=require("path")},669:r=>{"use strict";r.exports=require("util")}};var e={};function __webpack_require__(t){if(e[t]){return e[t].exports}var s=e[t]={exports:{}};var n=true;try{r[t](s,s.exports,__webpack_require__);n=false}finally{if(n)delete e[t]}return s.exports}__webpack_require__.ab=__dirname+"/";return __webpack_require__(430)})(); \ No newline at end of file diff --git a/packages/next/package.json b/packages/next/package.json index 00488c370942c..af32a5466293f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -171,7 +171,6 @@ "ast-types": "0.13.2", "async-retry": "1.2.3", "async-sema": "3.0.0", - "babel-loader": "8.1.0", "babel-plugin-dynamic-import-node": "2.3.3", "cacache": "15.0.5", "cache-loader": "4.1.0", diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index ca2664d746de9..0712a9be2211d 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -125,14 +125,6 @@ export async function ncc_babel_bundle_packages(task, opts) { .target('compiled/babel/') } -// eslint-disable-next-line camelcase -externals['babel-loader'] = 'next/dist/compiled/babel-loader' -export async function ncc_babel_loader(task, opts) { - await task - .source(opts.src || relative(__dirname, require.resolve('babel-loader'))) - .ncc({ packageName: 'babel-loader', externals }) - .target('compiled/babel-loader') -} // eslint-disable-next-line camelcase externals['cacache'] = 'next/dist/compiled/cacache' export async function ncc_cacache(task, opts) { @@ -551,7 +543,6 @@ export async function ncc(task) { 'ncc_async_sema', 'ncc_babel_bundle', 'ncc_babel_bundle_packages', - 'ncc_babel_loader', 'ncc_cacache', 'ncc_cache_loader', 'ncc_ci_info', diff --git a/test/unit/next-babel-loader.unit.test.js b/test/unit/next-babel-loader.unit.test.js index e917a4391b07a..d59dd3d70ef52 100644 --- a/test/unit/next-babel-loader.unit.test.js +++ b/test/unit/next-babel-loader.unit.test.js @@ -6,7 +6,13 @@ process.env.NODE_ENV = 'production' require('next/dist/build/babel/preset') process.env.NODE_ENV = NODE_ENV -const loader = require('next/dist/build/webpack/loaders/next-babel-loader') +function interopRequireDefault(mod) { + return mod.default || mod +} + +const loader = interopRequireDefault( + require('next/dist/build/webpack/loaders/next-babel-loader') +) const os = require('os') const path = require('path') diff --git a/yarn.lock b/yarn.lock index e76d0244c8fa4..75aca1fbdc1a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3865,16 +3865,6 @@ babel-jest@^26.0.1: graceful-fs "^4.2.4" slash "^3.0.0" -babel-loader@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" - dependencies: - find-cache-dir "^2.1.0" - loader-utils "^1.4.0" - mkdirp "^0.5.3" - pify "^4.0.1" - schema-utils "^2.6.5" - babel-plugin-dynamic-import-node@2.3.3, babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -9857,7 +9847,7 @@ loader-utils@2.0.0, loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" -loader-utils@^1.0.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: +loader-utils@^1.0.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" dependencies: