Skip to content

Commit f5f7f1b

Browse files
committed
Turbopack: Document the reasons for the current design of parse_segment_config_from_source
1 parent f272121 commit f5f7f1b

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

crates/next-core/src/segment_config.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,67 @@ pub enum ParseSegmentMode {
300300
App,
301301
}
302302

303+
/// Parse the raw source code of a file to get the segment config local to that file.
304+
///
305+
/// See [the Next.js documentation for Route Segment
306+
/// Configs](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config).
307+
///
308+
/// Pages router and middleware use this directly. App router uses
309+
/// `parse_segment_config_from_loader_tree` instead, which aggregates configuration information
310+
/// across multiple files.
311+
///
312+
/// ## A Note on Parsing the Raw Source Code
313+
///
314+
/// A better API would use `ModuleAssetContext::process` to convert the `Source` to a `Module`,
315+
/// instead of parsing the raw source code. That would ensure that things like webpack loaders can
316+
/// run before SWC tries to parse the file, e.g. to strip unsupported syntax using Babel. However,
317+
/// because the config includes `runtime`, we can't know which context to use until after parsing
318+
/// the file.
319+
///
320+
/// This could be solved with speculative parsing:
321+
/// 1. Speculatively process files and extract route segment configs using the Node.js
322+
/// `ModuleAssetContext` first. This is the common/happy codepath.
323+
/// 2. If we get a config specifying `runtime = "edge"`, we should use the Edge runtime's
324+
/// `ModuleAssetContext` and re-process the file(s), extracting the segment config again.
325+
/// 3. If we failed to get a configuration (e.g. a parse error), we need speculatively process with
326+
/// the Edge runtime and look for a `runtime = "edge"` configuration key. If that also fails,
327+
/// then we should report any issues/errors from the first attempt using the Node.js context.
328+
///
329+
/// While a speculative parsing algorithm is straightforward, there are a few factors that make it
330+
/// impractical to implement:
331+
///
332+
/// - The app router config is loaded across many different files (page, layout, or route handler,
333+
/// including an arbitrary number of those files in parallel routes), and once we discover that
334+
/// something specified edge runtime, we must restart that entire loop, so try/reparse logic can't
335+
/// be cleanly encapsulated to an operation over a single file.
336+
///
337+
/// - There's a lot of tracking that needs to happen to later suppress `Issue` collectibles on
338+
/// speculatively-executed `OperationVc`s.
339+
///
340+
/// - Most things default to the node.js runtime and can be overridden to edge runtime, but
341+
/// middleware is an exception, so different codepaths have different defaults.
342+
///
343+
/// The `runtime` option is going to be deprecated, and we may eventually remove edge runtime
344+
/// completely (in Next 18?), so it doesn't make sense to spend a ton of time improving logic around
345+
/// that. In the future, doing this the right way with the `ModuleAssetContext` will be easy (there
346+
/// will only be one, no speculative parsing is needed), and I think it's okay to use a hacky
347+
/// solution for a couple years until that day comes.
348+
///
349+
/// ## What does webpack do?
350+
///
351+
/// The logic is in `packages/next/src/build/analysis/get-page-static-info.ts`, but it's very
352+
/// similar to what we do here.
353+
///
354+
/// There are a couple of notable differences:
355+
///
356+
/// - The webpack implementation uses a regexp (`PARSE_PATTERN`) to skip parsing some files, but
357+
/// this regexp is imperfect and may also suppress some lints that we have. The performance
358+
/// benefit is small, so we're not currently doing this (but we could revisit that decision in the
359+
/// future).
360+
///
361+
/// - The `parseModule` helper function swallows errors (!) returning a `null` ast value when
362+
/// parsing fails. This seems bad, as it may lead to silently-ignored segment configs, so we don't
363+
/// want to do this.
303364
#[turbo_tasks::function]
304365
pub async fn parse_segment_config_from_source(
305366
source: ResolvedVc<Box<dyn Source>>,
@@ -1229,6 +1290,8 @@ async fn parse_route_matcher_from_js_value(
12291290
})
12301291
}
12311292

1293+
/// A wrapper around [`parse_segment_config_from_source`] that merges route segment configuration
1294+
/// information from all relevant files (page, layout, parallel routes, etc).
12321295
#[turbo_tasks::function]
12331296
pub async fn parse_segment_config_from_loader_tree(
12341297
loader_tree: Vc<AppPageLoaderTree>,

0 commit comments

Comments
 (0)