dce-edge

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

DCE + Edge

DCE + Edge

Use this skill when changing conditional
require()
paths, Node-only imports, or edge/runtime branching.
当你需要修改条件式
require()
路径、仅Node.js可用的导入,或Edge/运行时分支逻辑时,可以参考本技能。

DCE-Safe
require()
Pattern

DCE安全的
require()
模式

Webpack only DCEs a
require()
when it sits inside the dead branch of an
if/else
whose condition DefinePlugin can evaluate at compile time.
ts
// CORRECT - webpack can eliminate the dead branch
if (process.env.__NEXT_USE_NODE_STREAMS) {
  require('node:stream')
} else {
  // web path
}
What does NOT work:
  • Early-return/throw guards: webpack doesn't do control-flow analysis for throws/returns, so the
    require()
    is still traced.
  • Bare
    if
    without
    else
    : works for inline
    node:*
    specifiers but NOT for
    require('./some-module')
    that pulls a new file into the module graph.
Always test edge changes with
pnpm test-start-webpack
on
test/e2e/app-dir/app/standalone.test.ts
(has edge routes), not with
NEXT_SKIP_ISOLATE=1
which skips the full webpack compilation.
Webpack仅会对位于if/else分支中、且条件可被DefinePlugin在编译时求值的死分支内的
require()
进行死代码消除(DCE)。
ts
// CORRECT - webpack can eliminate the dead branch
if (process.env.__NEXT_USE_NODE_STREAMS) {
  require('node:stream')
} else {
  // web path
}
以下写法无效:
  • 提前返回/抛出异常的保护逻辑:webpack不会对抛出/返回语句进行控制流分析,因此
    require()
    仍会被追踪到。
  • 无else分支的单独if语句:对于内联的
    node:*
    标识符有效,但对于会将新文件拉入模块图的
    require('./some-module')
    无效。
测试Edge相关修改时,请始终使用
pnpm test-start-webpack
运行
test/e2e/app-dir/app/standalone.test.ts
(包含Edge路由),不要使用
NEXT_SKIP_ISOLATE=1
,因为它会跳过完整的webpack编译流程。

TypeScript + DCE Interaction

TypeScript与DCE的交互

Use
if/else
(not two independent
if
blocks) when assigning a variable conditionally on
process.env.X
. TypeScript cannot prove exhaustiveness across
if (flag) { x = a }; if (!flag) { x = b }
and will error with "variable used before being assigned". The
if/else
pattern satisfies both TypeScript (definite assignment) and webpack DCE.
当根据
process.env.X
条件为变量赋值时,请使用if/else(而非两个独立的if块)。TypeScript无法在
if (flag) { x = a }; if (!flag) { x = b }
这种写法中证明赋值的穷尽性,会抛出“变量在赋值前被使用”的错误。if/else模式既能满足TypeScript的确定赋值要求,又能适配webpack的DCE机制。

Compile-Time Switcher Pattern

编译时切换器模式

Platform-specific code (node vs web) can use a single
.ts
switcher module that conditionally
require()
s either
.node.ts
or
.web.ts
into a typed variable, then re-exports the shared runtime API as named exports. Keep the branch as
if/else
so DefinePlugin can dead-code-eliminate the unused
require()
. Keep shared types canonical in
.node.ts
, with
.web.ts
importing them via
import type
and the switcher re-exporting types as needed. Examples:
stream-ops.ts
and
debug-channel-server.ts
.
针对平台特定的代码(Node.js vs Web),可以使用单个.ts切换器模块,通过条件式
require()
.node.ts
.web.ts
导入到一个类型化变量中,然后将共享的运行时API作为命名导出重新导出。请保持分支为if/else结构,以便DefinePlugin可以对未使用的
require()
进行死代码消除。将共享类型定义在
.node.ts
中作为标准版本,
.web.ts
通过
import type
导入这些类型,切换器模块按需重新导出类型。示例:
stream-ops.ts
debug-channel-server.ts

NEXT_RUNTIME
Is Not a Feature Flag

NEXT_RUNTIME
并非功能标志

In user-project webpack server compilers,
process.env.NEXT_RUNTIME
is inlined to
'nodejs'
. Guarding Node-only
require('node:*')
paths with
NEXT_RUNTIME === 'nodejs'
does not prune anything. For feature-gated codepaths, guard on the real feature define (e.g.
process.env.__NEXT_USE_NODE_STREAMS
).
在用户项目的webpack服务端编译器中,
process.env.NEXT_RUNTIME
会被内联为
'nodejs'
。使用
NEXT_RUNTIME === 'nodejs'
来保护仅Node.js可用的
require('node:*')
路径不会剔除任何代码。对于功能 gated 的代码路径,请使用真实的功能定义(如
process.env.__NEXT_USE_NODE_STREAMS
)作为判断条件。

Edge Runtime Constraints

Edge运行时约束

Edge routes do NOT use pre-compiled runtime bundles. They are compiled by the user's webpack/Turbopack, so
define-env.ts
controls DCE. Feature flags that gate
node:*
imports must be forced to
false
for edge builds in
define-env.ts
(
isEdgeServer ? false : flagValue
), otherwise webpack will try to resolve
node:stream
etc. and fail.
Edge路由不使用预编译的运行时包,它们由用户的webpack/Turbopack编译,因此
define-env.ts
控制着DCE流程。用于限制
node:*
导入的功能标志必须在
define-env.ts
中强制设为false以适配Edge构建(写法如
isEdgeServer ? false : flagValue
),否则webpack会尝试解析
node:stream
等模块并失败。

app-page.ts
Template Gotchas

app-page.ts
模板注意事项

  • app-page.ts
    is a build template compiled by the user's bundler. Any
    require()
    in this file is traced by webpack/turbopack at
    next build
    time. You cannot require internal modules with relative paths because they won't be resolvable from the user's project. Instead, export new helpers from
    entry-base.ts
    and access them via
    entryBase.*
    in the template.
  • Template helpers should stay out of
    RenderResult
    . If
    app-page.ts
    needs a Node-stream-only utility, prefer a small dedicated helper module in
    server/stream-utils/
    (with DCE-safe
    if/else
    +
    require()
    ).
  • app-page.ts
    是一个由用户打包工具编译的构建模板。该文件中的任何
    require()
    都会在
    next build
    时被webpack/turbopack追踪。你不能使用相对路径导入内部模块,因为这些模块在用户项目中无法被解析。相反,请从
    entry-base.ts
    导出新的工具函数,并在模板中通过
    entryBase.*
    访问它们。
  • 模板工具函数应避免出现在
    RenderResult
    中。如果
    app-page.ts
    需要仅Node.js流可用的工具,请优先使用
    server/stream-utils/
    中的小型专用工具模块(配合DCE安全的if/else +
    require()
    模式)。

Verification

验证方式

  • Validate edge bundling regressions with
    pnpm test-start-webpack test/e2e/app-dir/app/standalone.test.ts
  • For module-resolution/build-graph fixes, verify without
    NEXT_SKIP_ISOLATE=1
  • 使用
    pnpm test-start-webpack test/e2e/app-dir/app/standalone.test.ts
    验证Edge打包是否出现回归问题
  • 对于模块解析/构建图修复,请在不使用
    NEXT_SKIP_ISOLATE=1
    的情况下进行验证

Related Skills

相关技能

  • $flags
    - flag wiring (config/schema/define-env/runtime env)
  • $react-vendoring
    - entry-base boundaries and vendored React
  • $runtime-debug
    - reproduction and verification workflow
  • $flags
    - 标志配置(config/schema/define-env/runtime env)
  • $react-vendoring
    - entry-base边界与 vendored React
  • $runtime-debug
    - 复现与验证工作流