studio-config-option-lifecycle

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Studio Config Option Lifecycle

Studio Config 选项生命周期

Make reload behavior explicit for every Studio-facing option. A config file is reset and re-executed when it changes, but a consumer only observes the new value if its code reads the option again.
为每个面向 Studio 的选项明确重载行为。配置文件发生变化时会被重置并重新执行,但只有当使用方的代码再次读取该选项时,使用方才能观察到新值。

Classify the whole option

对整个选项进行分类

Inspect every Studio consumer, then assign one lifecycle to the whole option:
  • Startup-fixed: Changing the value requires recreating a server, compiler, watcher, directory mapping, or other initialized resource.
  • Reloadable: Every Studio consumer can safely use the new value after the browser reload or at another deliberate request boundary.
If any consumer must be startup-fixed, make the option startup-fixed for all Studio consumers. Do not implement mixed lifecycle behavior.
Do not infer reloadability from
Config.set*()
state being updated. Config re-execution updates module state regardless of whether an already-created consumer observes it.
检查每个 Studio 使用方,然后为整个选项指定一种生命周期:
  • 启动固定(startup-fixed): 修改该值需要重新创建 server、compiler、watcher、directory mapping 或其他已初始化的 resource。
  • 可重载(reloadable): 所有 Studio 使用方都可以在 browser reload 后,或在另一个明确的 request boundary 安全使用新值。
如果任一使用方必须采用 startup-fixed,则该选项对所有 Studio 使用方都必须采用 startup-fixed。不要实现混合生命周期行为。
不要根据
Config.set*()
状态已更新这一点来推断可重载性。无论已创建的使用方是否会观察到变化,Config 重新执行都会更新 module state。

Wire startup-fixed values

接入启动固定值

Resolve the option once in
packages/cli/src/studio.ts
before calling
startStudio()
:
ts
const fixedValue = option.getValue({commandLine: parsedCli}).value;

await StudioServerInternals.startStudio({
	fixedValue,
});
Pass the value, not a getter, through
startStudio()
,
startServer()
, and the consumer. Keep new internal parameters required; use
T | null
when absence is valid.
Capture startup-fixed render settings in
StudioRenderJobFixedConfig
at the Studio queue boundary and thread that object into the job processor. Do not call
option.getValue()
from the processor, because config state may have changed since Studio startup.
Typical startup-fixed consumers include the Studio port, entry point, active compiler choice and override, polling mode, public directory and watcher, network binding, and cross-site-isolation headers.
在调用
startStudio()
之前,在
packages/cli/src/studio.ts
中解析一次该选项:
ts
const fixedValue = option.getValue({commandLine: parsedCli}).value;

await StudioServerInternals.startStudio({
	fixedValue,
});
将该值而不是 getter 传递给
startStudio()
、
startServer()
和使用方。新的内部参数应保持必填;当允许不存在值时,使用
T | null
。
在 Studio queue 边界,将 startup-fixed 的 render settings 捕获到
StudioRenderJobFixedConfig
中,并将该对象逐层传递给 job processor。不要在 processor 中调用
option.getValue()
,因为 config state 可能在 Studio 启动后已经发生变化。
典型的 startup-fixed 使用方包括 Studio port、entry point、active compiler choice 及 override、polling mode、public directory 和 watcher、network binding,以及 cross-site-isolation headers。

Wire reloadable values

接入可重载值

Read reloadable options through a getter that retains CLI precedence:
ts
const getValue = () =>
	option.getValue({commandLine: parsedCli}).value;

await StudioServerInternals.startStudio({
	getValue,
});
Pass the getter as a required internal callback and invoke it only at the boundary that should observe config changes, such as generating Studio HTML after the
config-file-changed
browser reload. Do not evaluate the getter earlier and pass its result onward.
Use the existing
getStudioRuntimeConfig()
path for values already represented by
StudioRuntimeConfig
. Be careful when extending that exported type: adding a required property can be a public API break. For independent HTML bootstrap values, pass a dedicated getter through the internal Studio server layers.
Only use this pattern when all Studio consumers are reloadable. Typical examples include UI behavior and HTML bootstrap defaults that do not require rebuilding initialized resources.
通过一个保留 CLI 优先级的 getter 读取 reloadable 选项:
ts
const getValue = () =>
	option.getValue({commandLine: parsedCli}).value;

await StudioServerInternals.startStudio({
	getValue,
});
将 getter 作为必填的内部 callback 传递,并且只在应观察 config 变化的边界调用它,例如在
config-file-changed
browser reload 之后生成 Studio HTML 时。不要提前对 getter 求值并继续传递其结果。
对于已由
StudioRuntimeConfig
表示的值,使用现有的
getStudioRuntimeConfig()
路径。扩展该 exported type 时需谨慎:添加 required property 可能构成 public API break。对于独立的 HTML bootstrap 值,通过 internal Studio server layers 传递专用 getter。
仅当所有 Studio 使用方都可重载时,才使用此模式。典型示例包括无需重建 initialized resources 的 UI behavior 和 HTML bootstrap defaults。

Resolve lifecycle conflicts

解决生命周期冲突

Search all reads of the option and decide each one independently:
sh
rg -n "myOption|setMyOption|my-cli-flag" packages
If the consumers do not all support reloading, capture the option once at Studio startup and pass that same value to every consumer. For example, if the active preview compiler cannot change bundlers, future render jobs must retain the startup bundler choice as well.
Treat aliases as one option. If a deprecated setter updates multiple underlying values, make every affected Studio consumer follow the stricter startup-fixed lifecycle.
搜索该选项的所有读取位置,并分别判断每个读取位置:
sh
rg -n "myOption|setMyOption|my-cli-flag" packages
如果各使用方并非都支持 reload,则在 Studio 启动时捕获一次该选项,并将同一个值传递给每个使用方。例如,如果 active preview compiler 无法切换 bundler,未来的 render job 也必须保留启动时的 bundler choice。
将 alias 视为同一个选项。如果 deprecated setter 更新多个 underlying values,则让每个受影响的 Studio 使用方都遵循更严格的 startup-fixed 生命周期。

Reset and rollback

重置与回滚

Ensure config reload resets the option before executing the changed file, so deleting a setter restores the default. Options registered through
BrowserSafeApis.options
and exposed directly through
Config
are reset by
resetBrowserSafeConfigOptions()
. Add an explicit reset in
ConfigInternals.resetConfigOptions()
for custom module state.
Preserve transactional reload behavior: an invalid changed config must leave the previous valid configuration active.
确保 config reload 在执行变更后的文件之前重置该选项,从而在删除 setter 后恢复 default。通过
BrowserSafeApis.options
注册的选项以及由
Config
直接暴露的选项,会被
resetBrowserSafeConfigOptions()
重置。对于 custom module state,在
ConfigInternals.resetConfigOptions()
中添加显式 reset。
保持事务性的 reload 行为:无效的变更后 config 必须让上一个有效配置继续生效。

Verify the lifecycle

验证生命周期

Use existing checks or a manual workflow to verify the classification:
  • Reloadable: change the option after the initial read, cross the intended reload/request boundary, and confirm the new value is observed.
  • Startup-fixed: capture the initial value, change config state, and confirm the initialized consumer still receives the original value.
  • Cross-consumer: confirm every Studio consumer receives the same startup snapshot when any one consumer requires it.
  • Reset: omit a previously set option on reload and confirm its default is restored.
  • Nullable internal inputs: verify call sites pass
    null
    explicitly when no value exists.
Run focused builds and checks for the affected packages:
sh
bunx turbo run make lint formatting --filter='@remotion/cli' --filter='@remotion/studio-server'
bun test packages/cli/src/test/config-reload.test.ts packages/cli/src/test/config-reset.test.ts
使用现有检查或手动流程验证生命周期:
  • 可重载: 在首次读取后修改选项,越过预期的 reload/request boundary,并确认观察到了新值。
  • 启动固定: 捕获初始值,更改 config state,并确认已初始化的使用方仍然接收到原始值。
  • 跨使用方: 当任一使用方要求 startup-fixed 时,确认每个 Studio 使用方都接收到相同的 startup snapshot。
  • 重置: reload 时省略先前设置的选项,并确认 default 已恢复。
  • 可空内部输入: 确认不存在值时,各 call site 都显式传入
    null
    。
对受影响的 package 运行聚焦的构建和检查:
sh
bunx turbo run make lint formatting --filter='@remotion/cli' --filter='@remotion/studio-server'
bun test packages/cli/src/test/config-reload.test.ts packages/cli/src/test/config-reset.test.ts