freecodecamp-curriculum by aradotso/trending-skills
npx skills add https://github.com/aradotso/trending-skills --skill freecodecamp-curriculum由 ara.so 提供的技能 — Daily 2026 技能集合。
freeCodeCamp.org 是一个免费、开源的学习平台,拥有数千个交互式编程挑战、认证和全栈课程。其代码库包括一个 React/TypeScript 前端、Node.js/Fastify 后端和一个基于 YAML/Markdown 的课程系统。
freeCodeCamp/
├── api/ # Fastify API 服务器 (TypeScript)
├── client/ # Gatsby/React 前端 (TypeScript)
├── curriculum/ # 所有挑战和认证 (YAML/Markdown)
│ └── challenges/
│ ├── english/
│ │ ├── responsive-web-design/
│ │ ├── javascript-algorithms-and-data-structures/
│ │ └── ...
│ └── ...
├── tools/
│ ├── challenge-helper-scripts/ # 用于课程编写的 CLI 工具
│ └── ui-components/ # 共享的 React 组件
├── config/ # 共享配置
└── e2e/ # Playwright 端到端测试
nvm 或 fnm)广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
git clone https://github.com/<YOUR_USERNAME>/freeCodeCamp.git
cd freeCodeCamp
pnpm install
cp sample.env .env
需要设置的关键 .env 变量:
# MongoDB
MONGOHQ_URL=mongodb://127.0.0.1:27017/freecodecamp
# GitHub OAuth (在 github.com/settings/developers 创建)
GITHUB_ID=$GITHUB_OAUTH_CLIENT_ID
GITHUB_SECRET=$GITHUB_OAUTH_CLIENT_SECRET
# 认证
JWT_SECRET=$YOUR_JWT_SECRET
SESSION_SECRET=$YOUR_SESSION_SECRET
# 电子邮件 (本地开发可选)
SENDGRID_API_KEY=$SENDGRID_API_KEY
pnpm run seed
# 启动所有服务 (API + 客户端)
pnpm run develop
# 或单独启动:
pnpm run develop:api # Fastify API 运行在 :3000 端口
pnpm run develop:client # Gatsby 运行在 :8000 端口
挑战以 YAML/Markdown 文件的形式存储在 curriculum/challenges/ 目录下。
# curriculum/challenges/english/02-javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code.md
---
id: bd7123c8c441eddfaeb5bdef # 唯一的 MongoDB ObjectId 风格字符串
title: Comment Your JavaScript Code
challengeType: 1 # 1=JS, 0=HTML, 2=JSX, 3=Vanilla JS, 5=Project, 7=Video
forumTopicId: 16783
dashedName: comment-your-javascript-code
---
# --description--
Comments are lines of code that JavaScript will intentionally ignore.
```js
// This is an in-line comment.
/* This is a multi-line comment */
尝试创建每种类型的注释。
提示 1
assert.match(code, /(\/\/)/).length > 0);
提示 2
assert.match(code, /(\/\*[\s\S]+?\*\/)/).length > 0);
// Your starting code here
// inline comment
/* multi-line
comment */
### 挑战类型
| 类型 | 值 | 描述 |
|------|-------|-------------|
| HTML | 0 | HTML/CSS 挑战 |
| JavaScript | 1 | JS 算法挑战 |
| JSX | 2 | React 组件挑战 |
| Vanilla JS | 3 | DOM 操作 |
| Python | 7 | Python 挑战 |
| Project | 5 | 认证项目 |
| Video | 11 | 基于视频的课程 |
---
## 创建新挑战
### 使用辅助脚本
```bash
# 交互式创建新挑战
pnpm run create-challenge
# 或直接使用辅助工具
cd tools/challenge-helper-scripts
pnpm run create-challenge --superblock responsive-web-design --block css-flexbox
curriculum/challenges/english/ 下找到正确的目录.md 文件# 生成唯一的挑战 ID
node -e "const {ObjectID} = require('mongodb'); console.log(new ObjectID().toString())"
3. 遵循上述挑战文件格式
# 检查并验证所有课程文件
pnpm run test:curriculum
# 测试特定挑战
pnpm run test:curriculum -- --challenge <challenge-id>
# 测试特定模块
pnpm run test:curriculum -- --block basic-javascript
测试使用自定义断言库。在 # --hints-- 块内:
# --hints--
`myVariable` 应使用 `let` 声明。
```js
assert.match(code, /let\s+myVariable/);
当传入 42 时,函数应返回 true。
assert.strictEqual(myFunction(42), true);
DOM 应包含一个 id 为 main 的元素。
const el = document.getElementById('main');
assert.exists(el);
### 可用的测试工具
```js
// DOM 访问 (用于 HTML 挑战)
document.querySelector('#my-id')
document.getElementById('test')
// 代码检查
assert.match(code, /regex/); // 原始源代码字符串
assert.include(code, 'someString');
// 值断言 (Chai 风格)
assert.strictEqual(actual, expected);
assert.isTrue(value);
assert.exists(value);
assert.approximately(actual, expected, delta);
// 对于异步挑战
// 使用 __helpers 对象
const result = await fetch('/api/test');
assert.strictEqual(result.status, 200);
// api/src/routes/example.ts
import { type FastifyPluginCallbackTypebox } from '../helpers/plugin-callback-typebox';
import { Type } from '@fastify/type-provider-typebox';
export const exampleRoutes: FastifyPluginCallbackTypebox = (
fastify,
_options,
done
) => {
fastify.get(
'/example/:id',
{
schema: {
params: Type.Object({
id: Type.String()
}),
response: {
200: Type.Object({
data: Type.String()
})
}
}
},
async (req, reply) => {
const { id } = req.params;
return reply.send({ data: `Result for ${id}` });
}
);
done();
};
// api/src/app.ts - 注册插件
import { exampleRoutes } from './routes/example';
await fastify.register(exampleRoutes, { prefix: '/api' });
// api/src/schemas/user.ts
import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
completedChallenges: [
{
id: String,
completedDate: Number,
solution: String
}
]
});
export const User = mongoose.model('User', userSchema);
// client/src/pages/my-new-page.tsx
import React from 'react';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
const MyNewPage = (): JSX.Element => {
const { t } = useTranslation();
return (
<>
<Helmet>
<title>{t('page-title.my-new-page')} | freeCodeCamp.org</title>
</Helmet>
<main>
<h1>{t('headings.my-new-page')}</h1>
</main>
</>
);
};
export default MyNewPage;
// client/src/redux/selectors.ts 模式
import { createSelector } from 'reselect';
import { RootState } from './types';
export const userSelector = (state: RootState) => state.app.user;
export const completedChallengesSelector = createSelector(
userSelector,
user => user?.completedChallenges ?? []
);
// 在组件中
import { useAppSelector } from '../redux/hooks';
import { completedChallengesSelector } from '../redux/selectors';
const MyComponent = () => {
const completedChallenges = useAppSelector(completedChallengesSelector);
return <div>{completedChallenges.length} challenges completed</div>;
};
// 将键添加到 client/i18n/locales/english/translations.json
{
"my-component": {
"title": "My Title",
"description": "My description with {{variable}}"
}
}
// 在组件中使用
const { t } = useTranslation();
t('my-component.title');
t('my-component.description', { variable: 'value' });
# 运行所有单元测试
pnpm test
# 运行特定包的测试
pnpm --filter api test
pnpm --filter client test
# 监视模式
pnpm --filter client test -- --watch
# 验证所有挑战
pnpm run test:curriculum
# 验证特定超级模块
pnpm run test:curriculum -- --superblock javascript-algorithms-and-data-structures
# 检查挑战 Markdown 格式
pnpm run lint:curriculum
# 运行所有端到端测试
pnpm run test:e2e
# 运行特定测试文件
pnpm run test:e2e -- e2e/learn.spec.ts
# 使用 UI 运行
pnpm run test:e2e -- --ui
// e2e/my-feature.spec.ts
import { test, expect } from '@playwright/test';
test('user can complete a challenge', async ({ page }) => {
await page.goto('/learn/javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code');
// 在代码编辑器中填写
await page.locator('.monaco-editor').click();
await page.keyboard.type('// inline comment\n/* block comment */');
// 运行测试
await page.getByRole('button', { name: /run the tests/i }).click();
// 检查结果
await expect(page.getByText('Tests Passed')).toBeVisible();
});
# 开发
pnpm run develop # 启动所有服务
pnpm run develop:api # 仅启动 API
pnpm run develop:client # 仅启动客户端
# 构建
pnpm run build # 构建所有内容
pnpm run build:api # 构建 API
pnpm run build:client # 构建客户端 (Gatsby)
# 测试
pnpm test # 单元测试
pnpm run test:curriculum # 验证课程
pnpm run test:e2e # Playwright 端到端测试
# 代码检查
pnpm run lint # 对所有包进行 ESLint 检查
pnpm run lint:curriculum # 课程 Markdown 格式检查
# 数据库
pnpm run seed # 用课程数据初始化数据库
pnpm run seed:certified-user # 初始化一个测试认证用户
# 实用工具
pnpm run create-challenge # 交互式挑战创建器
pnpm run clean # 清理构建产物
超级模块映射到认证。目录名称使用 kebab-case:
responsive-web-design/
javascript-algorithms-and-data-structures/
front-end-development-libraries/
data-visualization/
relational-database/
back-end-development-and-apis/
quality-assurance/
scientific-computing-with-python/
data-analysis-with-python/
machine-learning-with-python/
coding-interview-prep/
the-odin-project/
project-euler/
超级模块内的模块目录:
responsive-web-design/
├── basic-html-and-html5/
├── basic-css/
├── applied-visual-design/
├── css-flexbox/
└── css-grid/
每个挑战都需要一个唯一的 24 字符十六进制 ID:
// tools/challenge-helper-scripts/helpers/id-gen.ts
import { ObjectId } from 'bson';
export const generateId = (): string => new ObjectId().toHexString();
每个挑战都需要一个 forumTopicId 链接到 forum.freecodecamp.org:
forumTopicId: 301090 # 必须是真实的论坛帖子 ID
每个模块都需要一个 _meta.json:
{
"name": "Basic JavaScript",
"dashedName": "basic-javascript",
"order": 0,
"time": "5 hours",
"template": "",
"required": [],
"isUpcomingChange": false,
"isBeta": false,
"isLocked": false,
"isPrivate": false
}
// 在端到端测试中,使用测试用户夹具
import { authedUser } from './fixtures/authed-user';
test.use({ storageState: 'playwright/.auth/user.json' });
test('authenticated action', async ({ page }) => {
// 页面已登录
await page.goto('/settings');
await expect(page.getByText('Account Settings')).toBeVisible();
});
# 检查 MongoDB 是否正在运行
mongosh --eval "db.adminCommand('ping')"
# 启动 MongoDB (macOS 使用 Homebrew)
brew services start mongodb-community
# 在测试中使用内存中的 MongoDB
MONGOHQ_URL=mongodb://127.0.0.1:27017/freecodecamp-test pnpm test
# API 运行在 3000 端口,客户端运行在 8000 端口
lsof -i :3000
kill -9 <PID>
# 查看详细的错误输出
pnpm run test:curriculum -- --verbose
# 常见问题:
# - 缺少 forumTopicId
# - 重复的挑战 ID
# - 无效的 challengeType
# - 格式错误的 YAML 前置元数据
# 使用项目要求的版本
node --version # 应匹配 .nvmrc
pnpm --version # 应匹配 package.json 中的 packageManager
nvm use # 切换到正确的 Node 版本
# 清除 Gatsby 缓存
pnpm --filter client run clean
pnpm run develop:client
# 1. 创建功能分支
git checkout -b fix/challenge-typo-in-basic-js
# 2. 进行更改并测试
pnpm run test:curriculum
pnpm test
# 3. 代码检查
pnpm run lint
# 4. 使用约定式提交进行提交
git commit -m "fix(curriculum): correct typo in basic-javascript challenge"
# 5. 推送并针对主分支打开 PR
git push origin fix/challenge-typo-in-basic-js
提交消息前缀:fix:、feat:、chore:、docs:、refactor:、test:
每周安装量
345
仓库
GitHub 星标数
10
首次出现
8 天前
安全审计
安装于
gemini-cli341
github-copilot341
codex341
amp341
cline341
kimi-cli341
Skill by ara.so — Daily 2026 Skills collection.
freeCodeCamp.org is a free, open-source learning platform with thousands of interactive coding challenges, certifications, and a full-stack curriculum. The codebase includes a React/TypeScript frontend, Node.js/Fastify backend, and a YAML/Markdown-based curriculum system.
freeCodeCamp/
├── api/ # Fastify API server (TypeScript)
├── client/ # Gatsby/React frontend (TypeScript)
├── curriculum/ # All challenges and certifications (YAML/Markdown)
│ └── challenges/
│ ├── english/
│ │ ├── responsive-web-design/
│ │ ├── javascript-algorithms-and-data-structures/
│ │ └── ...
│ └── ...
├── tools/
│ ├── challenge-helper-scripts/ # CLI tools for curriculum authoring
│ └── ui-components/ # Shared React components
├── config/ # Shared configuration
└── e2e/ # Playwright end-to-end tests
nvm or fnm)git clone https://github.com/<YOUR_USERNAME>/freeCodeCamp.git
cd freeCodeCamp
pnpm install
cp sample.env .env
Key .env variables to set:
# MongoDB
MONGOHQ_URL=mongodb://127.0.0.1:27017/freecodecamp
# GitHub OAuth (create at github.com/settings/developers)
GITHUB_ID=$GITHUB_OAUTH_CLIENT_ID
GITHUB_SECRET=$GITHUB_OAUTH_CLIENT_SECRET
# Auth
JWT_SECRET=$YOUR_JWT_SECRET
SESSION_SECRET=$YOUR_SESSION_SECRET
# Email (optional for local dev)
SENDGRID_API_KEY=$SENDGRID_API_KEY
pnpm run seed
# Start everything (API + Client)
pnpm run develop
# Or start individually:
pnpm run develop:api # Fastify API on :3000
pnpm run develop:client # Gatsby on :8000
Challenges are stored as YAML/Markdown files under curriculum/challenges/.
# curriculum/challenges/english/02-javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code.md
---
id: bd7123c8c441eddfaeb5bdef # unique MongoDB ObjectId-style string
title: Comment Your JavaScript Code
challengeType: 1 # 1=JS, 0=HTML, 2=JSX, 3=Vanilla JS, 5=Project, 7=Video
forumTopicId: 16783
dashedName: comment-your-javascript-code
---
# --description--
Comments are lines of code that JavaScript will intentionally ignore.
```js
// This is an in-line comment.
/* This is a multi-line comment */
Try creating one of each type of comment.
hint 1
assert(code.match(/(\/\/)/).length > 0);
hint 2
assert(code.match(/(\/\*[\s\S]+?\*\/)/).length > 0);
// Your starting code here
// inline comment
/* multi-line
comment */
### Challenge Types
| Type | Value | Description |
|------|-------|-------------|
| HTML | 0 | HTML/CSS challenges |
| JavaScript | 1 | JS algorithm challenges |
| JSX | 2 | React component challenges |
| Vanilla JS | 3 | DOM manipulation |
| Python | 7 | Python challenges |
| Project | 5 | Certification projects |
| Video | 11 | Video-based lessons |
---
## Creating a New Challenge
### Using the Helper Script
```bash
# Create a new challenge interactively
pnpm run create-challenge
# Or use the helper directly
cd tools/challenge-helper-scripts
pnpm run create-challenge --superblock responsive-web-design --block css-flexbox
curriculum/challenges/english/.md file with a unique ID# Generate a unique challenge ID
node -e "const {ObjectID} = require('mongodb'); console.log(new ObjectID().toString())"
3. Follow the challenge file format above
# Lint and validate all curriculum files
pnpm run test:curriculum
# Test a specific challenge
pnpm run test:curriculum -- --challenge <challenge-id>
# Test a specific block
pnpm run test:curriculum -- --block basic-javascript
Tests use a custom assertion library. Inside # --hints-- blocks:
# --hints--
`myVariable` should be declared with `let`.
```js
assert.match(code, /let\s+myVariable/);
The function should return true when passed 42.
assert.strictEqual(myFunction(42), true);
The DOM should contain an element with id main.
const el = document.getElementById('main');
assert.exists(el);
### Available Test Utilities
```js
// DOM access (for HTML challenges)
document.querySelector('#my-id')
document.getElementById('test')
// Code inspection
assert.match(code, /regex/); // raw source code string
assert.include(code, 'someString');
// Value assertions (Chai-style)
assert.strictEqual(actual, expected);
assert.isTrue(value);
assert.exists(value);
assert.approximately(actual, expected, delta);
// For async challenges
// Use __helpers object
const result = await fetch('/api/test');
assert.strictEqual(result.status, 200);
// api/src/routes/example.ts
import { type FastifyPluginCallbackTypebox } from '../helpers/plugin-callback-typebox';
import { Type } from '@fastify/type-provider-typebox';
export const exampleRoutes: FastifyPluginCallbackTypebox = (
fastify,
_options,
done
) => {
fastify.get(
'/example/:id',
{
schema: {
params: Type.Object({
id: Type.String()
}),
response: {
200: Type.Object({
data: Type.String()
})
}
}
},
async (req, reply) => {
const { id } = req.params;
return reply.send({ data: `Result for ${id}` });
}
);
done();
};
// api/src/app.ts - register the plugin
import { exampleRoutes } from './routes/example';
await fastify.register(exampleRoutes, { prefix: '/api' });
// api/src/schemas/user.ts
import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
completedChallenges: [
{
id: String,
completedDate: Number,
solution: String
}
]
});
export const User = mongoose.model('User', userSchema);
// client/src/pages/my-new-page.tsx
import React from 'react';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
const MyNewPage = (): JSX.Element => {
const { t } = useTranslation();
return (
<>
<Helmet>
<title>{t('page-title.my-new-page')} | freeCodeCamp.org</title>
</Helmet>
<main>
<h1>{t('headings.my-new-page')}</h1>
</main>
</>
);
};
export default MyNewPage;
// client/src/redux/selectors.ts pattern
import { createSelector } from 'reselect';
import { RootState } from './types';
export const userSelector = (state: RootState) => state.app.user;
export const completedChallengesSelector = createSelector(
userSelector,
user => user?.completedChallenges ?? []
);
// In a component
import { useAppSelector } from '../redux/hooks';
import { completedChallengesSelector } from '../redux/selectors';
const MyComponent = () => {
const completedChallenges = useAppSelector(completedChallengesSelector);
return <div>{completedChallenges.length} challenges completed</div>;
};
// Add keys to client/i18n/locales/english/translations.json
{
"my-component": {
"title": "My Title",
"description": "My description with {{variable}}"
}
}
// Use in component
const { t } = useTranslation();
t('my-component.title');
t('my-component.description', { variable: 'value' });
# Run all unit tests
pnpm test
# Run tests for a specific package
pnpm --filter api test
pnpm --filter client test
# Watch mode
pnpm --filter client test -- --watch
# Validate all challenges
pnpm run test:curriculum
# Validate specific superblock
pnpm run test:curriculum -- --superblock javascript-algorithms-and-data-structures
# Lint challenge markdown
pnpm run lint:curriculum
# Run all e2e tests
pnpm run test:e2e
# Run specific test file
pnpm run test:e2e -- e2e/learn.spec.ts
# Run with UI
pnpm run test:e2e -- --ui
// e2e/my-feature.spec.ts
import { test, expect } from '@playwright/test';
test('user can complete a challenge', async ({ page }) => {
await page.goto('/learn/javascript-algorithms-and-data-structures/basic-javascript/comment-your-javascript-code');
// Fill in the code editor
await page.locator('.monaco-editor').click();
await page.keyboard.type('// inline comment\n/* block comment */');
// Run tests
await page.getByRole('button', { name: /run the tests/i }).click();
// Check results
await expect(page.getByText('Tests Passed')).toBeVisible();
});
# Development
pnpm run develop # Start all services
pnpm run develop:api # API only
pnpm run develop:client # Client only
# Building
pnpm run build # Build everything
pnpm run build:api # Build API
pnpm run build:client # Build client (Gatsby)
# Testing
pnpm test # Unit tests
pnpm run test:curriculum # Validate curriculum
pnpm run test:e2e # Playwright e2e
# Linting
pnpm run lint # ESLint all packages
pnpm run lint:curriculum # Curriculum markdown lint
# Database
pnpm run seed # Seed DB with curriculum data
pnpm run seed:certified-user # Seed a test certified user
# Utilities
pnpm run create-challenge # Interactive challenge creator
pnpm run clean # Clean build artifacts
Superblocks map to certifications. Directory names use kebab-case:
responsive-web-design/
javascript-algorithms-and-data-structures/
front-end-development-libraries/
data-visualization/
relational-database/
back-end-development-and-apis/
quality-assurance/
scientific-computing-with-python/
data-analysis-with-python/
machine-learning-with-python/
coding-interview-prep/
the-odin-project/
project-euler/
Block directories within a superblock:
responsive-web-design/
├── basic-html-and-html5/
├── basic-css/
├── applied-visual-design/
├── css-flexbox/
└── css-grid/
Every challenge needs a unique 24-character hex ID:
// tools/challenge-helper-scripts/helpers/id-gen.ts
import { ObjectId } from 'bson';
export const generateId = (): string => new ObjectId().toHexString();
Every challenge needs a forumTopicId linking to forum.freecodecamp.org:
forumTopicId: 301090 # Must be a real forum post ID
Each block needs a _meta.json:
{
"name": "Basic JavaScript",
"dashedName": "basic-javascript",
"order": 0,
"time": "5 hours",
"template": "",
"required": [],
"isUpcomingChange": false,
"isBeta": false,
"isLocked": false,
"isPrivate": false
}
// In e2e tests, use the test user fixture
import { authedUser } from './fixtures/authed-user';
test.use({ storageState: 'playwright/.auth/user.json' });
test('authenticated action', async ({ page }) => {
// page is already logged in
await page.goto('/settings');
await expect(page.getByText('Account Settings')).toBeVisible();
});
# Check if MongoDB is running
mongosh --eval "db.adminCommand('ping')"
# Start MongoDB (macOS with Homebrew)
brew services start mongodb-community
# Use in-memory MongoDB for tests
MONGOHQ_URL=mongodb://127.0.0.1:27017/freecodecamp-test pnpm test
# API runs on 3000, Client on 8000
lsof -i :3000
kill -9 <PID>
# See detailed error output
pnpm run test:curriculum -- --verbose
# Common issues:
# - Missing forumTopicId
# - Duplicate challenge IDs
# - Invalid challengeType
# - Malformed YAML frontmatter
# Use the project's required versions
node --version # Should match .nvmrc
pnpm --version # Should match packageManager in package.json
nvm use # Switches to correct Node version
# Clear Gatsby cache
pnpm --filter client run clean
pnpm run develop:client
# 1. Create a feature branch
git checkout -b fix/challenge-typo-in-basic-js
# 2. Make changes and test
pnpm run test:curriculum
pnpm test
# 3. Lint
pnpm run lint
# 4. Commit using conventional commits
git commit -m "fix(curriculum): correct typo in basic-javascript challenge"
# 5. Push and open PR against main
git push origin fix/challenge-typo-in-basic-js
Commit message prefixes: fix:, feat:, chore:, docs:, refactor:, test:
Weekly Installs
345
Repository
GitHub Stars
10
First Seen
8 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli341
github-copilot341
codex341
amp341
cline341
kimi-cli341
OWASP 十大安全风险防范指南:Web应用安全漏洞与代码示例
824 周安装
阿里云AnalyticDB MySQL管理指南:使用OpenAPI与SDK进行云数据库操作
249 周安装
Google App Engine 部署指南:标准与灵活环境配置、Cloud SQL 连接教程
249 周安装
HTMX 开发指南:无需复杂 JavaScript 构建动态 Web 应用 | 现代前端技术
249 周安装
Hugging Face CLI 命令大全:hf 终端工具下载、上传、管理模型与数据集
249 周安装
e-Tax 电子申报自动化技能:通过浏览器自动填写日本国税厅申报书创建专区
249 周安装
数据库架构师技能:设计可扩展高性能数据层,精通技术选型与数据建模
249 周安装