Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rest of options in experimental.turbotrace and documentation #41817

Merged
merged 1 commit into from Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 42 additions & 0 deletions docs/advanced-features/output-file-tracing.md
Expand Up @@ -66,3 +66,45 @@ module.exports = {

- There are some cases in which Next.js might fail to include required files, or might incorrectly include unused files. In those cases, you can export page configs props `unstable_includeFiles` and `unstable_excludeFiles` respectively. Each prop accepts an array of [minimatch globs](https://www.npmjs.com/package/minimatch) relative to the project's root to either include or exclude in the trace.
- Currently, Next.js does not do anything with the emitted `.nft.json` files. The files must be read by your deployment platform, for example [Vercel](https://vercel.com), to create a minimal deployment. In a future release, a new command is planned to utilize these `.nft.json` files.

## Experimental `turbotrace`

Tracing dependencies can be slow because it requires very complex computations and analysis. We created `turbotrace` in Rust as a faster and smarter alternative to the JavaScript implementation.

To enable it, you can add the following configuration to your `next.config.js`:

```js
// next.config.js
module.exports = {
experimental: {
turbotrace: {
// control the log level of the turbotrace, default is `error`
logLevel?:
| 'bug'
| 'fatal'
| 'error'
| 'warning'
| 'hint'
| 'note'
| 'suggestions'
| 'info',
// control if the log of turbotrace should contain the details of the analysis, default is `false`
logDetail?: boolean
// show all log messages without limit
// turbotrace only show 1 log message for each categories by default
logAll?: boolean
// control the context directory of the turbotrace
// files outside of the context directory will not be traced
// set the `experimental.outputFileTracingRoot` has the same effect
// if the `experimental.outputFileTracingRoot` and this option are both set, the `experimental.turbotrace.contextDirectory` will be used
contextDirectory?: string
// if there is `process.cwd()` expression in your code, you can set this option to tell `turbotrace` the value of `process.cwd()` while tracing.
// for example the require(process.cwd() + '/package.json') will be traced as require('/path/to/cwd/package.json')
processCwd?: string,
// control the maximum number of files that are passed to the `turbotrace`
// default is 128
maxFiles?: number;
},
},
}
```
2 changes: 1 addition & 1 deletion packages/next-swc/crates/napi/src/lib.rs
Expand Up @@ -48,8 +48,8 @@ use swc_core::{
pub mod minify;
pub mod parse;
pub mod transform;
pub mod turbo_tracing;
pub mod turbopack;
pub mod turbotrace;
pub mod util;

static COMPILER: Lazy<Arc<Compiler>> = Lazy::new(|| {
Expand Down
9 changes: 8 additions & 1 deletion packages/next/build/index.ts
Expand Up @@ -1751,7 +1751,10 @@ export default async function build(
} catch (_) {}
}

const root = config.experimental.outputFileTracingRoot || dir
const root =
config.experimental?.turbotrace?.contextDirectory ??
config.experimental?.outputFileTracingRoot ??
dir
const toTrace = [require.resolve('next/dist/server/next-server')]

// ensure we trace any dependencies needed for custom
Expand All @@ -1769,6 +1772,10 @@ export default async function build(
action: 'annotate',
input: toTrace,
contextDirectory: root,
logLevel: config.experimental.turbotrace.logLevel,
processCwd: config.experimental.turbotrace.processCwd,
logDetail: config.experimental.turbotrace.logDetail,
showAll: config.experimental.turbotrace.logAll,
})
} else {
serverResult = await nodeFileTrace(toTrace, {
Expand Down
Expand Up @@ -23,6 +23,8 @@ const TRACE_IGNORES = [
'**/*/next/dist/bin/next',
]

const TURBO_TRACE_DEFAULT_MAX_FILES = 128

function getModuleFromDependency(
compilation: any,
dep: any
Expand Down Expand Up @@ -390,13 +392,33 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
.traceAsyncFn(async () => {
const contextDirectory =
this.turbotrace?.contextDirectory ?? this.tracingRoot
const filesTracedInEntries: string[] =
await binding.turbo.startTrace({
action: 'print',
input: entriesToTrace,
contextDirectory,
processCwd: this.turbotrace?.processCwd ?? this.appDir,
})
const maxFiles =
this.turbotrace?.maxFiles ?? TURBO_TRACE_DEFAULT_MAX_FILES
let chunks = [...entriesToTrace]
let restChunks =
chunks.length > maxFiles ? chunks.splice(maxFiles) : []
let filesTracedInEntries: string[] = []
while (chunks.length) {
filesTracedInEntries = filesTracedInEntries.concat(
await binding.turbo.startTrace({
action: 'print',
input: chunks,
contextDirectory,
processCwd:
this.turbotrace?.processCwd ?? this.appDir,
logLevel: this.turbotrace?.logLevel,
showAll: this.turbotrace?.logAll,
})
)
chunks = restChunks
if (restChunks.length) {
restChunks =
chunks.length > maxFiles
? chunks.splice(maxFiles)
: []
}
}

// only trace the assets under the appDir
// exclude files from node_modules, entries and processed by webpack
const filesTracedFromEntries = filesTracedInEntries
Expand Down Expand Up @@ -763,13 +785,27 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
!binding?.isWasm &&
typeof binding.turbo.startTrace === 'function'
) {
await binding.turbo.startTrace({
action: 'annotate',
input: this.chunksToTrace,
contextDirectory:
this.turbotrace?.contextDirectory ?? this.tracingRoot,
processCwd: this.turbotrace?.processCwd ?? this.appDir,
})
const maxFiles =
this.turbotrace?.maxFiles ?? TURBO_TRACE_DEFAULT_MAX_FILES
let chunks = [...this.chunksToTrace]
let restChunks =
chunks.length > maxFiles ? chunks.splice(maxFiles) : []
while (chunks.length) {
await binding.turbo.startTrace({
action: 'annotate',
input: chunks,
contextDirectory:
this.turbotrace?.contextDirectory ?? this.tracingRoot,
processCwd: this.turbotrace?.processCwd ?? this.appDir,
showAll: this.turbotrace?.logAll,
logLevel: this.turbotrace?.logLevel,
})
chunks = restChunks
if (restChunks.length) {
restChunks =
chunks.length > maxFiles ? chunks.splice(maxFiles) : []
}
}
if (this.turbotraceOutputPath && this.turbotraceFiles) {
const existedNftFile = await nodeFs.promises
.readFile(this.turbotraceOutputPath, 'utf8')
Expand Down
6 changes: 6 additions & 0 deletions packages/next/server/config-schema.ts
Expand Up @@ -448,6 +448,9 @@ const configSchema = {
'info',
],
} as any,
logAll: {
type: 'boolean',
},
logDetail: {
type: 'boolean',
},
Expand All @@ -457,6 +460,9 @@ const configSchema = {
processCwd: {
type: 'string',
},
maxFiles: {
type: 'integer',
},
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions packages/next/server/config-shared.ts
Expand Up @@ -176,8 +176,10 @@ export interface ExperimentalConfig {
| 'suggestions'
| 'info'
logDetail?: boolean
logAll?: boolean
contextDirectory?: string
processCwd?: string
maxFiles?: number
}
}

Expand Down