fuels-ts 的 `fuels.config.ts` 配置文件完全指南:全部配置项、默认值与源码解析
本文以
fuels-ts(Fuel Network TypeScript SDK)中fuelsCLI 的 config-file.md 为骨架,系统讲解fuels.config.ts的全部配置选项。你将掌握每种配置项的作用、适用命令、默认行为、与其它配置的互斥关系,以及环境变量加载方式;同时通过packages/fuels/src/cli下的真实源码理解这些配置项在 CLI 启动链中如何被加载、校验与消费,从而能独立编写一份可运行的 Fuels 项目配置。
1. 配置文件是什么:CLI 的心脏
fuels 是 fuels-ts 仓库(根目录见 package.json)为 Fuel 开发者提供的命令行工具集。无论你执行 fuels build、fuels deploy、fuels dev 还是 fuels node,CLI 都会从当前工作目录解析一份 fuels.config.ts(也支持 fuels.config.js/.cjs/.mjs),把它作为类型生成、Sway 程序编译、合约部署以及本地节点管理等一系列操作的唯一事实来源。
从源码看,配置加载逻辑集中在 packages/fuels/src/cli/config/loadConfig.ts:CLI 使用 joycon 沿当前目录向上查找配置文件,再借助 bundle-require(内部基于 esbuild,target: 'ES2021'、platform: 'node'、format: 'esm')把 TypeScript 配置实时编译加载。因此,你可以在 fuels.config.ts 中自由使用 import、类型标注与异步逻辑,甚至把它写成一个默认导出的 createConfig({...}) 对象。
createConfig 本身是一个极轻的包装(见 packages/fuels/src/cli/utils/createConfig.ts),仅仅是为配置对象提供类型提示与校验的类型化入口,它不执行任何运行时变换。因此配置文件中常见的写法是:
import { createConfig } from 'fuels';
export default createConfig({
workspace: './sway-programs',
output: './src/sway-api',
});
下面的章节逐一说明 UserFuelsConfig 支持的每个配置项。完整的类型定义可查看 packages/fuels/src/cli/types.ts,其 JSDoc 注释中标注了每个字段的默认值语义;所有真实可运行的完整示例则沉淀在 apps/demo-fuels/fuels.config.full.ts 中。
2. 程序入口配置:workspace 与 contracts / predicates / scripts
这一组配置决定了 CLI 需要处理哪些 Sway 程序(合约、谓词、脚本),两者是“整仓模式”与“分目录模式”的关系。
2.1 workspace:指向 Forc workspace 的相对目录
workspace 是一个字符串,指向 Forc workspace 目录(即包含声明了 [workspace] members 的 Forc.toml 的目录):
// region workspace —— 摘自 apps/demo-fuels/fuels.config.full.ts
workspace: './sway-programs',
互斥约定:
workspace与contracts、predicates、scripts不兼容。二者只能择一:要么声明整个 Forc workspace,让 CLI 自动识别其中所有非 library 类型的成员;要么逐个显式列出三种程序目录。
2.2 contracts / predicates / scripts:分别列出程序目录
三者都是“字符串数组”,每一项是到对应类型 Sway 程序(或其所在目录)的相对路径:
// region contracts / predicates / scripts —— 摘自 apps/demo-fuels/fuels.config.full.ts
contracts: ['./sway-programs/contracts'],
predicates: ['./sway-programs/predicates'],
scripts: ['./sway-programs/scripts'],
互斥约定:
contracts、predicates、scripts三个属性均与workspace不兼容。
2.3 源码视角:workspace 模式下成员如何被解析
为什么推荐二选一?从 loadConfig.ts 可以看到两种模式的解析路径完全不同:
- 未配置
workspace时,contracts/predicates/scripts会被逐一resolve(cwd, path)转为绝对路径; - 配置了
workspace时,CLI 会先readForcToml(workspace)读取该目录下的Forc.toml。如果其中没有[workspace]段,会直接抛出WORKSPACE_NOT_DETECTED错误,并提示改用形如contracts的按类型写法;若校验通过,则将members逐个解析,并通过readSwayType(path)识别每个成员的 Sway 类型,把除library之外的合约/谓词/脚本自动归类注入到对应数组中。
这意味着 workspace 模式下你无需维护三份路径列表,Forc workspace 新增一个非 library 成员即可被 CLI 自动感知。
3. 产物与链上配置:output、providerUrl、privateKey
3.1 output:TypeScript 类型定义生成目录
output 是一个字符串(必填项),指向生成 TypeScript 类型定义(含对 Sway ABI 的类型化封装)的相对目录:
// region output —— 摘自 apps/demo-fuels/fuels.config.full.ts
output: './src/sway-programs-api',
该字段是 yup 校验中唯一被强制要求的字段——见 packages/fuels/src/cli/config/validateConfig.ts,若缺失会报 config.output should be a valid string。加载阶段它还会被解析为绝对路径(loadConfig.ts)。类型生成相关的进阶用法可参考 生成类型指南。
3.2 providerUrl:部署合约时使用的节点 URL
providerUrl 是部署合约时 SDK 要连接的 fuel-core GraphQL 端点:
// region providerUrl —— 摘自 apps/demo-fuels/fuels.config.full.ts
// Default: http://127.0.0.1:4000/v1/graphql
providerUrl: 'http://network:port/v1/graphql',
覆盖行为:当
autoStartFuelCore为true时,该 URL 会被fuels dev命令启动的本地临时fuel-core节点地址覆盖,无需你手动改动。
从 loadConfig.ts 可见其默认解析顺序:process.env.FUEL_NETWORK_URL(若设置了该环境变量)优先,其次回退到 http://127.0.0.1:4000/v1/graphql。
3.3 privateKey:部署时使用的钱包私钥
privateKey 是部署合约所使用钱包账户的私钥。强烈建议通过环境变量注入(例如 process.env.MY_PRIVATE_KEY),而非把私钥硬编码进仓库:
// region privateKey —— 摘自 apps/demo-fuels/fuels.config.full.ts
privateKey: '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298',
覆盖行为:与
providerUrl类似,当autoStartFuelCore为true时,privateKey会被本地临时fuel-core节点的consensusKey(共识账户密钥)覆盖,以便部署交易能够立即被打包确认(详见下文的自动启动节点一节)。
如果不提供该字段,源码默认回退到 @fuel-ts/utils 导出的 defaultConsensusKey(见 loadConfig.ts)——这是 Fuel 本地开发环境内置的默认共识私钥,通常只适用于本地 fuel-core。
4. 本地开发节点配置:autoStartFuelCore、fuelCorePort、snapshotDir
以下三个属性仅被
fuels dev使用。
4.1 autoStartFuelCore:自动拉起短生命周期 fuel-core
布尔值。为 true 时,fuels dev 会自动完成两件事(原文档步骤,见 config-file.md):
- 作为
fuels dev命令的一部分,启动一个短生命周期的fuel-core节点; - 把
providerUrl覆盖为刚刚启动的fuel-core节点地址。
// region autoStartFuelCore —— 摘自 apps/demo-fuels/fuels.config.full.ts
autoStartFuelCore: true,
如果设为 false,则需要自行启动一个 fuel-core 节点,并通过 providerUrl 把它的地址告诉 CLI。值得注意的是,源码中该字段的默认值实为 true(loadConfig.ts 与第 L81 行 userConfig.autoStartFuelCore ?? true 双重确认)。
4.2 fuelCorePort:本地 fuel-core 监听端口
当 autoStartFuelCore 为 true 时,用它指定本地节点的端口号;为 false 时该字段被忽略:
// region fuelCorePort —— 摘自 apps/demo-fuels/fuels.config.full.ts
// Default: first free port, starting from 4000
fuelCorePort: 4000,
未配置时的默认行为是“从 4000 开始的第一个空闲端口”:在 autoStartFuelCore.ts 中可以看到 portfinder 的 getPortPromise({ port: 4000 }) 会从 4000 起自动寻找空闲端口。
4.3 snapshotDir:自定义 fuel-core 快照目录
snapshotDir 指向包含 fuel-core 自定义配置的目录,典型的文件包括:
chainConfig.json(链配置,如共识参数、初始区块)metadata.json(数据库元数据)stateConfig.json(初始状态,如预置账户余额)
// region snapshotDir —— 摘自 apps/demo-fuels/fuels.config.full.ts
snapshotDir: './my/snapshot/dir',
该配置只在 autoStartFuelCore 为 true 时生效。真实启动时,CLI 会以 ['--snapshot', config.snapshotDir, '--db-type', 'in-memory'] 的形式把快照目录与内存数据库参数传给 launchNode(见 autoStartFuelCore.ts),从而让本地节点加载你准备好的链上初始状态。
5. 构建与部署参数:forcBuildFlags 与 deployConfig
5.1 forcBuildFlags:定制 forc 构建标志
该属性被 fuels build 与 fuels deploy 使用。Sway 程序默认以 debug 模式编译;如需 release 模式等自定义行为,可通过该数组传入任意 forc build 标志:
// region forcBuildFlags —— 摘自 apps/demo-fuels/fuels.config.full.ts
// Default: []
forcBuildFlags: ['--release'],
构建模式在源码中会被显式建模:见 types.ts 中 FuelsConfig 携带的 buildMode: 'debug' | 'release' 字段,以及 loadConfig.ts 的判断逻辑——forcBuildFlags 中只要包含 '--release',buildMode 即为 release。字段本身默认是空数组 []。
forc 完整命令说明可参阅 Fuel 官方 Forc 文档中的
forc build一节(原文档引用),仓库内可在 Sway 工程各自的Forc.toml(如 apps/demo-typegen/demo-contract/Forc.toml)中查看真实 Sway 工程形态。
5.2 deployConfig:静态对象或动态函数
deployConfig 支持两种形态,用于定制部署参数:
形态一:静态对象。直接提供一个“开箱即用”的部署配置对象:
// region deployConfig-obj —— 摘自 apps/demo-fuels/fuels.config.full.ts
deployConfig: {},
形态二:函数。用于构建动态部署流程,典型场景包括:
- 需要从远程数据源拉取配置或数据(例如先请求链上费率再计算 gas);
- 需要引用已部署合约的 ID——此时可利用回调参数
options.contracts按名称取出对应合约:
// region deployConfig-fn —— 摘自 apps/demo-fuels/fuels.config.full.ts
deployConfig: async (options: ContractDeployOptions) => {
// ability to fetch data remotely
await Promise.resolve(`simulating remote data fetch`);
// get contract by name
const { contracts } = options;
const contract = contracts.find(({ name }) => {
const found = name === MY_FIRST_DEPLOYED_CONTRACT_NAME;
return found;
});
if (!contract) {
throw new Error('Contract not found!');
}
return {
storageSlots: [
{
key: '0x..',
/**
* Here we could initialize a storage slot,
* using the relevant contract ID.
*/
value: contract.contractId,
},
],
};
},
从类型定义看,回调的入参 options 类型为 ContractDeployOptions,携带 contracts(已部署合约数组)、contractName、contractPath 等信息;返回值类型为合约包(@fuel-ts/contract)中的 DeployContractOptions(见 packages/fuels/src/cli/types.ts),支持 storageSlots 等部署级参数。把合约 ID 写入某个 storage slot 是“先部署 A、再按 A 的地址初始化 B”这类链上编排的常见技巧。
6. 生命周期回调:onBuild、onDeploy、onDev、onNode、onFailure
fuels CLI 允许你在关键事件发生后挂接回调,用于日志、通知、缓存、产物后处理等。所有回调都可返回 void 或 Promise<void>(异步回调会在内部被 await)。
onBuild——构建事件成功后被调用。参数:config(加载后的 fuels.config.ts 配置对象)。
// region onBuild —— 摘自 apps/demo-fuels/fuels.config.full.ts
onBuild: (config: FuelsConfig): void | Promise<void> => {
console.log('fuels:onBuild', { config });
},
onDeploy——部署事件成功后被调用。参数:config、data(已部署合约的数组)。data 的具体形态是 DeployedData,可能包含 contracts、scripts、predicates 三类产物,其中合约条目为 { name, contractId } 结构(见 packages/fuels/src/cli/types.ts):
// region onDeploy —— 摘自 apps/demo-fuels/fuels.config.full.ts
onDeploy: (config: FuelsConfig, data: DeployedData): void | Promise<void> => {
console.log('fuels:onDeploy', { config, data });
},
onDev——fuels dev 命令成功重启后被调用。参数:config。
// region onDev —— 摘自 apps/demo-fuels/fuels.config.full.ts
onDev: (config: FuelsConfig): void | Promise<void> => {
console.log('fuels:onDev', { config });
},
onNode——fuels node 命令成功刷新后被调用。参数:config。
// region onNode —— 摘自 apps/demo-fuels/fuels.config.full.ts
onNode: (config: FuelsConfig): void | Promise<void> => {
console.log('fuels:onNode', { config });
},
onFailure——发生错误时调用,可用于统一错误上报或日志清洗。参数:config、error(原始错误对象)。
// region onFailure —— 摘自 apps/demo-fuels/fuels.config.full.ts
onFailure: (config: FuelsConfig, error: Error): void | Promise<void> => {
console.log('fuels:onFailure', { config, error });
},
7. 二进制路径:forcPath 与 fuelCorePath
CLI 在执行编译与启动节点时,需要调用两个原生二进制:Sway 编译器 forc 与链节点 fuel-core。默认情况下二者都取 system 二进制(即直接调用环境变量 PATH 中的 forc / fuel-core);当你希望固定版本、或使用工具链管理器(如 fuelup)安装的特定二进制时,可显式指定路径:
// region forcPath / fuelCorePath —— 摘自 apps/demo-fuels/fuels.config.full.ts
// Default: 'forc',
forcPath: '~/.fuelup/bin/forc',
// Default: 'fuel-core'
fuelCorePath: '~/.fuelup/bin/fuel-core',
从类型注释看,这两个字段“如果设置,将使用到 forc/fuel-core 二进制的绝对路径”(packages/fuels/src/cli/types.ts)。真实加载时会经过 tryFindBinaries 处理(loadConfig.ts),在未提供时回退到系统二进制。使用 fuelup 管理工具链的项目(仓库内如 apps/create-fuels-counter-guide/fuel-toolchain.toml)通常会配出类似上例的 ~/.fuelup/bin/... 路径;而由 fuels 包自行分发二进制的项目则会像下一节展示的那样指向 fuels-forc / fuels-core。
8. 从 .env 加载环境变量
由于 fuels.config.ts 是经过 esbuild 编译执行的真实 TS 文件,你可以在其中自由读取 process.env。原文档推荐的做法是引入 dotenv 包:先安装依赖——
pnpm install dotenv
npm install dotenv
bun install dotenv
然后在 fuels.config.ts 中先加载 .env 再读取变量。仓库中 apps/create-fuels-counter-guide/fuels.config.ts 给出了一个生产可用的完整范式:
// region fuels-config-file-env —— 摘自 apps/create-fuels-counter-guide/fuels.config.ts
import { createConfig } from 'fuels';
import dotenv from 'dotenv';
import { providerUrl } from './src/lib';
dotenv.config({
path: ['.env.local', '.env'],
});
// If your node is running on a port other than 4000, you can set it here
const fuelCorePort = +(process.env.VITE_FUEL_NODE_PORT as string) || 4000;
export default createConfig({
workspace: './sway-programs', // Path to your Sway workspace
output: './src/sway-api', // Where your generated types will be saved
fuelCorePort,
providerUrl,
forcPath: 'fuels-forc',
fuelCorePath: 'fuels-core',
});
几点值得注意的实践:
dotenv.config({ path: ['.env.local', '.env'] })允许按“本地覆盖优先”的顺序加载多份环境文件(先.env.local后.env);fuelCorePort从环境变量读取后转为数字,并用|| 4000提供回退默认值;providerUrl也可以集中定义在应用代码(示例中为./src/lib导出)中,前后端共享同一份节点地址;- 示例中
forcPath/fuelCorePath指向fuels-forc/fuels-core,说明该项目通过依赖包自带二进制的分发方式运行(fuels生态中把原生二进制作为 npm 依赖交付的常用做法)。
配合第 3.3 节提到的 privateKey 同理——你完全可以写成 privateKey: process.env.MY_PRIVATE_KEY,从而把密钥彻底隔离在版本库之外。
9. 一份完整的 fuels.config.ts 参考
把前面所有配置项汇总到同一个文件,即得到官方在 apps/demo-fuels/fuels.config.full.ts 中维护的“全量示例”:
/* eslint-disable no-console */
import { createConfig } from 'fuels';
import type { ContractDeployOptions, DeployedData, FuelsConfig } from 'fuels';
const MY_FIRST_DEPLOYED_CONTRACT_NAME = '';
export default createConfig({
// workspace —— 与下方 contracts/predicates/scripts 二选一
workspace: './sway-programs',
contracts: ['./sway-programs/contracts'],
predicates: ['./sway-programs/predicates'],
scripts: ['./sway-programs/scripts'],
// 类型定义输出目录(必填)
output: './src/sway-programs-api',
// 链上相关
privateKey: '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298',
// Default: http://127.0.0.1:4000/v1/graphql
providerUrl: 'http://network:port/v1/graphql',
// fuels dev 专属
snapshotDir: './my/snapshot/dir',
autoStartFuelCore: true,
// Default: first free port, starting from 4000
fuelCorePort: 4000,
// 构建参数(fuels build / fuels deploy 使用),默认 debug
// Default: []
forcBuildFlags: ['--release'],
// 部署参数:静态对象或异步函数
deployConfig: async (options: ContractDeployOptions) => {
await Promise.resolve(`simulating remote data fetch`);
const { contracts } = options;
const contract = contracts.find(({ name }) => name === MY_FIRST_DEPLOYED_CONTRACT_NAME);
if (!contract) {
throw new Error('Contract not found!');
}
return {
storageSlots: [{ key: '0x..', value: contract.contractId }],
};
},
// 生命周期回调
onBuild: (config: FuelsConfig): void | Promise<void> => {
console.log('fuels:onBuild', { config });
},
onDeploy: (config: FuelsConfig, data: DeployedData): void | Promise<void> => {
console.log('fuels:onDeploy', { config, data });
},
onDev: (config: FuelsConfig): void | Promise<void> => {
console.log('fuels:onDev', { config });
},
onNode: (config: FuelsConfig): void | Promise<void> => {
console.log('fuels:onNode', { config });
},
onFailure: (config: FuelsConfig, error: Error): void | Promise<void> => {
console.log('fuels:onFailure', { config, error });
},
// 二进制路径,缺省走系统 PATH 中的 forc / fuel-core
// Default: 'forc'
forcPath: '~/.fuelup/bin/forc',
// Default: 'fuel-core'
fuelCorePath: '~/.fuelup/bin/fuel-core',
});
提示:上例同时保留了
workspace与contracts/predicates/scripts,仅用于在同一文件里展示两种写法;真实使用必须二选一,否则会触发互斥校验。简化版配置只需workspace+output即可(参考 apps/demo-fuels/fuels.config.ts 与 apps/demo-fuels/fuels.config.minimal.ts)。
10. 默认值速查与加载流程小结
下表汇总各配置项的默认行为(依据 types.ts JSDoc 与 loadConfig.ts 实现):
| 配置项 | 类型 | 默认值 / 默认行为 | 主要生效命令 |
|---|---|---|---|
workspace |
string |
无(与 contracts/predicates/scripts 互斥) | build / deploy / dev |
contracts |
string[] |
[](与 workspace 互斥) |
build / deploy / dev |
predicates |
string[] |
[](与 workspace 互斥) |
build / deploy / dev |
scripts |
string[] |
[](与 workspace 互斥) |
build / deploy / dev |
output |
string |
必填(yup 强校验) | 类型生成 |
providerUrl |
string |
process.env.FUEL_NETWORK_URL,否则 http://127.0.0.1:4000/v1/graphql;autoStartFuelCore 时被覆盖 |
deploy / dev |
privateKey |
string |
defaultConsensusKey;autoStartFuelCore 时被覆盖 |
deploy / dev |
snapshotDir |
string |
无 | 仅 dev |
autoStartFuelCore |
boolean |
true |
仅 dev |
fuelCorePort |
number |
4000 起第一个空闲端口(autoStartFuelCore=false 时忽略) | 仅 dev |
forcBuildFlags |
string[] |
[](含 --release 则 buildMode=release) |
build / deploy |
deployConfig |
对象或函数 | {} |
deploy |
forcPath |
string |
系统二进制 forc |
build / deploy / dev |
fuelCorePath |
string |
系统二进制 fuel-core |
dev / node |
onBuild / onDeploy / onDev / onNode / onFailure |
回调函数 | 无 | 各自对应事件 |
CLI 的完整消费链可概括为:loadUserConfig(查找并 esbuild 编译 fuels.config.*)→ validateConfig(yup 校验必填与类型)→ loadConfig(注入全部默认值、解析 output/程序路径、推导 buildMode)→ 各命令(build/deploy/dev/node)按需读取。当 fuels dev 且 autoStartFuelCore 为真时,autoStartFuelCore.ts 会启动带 --snapshot/--db-type in-memory 的临时节点,并就地改写内存中的 providerUrl 与 privateKey,这正是前文多次提到的“覆盖行为”的源码实现位置。
掌握这些配置项之后,你就能为「本地开发自动起链」「CI 中按 --release 出包」「多合约按依赖顺序部署」等场景编写出精准、可维护的 Fuels 工程配置。关于每个命令的具体用法,可继续阅读 fuels CLI 命令参考。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00