freecodecamp-curriculum

安装量: 86
排名: #9276

安装

npx skills add https://github.com/aradotso/trending-skills --skill freecodecamp-curriculum

freeCodeCamp Curriculum & Platform Development 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. Architecture Overview 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 Local Development Setup Prerequisites Node.js 20+ (use nvm or fnm ) pnpm 9+ MongoDB (local or Atlas) A GitHub account (for OAuth) 1. Fork & Clone git clone https://github.com/ < YOUR_USERNAME

/freeCodeCamp.git cd freeCodeCamp 2. Install Dependencies pnpm install 3. Configure Environment 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 4. Seed the Database pnpm run seed 5. Start Development Servers

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

Curriculum Challenge Structure Challenges are stored as YAML/Markdown files under curriculum/challenges/ . Challenge File Format

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 / --instructions-- Try creating one of each type of comment. --hints-- hint 1 assert ( code . match ( / ( \/ \/ ) / ) . length

0 ) ; hint 2 assert ( code . match ( / ( \/ * [ \s \S ] +? * \/ ) / ) . length

0 ) ; --seed-- --seed-contents-- // Your starting code here --solutions-- // 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
Manual Creation
Find the correct directory under
curriculum/challenges/english/
Create a new
.md
file with a unique ID
# Generate a unique challenge ID
node
-e
"const {ObjectID} = require('mongodb'); console.log(new ObjectID().toString())"
Follow the challenge file format above
Validate Your Challenge
# 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
Writing Challenge Tests
Tests use a custom assertion library. Inside
# --hints--
blocks:
JavaScript Challenges
#
--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 Development (Fastify)
Route Structure
// 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
(
)
;
}
;
Adding a New API Route
// api/src/app.ts - register the plugin
import
{
exampleRoutes
}
from
'./routes/example'
;
await
fastify
.
register
(
exampleRoutes
,
{
prefix
:
'/api'
}
)
;
Database Access (Mongoose)
// 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 (Gatsby/React) Development
Adding a New Page
// 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
;
Using the Redux Store
// 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
>
;
}
;
i18n Translations
// 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'
}
)
;
Testing
Unit Tests (Jest)
# 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
Curriculum Tests
# 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
E2E Tests (Playwright)
# 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
Writing E2E Tests
// 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
(
)
;
}
)
;
Key pnpm Scripts Reference
# 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
Superblock & Block Naming Conventions
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/
Common Patterns & Gotchas
Challenge ID Generation
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
(
)
;
Adding Forum Links
Every challenge needs a
forumTopicId
linking to forum.freecodecamp.org:
forumTopicId
:
301090
# Must be a real forum post ID
Curriculum Meta Files
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
}
Testing with Authentication
// 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
(
)
;
}
)
;
Troubleshooting
MongoDB Connection Issues
# 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
Port Conflicts
# API runs on 3000, Client on 8000
lsof
-i
:3000
kill
-9
<
PID
>
Curriculum Validation Failures
# See detailed error output
pnpm
run test:curriculum --
--verbose
# Common issues:
# - Missing forumTopicId
# - Duplicate challenge IDs
# - Invalid challengeType
# - Malformed YAML frontmatter
Node/pnpm Version Mismatch
# 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
Client Build Errors
# Clear Gatsby cache
pnpm
--filter
client run clean
pnpm
run develop:client
Contributing Workflow
# 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:
Resources
Contribution guide:
https://contribute.freecodecamp.org
Forum:
https://forum.freecodecamp.org
Discord:
https://discord.gg/PRyKn3Vbay
How to report bugs:
https://forum.freecodecamp.org/t/how-to-report-a-bug/19543
返回排行榜