NFT开发核心步骤:本地IPFS节点搭建与元数据上传实战在Web3开发中,“将元数据上传到IPFS”是确保NFT资产去中心化的行业共识。然而,许多教程对此一笔带过,让开发者在面对环境配置、节点操作和脚本自动化时困难重重。从ipfsinit与daemon的区别,到实现图片和
在 Web3 开发中,“将元数据上传到 IPFS”是确保 NFT 资产去中心化的行业共识。然而,许多教程对此一笔带过,让开发者在面对环境配置、节点操作和脚本自动化时困难重重。从 ipfs init
与 daemon
的区别,到实现图片和 JSON 的链式上传,每个环节都可能成为项目的瓶颈。
本文旨在终结这种困惑。我们将以一篇“生产级”的实操指南,手把手带你走完在 macOS 上从零搭建本地 IPFS 节点,并使用 TypeScript 脚本自动化处理 NFT 元数据的完整流程。无论你是初涉此领域的开发者,还是希望规范化开发流程的资深工程师,都能在这里找到清晰、可复现的最佳实践。
告别 NFT 元数据上传的困惑!本篇实战指南将带你从零配置本地 IPFS 节点,到用 TypeScript 脚本实现图片与 JSON 的自动化链式上传,为你的 Web3 项目打下坚实基础。
目标:让您的电脑拥有 ipfs
这个命令行工具,并让终端能找到它。
# 安装
brew install ipfs --cask
brew install --formula ipfs
# 修改 ~/.zshrc (让终端知道路径)
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
brew install ipfs
# brew link ipfs (创建“快捷方式”)
brew link ipfs
目标:在您的电脑上创建一个 IPFS 仓库(.ipfs
文件夹),生成您节点的唯一身份密钥和配置文件。这是一次性的操作。
ipfs init
generating ED25519 keypair...done
peer identity: 12D3KooWPvJRR6eakpAo4Kjb8jdPWJPhNpkV4ujTFfn4uxxPsgF2
initializing IPFS node at /Users/qiaopengjun/.ipfs
ipfs init
和 ipfs daemon
是 IPFS (InterPlanetary File System) 中两个不同的命令,它们的功能和用途有显著区别:
ipfs init
作用:初始化一个新的 IPFS 节点(即本地仓库)。
功能:
~/.ipfs
)创建一个新的 IPFS 配置文件。使用场景:
示例:
ipfs init
ipfs daemon
作用:启动 IPFS 守护进程(后台服务)。
功能:
5001
和 8080
)。Ctrl+C
或关闭终端)。使用场景:
示例:
ipfs daemon
命令 | 目的 | 运行频率 | 结果 |
---|---|---|---|
ipfs init |
初始化本地节点配置 | 仅一次 | 创建 ~/.ipfs 目录和配置文件 |
ipfs daemon |
启动节点并加入 IPFS 网络 | 每次需要使用时 | 激活网络连接和 API 服务 |
ipfs init
才能使用 ipfs daemon
(否则会报错找不到配置)。ipfs daemon
未运行,许多 IPFS 命令(如 ipfs add
或 ipfs cat
)将无法正常工作。ipfs config
命令修改初始化后的配置(如更改存储路径或端口)。
import { create } from "kubo-rpc-client";
import * as fs from "fs";
import { Buffer } from "buffer";
import * as path from "path";
import { fileURLToPath } from "url"; // ✅ 导入 url 模块的辅助函数
// ✅ 定义更详细的元数据接口,以匹配您的示例
interface Attribute {
trait_type: string;
value: string | number;
display_type?: "number";
}
interface NftMetadata {
name: string;
description: string;
image: string; // 将会是 ipfs://<Image_CID>
external_url?: string;
attributes: Attribute[];
}
// --- 配置 ---
const ipfs = create({ url: "http://localhost:5001/api/v0" });
// ✅ 新增:在 ESM 模块中获取当前目录路径的正确方法
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* 上传一个本地文件到 IPFS。
* @param filePath 文件的本地路径
* @returns 上传结果或 undefined
*/
export async function uploadFileToIPFS(filePath: string) {
try {
console.log(`\n--- 正在上传文件: ${filePath} ---`);
const file: Buffer = fs.readFileSync(filePath);
const result = await ipfs.add({
path: path.basename(filePath), // 只使用文件名
content: file,
});
console.log("✅ 文件上传成功!");
console.log(` - 文件名: ${result.path}`);
console.log(` - CID: ${result.cid.toString()}`);
console.log(` - 大小: ${result.size} 字节`);
return result;
} catch (err) {
console.error("❌ 上传文件失败:", err);
}
}
/**
* 将一个 JSON 对象上传到 IPFS。
* @param json 要上传的 JSON 对象
* @returns 上传结果或 undefined
*/
export async function uploadJSONToIPFS(json: NftMetadata) {
try {
console.log("\n--- 正在上传 JSON 对象 ---");
const result = await ipfs.add(JSON.stringify(json));
console.log("✅ JSON 元数据上传成功!");
console.log(` - CID: ${result.cid.toString()}`);
console.log(` - 大小: ${result.size} 字节`);
return result;
} catch (err) {
console.error("❌ 上传 JSON 失败:", err);
}
}
// 主执行函数
async function main() {
try {
// 检查 IPFS 节点连接
const version = await ipfs.version();
console.log(`✅ 成功连接到 IPFS 节点 (版本: ${version.version})`);
// --- 步骤 1: 上传图片文件 ---
// ✅ 修复:使用新的 __dirname 变量来构建正确的路径
const imagePath = path.join(
__dirname,
"..",
"..",
"assets",
"image",
"IMG_20210626_1803...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!