OpenCode 实践课:4 分钟用 Node.js 写出一个命令行 .gitignore 生成器

项目介绍

每次新建项目都要手动创建 .gitignore 文件,不同语言有不同的忽略规则,Google 一下、复制粘贴——流程机械但耗时。今天用 OpenCode + Node.js 写一个命令行工具,输入语言类型自动生成 .gitignore,一招终结这个重复劳动。

技术栈:Node.js(标准库,零依赖),功能:支持 node / python / go / rust / java 五种模板,支持 --list 查看和 --help 帮助。最终代码约 90 行。

准备工作

  • Node.js 18+ 已安装
  • OpenCode 已安装并配置好 API Key(参见 opencode.ai

实践过程

第一步:提出需求

新建空目录后,直接在 OpenCode 中输入需求:

> 我对 OpenCode 说:
> "用 Node.js 写一个 CLI 工具叫 gitignorify,根据参数生成 .gitignore 文件。内置 5 种模板:node、python、go、rust、java。运行方式 node gitignorify.js <type>,支持 --list 列出类型、--help 显示帮助。"

OpenCode 直接生成完整代码,包括模板定义、参数解析、文件写入逻辑,一次性跑通:

#!/usr/bin/env node
const fs = require('fs');
const path = require('path');

const templates = {
  node: `node_modules/\nnpm-debug.log*\n.env\ndist/\nbuild/\ncoverage/\n.vscode/\n.idea/\n`,
  python: `__pycache__/\n*.py[cod]\n*.so\nenv/\nvenv/\n.env\ndist/\nbuild/\n*.egg-info/\n.idea/\n`,
  go: `*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n*.test\n*.out\ngo.work\nvendor/\n.idea/\n`,
  rust: `target/\ndebug/\nCargo.lock\n.vscode/\n.idea/\n*.rs.bk\n`,
  java: `target/\n*.class\n*.jar\n*.war\n*.ear\n*.log\n.idea/\n.vscode/\n*.iml\n`,
};

要点: 一次性把模板数据结构也定义了,不需要来回调整。描述需求时说清楚"内置 5 种模板"就能让 AI 一次性生成全部内容,避免后续追加。

第二步:补全交互逻辑

> 我对 OpenCode 说:
> "补全完整逻辑:解析命令行参数,--list 和 --help 要优先处理。如果没传参数要报错并提示用 --list。如果模板不存在也报错。写入前检查 .gitignore 是否已存在,存在就追加。"

const args = process.argv.slice(2);

if (args.includes('--help') || args.includes('-h')) {
  console.log('Usage: npx gitignorify <type>');
  console.log('       npx gitignorify --list\n');
  console.log('Options:');
  console.log('  --list, -l    List available templates');
  console.log('  --help, -h    Show this help message');
  process.exit(0);
}

if (args.includes('--list') || args.includes('-l')) {
  console.log('Available templates:');
  Object.keys(templates).forEach(t => console.log(`  - ${t}`));
  process.exit(0);
}

const type = args[0];
if (!type) {
  console.error('Error: Please specify a project type.');
  console.error('Use --list to see available types.');
  process.exit(1);
}

if (!templates[type]) {
  console.error(`Error: Unknown type "${type}".`);
  console.error('Use --list to see available types.');
  process.exit(1);
}

要点: "存在就追加"这一句很关键——如果不提,AI 默认行为往往是覆盖。描述边界条件时要精确。

第三步:完成文件写入

> 我对 OpenCode 说:
> "最后加上写入 .gitignore 的逻辑,生成的文件第一行加注释标明来源。"

const content = `# Generated by gitignorify\n${templates[type]}`;
const filePath = path.join(process.cwd(), '.gitignore');

if (fs.existsSync(filePath)) {
  console.log('.gitignore already exists. Appending...');
  fs.appendFileSync(filePath, '\n' + content);
} else {
  fs.writeFileSync(filePath, content);
}

console.log(`.gitignore for ${type} project created!`);

要点: process.cwd() 确保生成在当前目录而非脚本所在目录——这是实际使用中的关键细节。

第四步:测试验证

> 我对 OpenCode 说:
> "在当前目录运行测试:生成 go 类型的 gitignore,再生成 python 类型测试追加逻辑,最后用 --list 列出所有类型。"

$ node gitignorify.js go
.gitignore for go project created!

$ node gitignorify.js python
.gitignore already exists. Appending...

$ node gitignorify.js --list
Available templates:
  - node
  - python
  - go
  - rust
  - java

全程没有报错,三个分支逻辑都正确。

完整代码

#!/usr/bin/env node
const fs = require('fs');
const path = require('path');

const templates = {
  node: `node_modules/\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.env\ndist/\nbuild/\ncoverage/\n.vscode/\n.idea/\n*.tsbuildinfo\n`,
  python: `__pycache__/\n*.py[cod]\n*$py.class\n*.so\n.Python\nenv/\nvenv/\n.env\ndist/\nbuild/\n*.egg-info/\n.idea/\n.vscode/\n`,
  go: `*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n*.test\n*.out\ngo.work\nvendor/\n.idea/\n.vscode/\n`,
  rust: `target/\ndebug/\nCargo.lock\n.vscode/\n.idea/\n*.rs.bk\n`,
  java: `target/\n*.class\n*.jar\n*.war\n*.ear\n*.log\n.idea/\n.vscode/\n*.iml\n`,
};

const args = process.argv.slice(2);

if (args.includes('--help') || args.includes('-h')) {
  console.log('Usage: npx gitignorify <type>');
  console.log('       npx gitignorify --list');
  console.log('');
  console.log('Generate a .gitignore file for your project.');
  console.log('');
  console.log('Options:');
  console.log('  --list, -l    List available templates');
  console.log('  --help, -h    Show this help message');
  process.exit(0);
}

if (args.includes('--list') || args.includes('-l')) {
  console.log('Available templates:');
  Object.keys(templates).forEach(t => console.log(`  - ${t}`));
  process.exit(0);
}

const type = args[0];
if (!type) {
  console.error('Error: Please specify a project type.');
  console.error('Use --list to see available types.');
  process.exit(1);
}

if (!templates[type]) {
  console.error(`Error: Unknown type "${type}".`);
  console.error('Use --list to see available types.');
  process.exit(1);
}

const content = `# Generated by gitignorify\n${templates[type]}`;
const filePath = path.join(process.cwd(), '.gitignore');

if (fs.existsSync(filePath)) {
  console.log('.gitignore already exists. Appending...');
  fs.appendFileSync(filePath, '\n' + content);
} else {
  fs.writeFileSync(filePath, content);
}

console.log(`.gitignore for ${type} project created!`);

小结

从描述需求到可运行工具,全程约 4 分钟。OpenCode 的价值不在于"替你写代码",而在于你把思路用自然语言描述出来,它即时转化成可执行的代码——省去了查文档、手写样板、调试语法的时间。这个小工具 90 行代码,如果纯手写大概要 15 分钟(查 API、确认模板内容、处理边界),用 OpenCode 效率直接翻 3 倍。下次新建项目时,你也可以试试——先不写代码,先告诉 OpenCode 你要什么。