Skip to content

Commit

Permalink
Make traces in development reliable (vercel#28990)
Browse files Browse the repository at this point in the history
Co-authored-by: Jiachi Liu <[email protected]>
  • Loading branch information
timneutkens and huozhi authored Sep 13, 2021
1 parent 48b37ed commit c1e5f5b
Show file tree
Hide file tree
Showing 41 changed files with 346 additions and 116 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ packages/create-next-app/templates/**
test/integration/eslint/**
test-timings.json
packages/next/build/swc/tests/fixture/**
bench/nested-deps/pages/**
bench/nested-deps/components/**
66 changes: 0 additions & 66 deletions bench/capture-trace.js

This file was deleted.

1 change: 1 addition & 0 deletions bench/nested-deps/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
components/*
182 changes: 182 additions & 0 deletions bench/nested-deps/fuzzponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#!/usr/bin/env node
const path = require('path')
const fs = require('fs')

const getSequenceGenerator = require('random-seed')
const generate = require('@babel/generator').default
const t = require('@babel/types')

const MIN_COMPONENT_NAME_LEN = 18
const MAX_COMPONENT_NAME_LEN = 24
const MIN_CHILDREN = 4
const MAX_CHILDREN = 80

const arrayUntil = (len) => [...Array(len)].map((_, i) => i)

const generateFunctionalComponentModule = (componentName, children = []) => {
const body = [
generateImport('React', 'react'),
...children.map((childName) => generateImport(childName, `./${childName}`)),
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(componentName),
t.arrowFunctionExpression(
[],
t.parenthesizedExpression(
generateJSXElement(
'div',
children.map((childName) => generateJSXElement(childName))
)
)
)
),
]),
t.exportDefaultDeclaration(t.identifier(componentName)),
]

return t.program(body, [], 'module')
}

const generateJSXElement = (componentName, children = null) =>
t.JSXElement(
t.JSXOpeningElement(t.JSXIdentifier(componentName), [], !children),
children ? t.JSXClosingElement(t.JSXIdentifier(componentName)) : null,
children || [],
!children
)

const generateImport = (componentName, requireString) =>
t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(componentName))],
t.stringLiteral(requireString)
)

const validFirstChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const validOtherChars = validFirstChars.toLowerCase()
function generateComponentName(seqGenerator, opts) {
const numOtherChars = seqGenerator.intBetween(opts.minLen, opts.maxLen)
const firstChar = validFirstChars[seqGenerator.range(validFirstChars.length)]
const otherChars = arrayUntil(numOtherChars).map(
() => validOtherChars[seqGenerator.range(validOtherChars.length)]
)
return `${firstChar}${otherChars.join('')}`
}

function* generateModules(name, remainingDepth, seqGenerator, opts) {
const filename = `${name}.${opts.extension}`
let ast

if (name === 'index') {
name = 'RootComponent'
}

if (remainingDepth === 0) {
ast = generateFunctionalComponentModule(name)
} else {
const numChildren = seqGenerator.intBetween(opts.minChild, opts.maxChild)
const children = arrayUntil(numChildren).map(() =>
generateComponentName(seqGenerator, opts)
)
ast = generateFunctionalComponentModule(name, children)

for (const child of children) {
yield* generateModules(child, remainingDepth - 1, seqGenerator, opts)
}
}

yield {
filename,
content: generate(ast).code,
}
}

function generateFuzzponents(outdir, seed, depth, opts) {
const seqGenerator = getSequenceGenerator(seed)

const filenames = new Set()
for (const { filename, content } of generateModules(
'index',
depth,
seqGenerator,
opts
)) {
if (filenames.has(filename)) {
throw new Error(
`Seed "${seed}" generates output with filename collisions.`
)
} else {
filenames.add(filename)
}
const fpath = path.join(outdir, filename)
fs.writeFileSync(fpath, `// ${filename}\n\n${content}`)
}
}

if (require.main === module) {
const { outdir, seed, depth, ...opts } = require('yargs')
.option('depth', {
alias: 'd',
demandOption: true,
describe: 'component hierarchy depth',
type: 'number',
})
.option('seed', {
alias: 's',
demandOption: true,
describe: 'prng seed',
type: 'number',
})
.option('outdir', {
alias: 'o',
demandOption: false,
default: process.cwd(),
describe: 'the directory where components should be written',
type: 'string',
normalize: true,
})
.option('minLen', {
demandOption: false,
default: MIN_COMPONENT_NAME_LEN,
describe: 'the smallest acceptible component name length',
type: 'number',
})
.option('maxLen', {
demandOption: false,
default: MAX_COMPONENT_NAME_LEN,
describe: 'the largest acceptible component name length',
type: 'number',
})
.option('minLen', {
demandOption: false,
default: MIN_COMPONENT_NAME_LEN,
describe: 'the smallest acceptible component name length',
type: 'number',
})
.option('maxLen', {
demandOption: false,
default: MAX_COMPONENT_NAME_LEN,
describe: 'the largest acceptible component name length',
type: 'number',
})
.option('minChild', {
demandOption: false,
default: MIN_CHILDREN,
describe: 'the smallest number of acceptible component children',
type: 'number',
})
.option('maxChild', {
demandOption: false,
default: MAX_CHILDREN,
describe: 'the largest number of acceptible component children',
type: 'number',
})
.option('extension', {
default: 'jsx',
describe: 'extension to use for generated components',
type: 'string',
}).argv

generateFuzzponents(outdir, seed, depth, opts)
}

module.exports = generateFuzzponents
9 changes: 9 additions & 0 deletions bench/nested-deps/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
eslint: {
ignoreDuringBuilds: true,
},
experimental: {
swcLoader: true,
swcMinify: true,
},
}
10 changes: 10 additions & 0 deletions bench/nested-deps/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"scripts": {
"prepare": "rm -rf components && node ./fuzzponent.js -d 2 -s 206 -o components",
"dev": "../../node_modules/.bin/next dev",
"build": "../../node_modules/.bin/next build",
"start": "../../node_modules/.bin/next start",
"dev-nocache": "rm -rf .next && yarn dev",
"build-nocache": "rm -rf .next && yarn build"
}
}
5 changes: 5 additions & 0 deletions bench/nested-deps/pages/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Comp from '../components/index.jsx'

export default function Home() {
return <Comp />
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@fullhuman/postcss-purgecss": "1.3.0",
"@mdx-js/loader": "0.18.0",
"@svgr/webpack": "5.5.0",
"@swc/cli": "0.1.49",
"@swc/core": "1.2.85",
"@swc/jest": "0.2.2",
"@testing-library/react": "11.2.5",
Expand Down Expand Up @@ -118,6 +119,7 @@
"prettier": "2.3.2",
"pretty-bytes": "5.3.0",
"pretty-ms": "7.0.0",
"random-seed": "0.3.0",
"react": "17.0.2",
"react-18": "npm:react@next",
"react-dom": "17.0.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/babel/loader/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getOptions } from 'next/dist/compiled/loader-utils'
import { Span } from '../../../telemetry/trace'
import { Span } from '../../../trace'
import transform from './transform'
import { NextJsLoaderContext } from './types'

Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/babel/loader/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import PluginPass from 'next/dist/compiled/babel/core-lib-plugin-pass'

import getConfig from './get-config'
import { consumeIterator } from './util'
import { Span } from '../../../telemetry/trace'
import { Span } from '../../../trace'
import { NextJsLoaderContext } from './types'

function getTraversalParams(file: any, pluginPairs: any[]) {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/babel/loader/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { loader } from 'next/dist/compiled/webpack/webpack'
import { Span } from '../../../telemetry/trace'
import { Span } from '../../../trace'

export interface NextJsLoaderContext extends loader.LoaderContext {
currentTraceSpan: Span
Expand Down
6 changes: 4 additions & 2 deletions packages/next/build/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { Span } from '../telemetry/trace'
import { Span } from '../trace'

export type CompilerResult = {
errors: string[]
Expand Down Expand Up @@ -42,7 +42,9 @@ export function runCompiler(
return new Promise((resolve, reject) => {
const compiler = webpack(config)
compiler.run((err: Error, stats: webpack.Stats) => {
const webpackCloseSpan = runWebpackSpan.traceChild('webpack-close')
const webpackCloseSpan = runWebpackSpan.traceChild('webpack-close', {
name: config.name,
})
webpackCloseSpan
.traceAsyncFn(() => closeCompiler(compiler))
.then(() => {
Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ import { generateBuildId } from './generate-build-id'
import { isWriteable } from './is-writeable'
import * as Log from './output/log'
import createSpinner from './spinner'
import { trace, flushAllTraces, setGlobal } from '../telemetry/trace'
import { trace, flushAllTraces, setGlobal } from '../trace'
import {
collectPages,
detectConflictingPaths,
Expand Down Expand Up @@ -1291,7 +1291,7 @@ export default async function build(
},
}

await exportApp(dir, exportOptions, exportConfig)
await exportApp(dir, exportOptions, nextBuildSpan, exportConfig)

const postBuildSpinner = createSpinner({
prefixText: `${Log.prefixes.info} Finalizing page optimization`,
Expand Down
5 changes: 5 additions & 0 deletions packages/next/build/output/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const prefixes = {
ready: chalk.green('ready') + ' -',
info: chalk.cyan('info') + ' -',
event: chalk.magenta('event') + ' -',
trace: chalk.magenta('trace') + ' -',
}

export function wait(...message: string[]) {
Expand All @@ -32,3 +33,7 @@ export function info(...message: string[]) {
export function event(...message: string[]) {
console.log(prefixes.event, ...message)
}

export function trace(...message: string[]) {
console.log(prefixes.trace, ...message)
}
3 changes: 3 additions & 0 deletions packages/next/build/output/store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import createStore from 'next/dist/compiled/unistore'
import stripAnsi from 'next/dist/compiled/strip-ansi'
import { flushAllTraces } from '../../trace'

import * as Log from './log'

Expand Down Expand Up @@ -88,4 +89,6 @@ store.subscribe((state) => {
}

Log.event('compiled successfully')
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
})
2 changes: 1 addition & 1 deletion packages/next/build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { UnwrapPromise } from '../lib/coalesced-function'
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
import * as Log from './output/log'
import { loadComponents } from '../server/load-components'
import { trace } from '../telemetry/trace'
import { trace } from '../trace'
import { setHttpAgentOptions } from '../server/config'
import { NextConfigComplete } from '../server/config-shared'

Expand Down
Loading

0 comments on commit c1e5f5b

Please sign in to comment.