Add profiling to webpack loaders (#20392)

Follow-up to #20357 with additional tracers.
This commit is contained in:
Tim Neutkens 2020-12-29 22:21:35 +01:00 committed by GitHub
parent 52270af307
commit 5c5108fe0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 588 additions and 288 deletions

3
.vscode/launch.json vendored
View file

@ -22,7 +22,8 @@
"runtimeExecutable": "yarn",
"runtimeArgs": ["run", "debug", "build", "test/integration/basic"],
"skipFiles": ["<node_internals>/**"],
"port": 9229
"port": 9229,
"outFiles": ["${workspaceFolder}/packages/next/dist/**/*"]
},
{
"name": "Launch app production",

View file

@ -4,5 +4,6 @@
"javascriptreact",
{ "language": "typescript", "autoFix": true },
{ "language": "typescriptreact", "autoFix": true }
]
],
"debug.javascript.unmapMissingSources": true
}

View file

@ -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

View file

@ -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
})
}

View file

@ -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]
})
}

View file

@ -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 }
}

View file

@ -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

View file

@ -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

View file

@ -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 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 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 escapedBuildId = escapeRegexp(buildId)
const pageIsDynamicRoute = isDynamicRoute(page)
const encodedPreviewProps = devalue(
JSON.parse(previewProps) as __ApiPreviewProps
)
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 envLoading = `
const { processEnv } = require('@next/env')
processEnv(${Buffer.from(loadedEnvFiles, 'base64').toString()})
`
: ''
const runtimeConfigSetter = runtimeConfig
? `
const runtimeConfig = ${runtimeConfig}
setConfig(runtimeConfig)
`
: 'const runtimeConfig = {}'
const runtimeConfigImports = runtimeConfig
? `
const { setConfig } = require('next/config')
`
: ''
if (page.match(API_ROUTE)) {
return `
${envLoading}
${runtimeConfigImports}
${
/*
this needs to be called first so its available for any other imports
*/
runtimeConfigSetter
}
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}'
import { getApiHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/api-handler'
${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,
const apiHandler = getApiHandler({
pageModule: require("${absolutePagePath}"),
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

View file

@ -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))
return devalue(clientManifest)
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)
})
}
function isJsFile(file: string): boolean {
@ -95,113 +101,120 @@ export default class BuildManifestPlugin {
}
createAssets(compilation: any, assets: any) {
const namedChunks: Map<string, CompilationType.Chunk> =
compilation.namedChunks
const assetMap: DeepMutable<BuildManifest> = {
polyfillFiles: [],
devFiles: [],
ampDevFiles: [],
lowPriorityFiles: [],
pages: { '/_app': [] },
ampFirstPages: [],
}
const span = tracer.startSpan('NextJsBuildManifest-createassets')
return traceFn(span, () => {
const namedChunks: Map<string, CompilationType.Chunk> =
compilation.namedChunks
const assetMap: DeepMutable<BuildManifest> = {
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
}
assetMap.ampFirstPages.push(pagePath)
}
}
const mainJsChunk = namedChunks.get(CLIENT_STATIC_FILES_RUNTIME_MAIN)
const mainJsFiles: string[] = getFilesArray(mainJsChunk?.files).filter(
isJsFile
)
const polyfillChunk = namedChunks.get(
CLIENT_STATIC_FILES_RUNTIME_POLYFILLS
)
// 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
)
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
}
assetMap.ampDevFiles.push(file.replace(/\\/g, '/'))
}
continue
}
const pagePath = getRouteFromEntrypoint(entrypoint.name)
const ampFirstEntryNames = ampFirstEntryNamesMap.get(compilation)
if (ampFirstEntryNames) {
for (const entryName of ampFirstEntryNames) {
const pagePath = getRouteFromEntrypoint(entryName)
if (!pagePath) {
continue
}
assetMap.ampFirstPages.push(pagePath)
}
}
const filesForEntry: string[] = []
const mainJsChunk = namedChunks.get(CLIENT_STATIC_FILES_RUNTIME_MAIN)
const mainJsFiles: string[] = getFilesArray(mainJsChunk?.files).filter(
isJsFile
)
const polyfillChunk = namedChunks.get(CLIENT_STATIC_FILES_RUNTIME_POLYFILLS)
// 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)
for (const entrypoint of compilation.entrypoints.values()) {
const isAmpRuntime = entrypoint.name === CLIENT_STATIC_FILES_RUNTIME_AMP
if (isAmpRuntime) {
// 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
}
assetMap.ampDevFiles.push(file.replace(/\\/g, '/'))
}
continue
}
const pagePath = getRouteFromEntrypoint(entrypoint.name)
if (!pagePath) {
continue
}
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
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) {

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
{"name":"babel-loader","main":"index.js","author":"Luis Couto <hello@luiscouto.pt>","license":"MIT"}

View file

@ -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]&&s<Math.min(r.length,t.length);s++);return r.slice(0,s)},t[0].split(/\/+|\\+/));return n.length>1?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)})();
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]&&s<Math.min(r.length,t.length);s++);return r.slice(0,s)},t[0].split(/\/+|\\+/));return n.length>1?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)})();

View file

@ -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",

View file

@ -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',

View file

@ -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')

View file

@ -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: