feat: migrate to pnpm for better workspace DX (#49293)

* feat: npm -> pnpm 

This resolves the issues with the gatsby client (gatsby-plugin-pnpm
deals with the fact that gatsby is relying on its own dependencies
being de-duped)
and challenge-editor (which doesn't seem to want to automatically install
codemirror and needed its own eslint config)

* fix: correct mocha path for curriculum tests

* fix: use select workspace with -F not -w

* fix: reorganise packages and restrict hoisting

pnpm works best if the workspaces keep their own dependencies, since
dependencies are not flattened and then what node resolves from a
require is predictable.

@types seem to be a special case and more care is required to prevent
them getting smushed together in the root (hence the .npmrc)

* fix: add types for tools + root

* fix: decouple challenge-auditor from client

* fix: add ui-components types

* fix(client): use the latest types for react 16

* fix: prettify

* fix: prettierignore pnpm-lock

* fix: relax hoisting

Turns out pnpm works just fine with types. I don't know what was going
wrong before, but there are no-longer any type conflicts.

* fix: add @redux-saga/core to fix eslint issue

It seems to only be redux-saga that import/named can't cope with, so it
is probably okay to work around this one.

* chore: add chai to tools/scripts/build

* fix: add store to root for cypress

* fix: allow cypress to download binaries

If we want to keep preventing cypress from downloading binaries, we can
figure out a workaround, but I'm allowing it to ease the transition to
pnpm.

My guess about why this is happening is that npm triggers Cypress's
postinstall script, but pnpm does not (because pnpm install only
installs if necessary, perferring to link)

* chore: re-enable pre/post scripts

* fix: update build scripts for client

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* chore: update engines to use pnpm


* fix: enable choice of (super)block for tests

Only 'nix machines for now.

* chore: pin pnpm to version 7

* chore: remove last npms

Except web + curriculum-server. I'll update them when I start work on
them again.

* fix: lockfile check to catch any package-locks

* fix(action): install pnpm for upcoming tests

* chore: add nodemon to new api

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
This commit is contained in:
Oliver Eyton-Williams
2023-03-02 19:17:44 +01:00
committed by GitHub
parent 66438c271f
commit d7848ae01a
81 changed files with 30413 additions and 55330 deletions

View File

@@ -55,6 +55,7 @@
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": [ "project": [
"./client/tsconfig.json",
"./tsconfig.json", "./tsconfig.json",
"./api/tsconfig.json", "./api/tsconfig.json",
"./config/tsconfig.json", "./config/tsconfig.json",

View File

@@ -276,6 +276,10 @@ jobs:
# Validate the Download # # Validate the Download #
# All languages should go ABOVE this. # # All languages should go ABOVE this. #
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
@@ -290,15 +294,15 @@ jobs:
- name: Build Source Files - name: Build Source Files
run: | run: |
echo npm version $(npm -v) echo pnpm version $(pnpm -v)
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
npm run build:server pnpm run build:server
- name: Lint and Format Files - name: Lint and Format Files
run: | run: |
npm run format:curriculum pnpm run format:curriculum
# We do not need to run tests because they are run after the PR is created. # We do not need to run tests because they are run after the PR is created.

View File

@@ -31,6 +31,11 @@ jobs:
repository: freeCodeCamp/mobile repository: freeCodeCamp/mobile
path: mobile path: mobile
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -50,9 +55,9 @@ jobs:
- name: Install and Build - name: Install and Build
run: | run: |
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
- name: Generate mobile test files - name: Generate mobile test files
run: | run: |

View File

@@ -37,6 +37,11 @@ jobs:
repository: freeCodeCamp/client-config repository: freeCodeCamp/client-config
path: client-config path: client-config
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -52,10 +57,10 @@ jobs:
- name: Install and Build - name: Install and Build
run: | run: |
npm ci pnpm install
npm run build pnpm run build
- name: Seed Database - name: Seed Database
run: npm run seed run: pnpm run seed
- name: Move serve.json to Public Folder - name: Move serve.json to Public Folder
run: cp client-config/serve.json client/public/serve.json run: cp client-config/serve.json client/public/serve.json
@@ -63,7 +68,7 @@ jobs:
uses: cypress-io/github-action@v4 uses: cypress-io/github-action@v4
with: with:
record: ${{ env.CYPRESS_RECORD_KEY != 0 }} record: ${{ env.CYPRESS_RECORD_KEY != 0 }}
start: npm run start-ci start: pnpm run start-ci
wait-on: http://localhost:8000 wait-on: http://localhost:8000
wait-on-timeout: 1200 wait-on-timeout: 1200
config: baseUrl=http://localhost:8000 config: baseUrl=http://localhost:8000

View File

@@ -30,6 +30,11 @@ jobs:
repository: freeCodeCamp/client-config repository: freeCodeCamp/client-config
path: client-config path: client-config
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -40,8 +45,8 @@ jobs:
- name: Install and Build - name: Install and Build
run: | run: |
npm ci pnpm install
npm run build pnpm run build
- name: Move serve.json to Public Folder - name: Move serve.json to Public Folder
run: cp client-config/serve.json client/public/serve.json run: cp client-config/serve.json client/public/serve.json
@@ -115,6 +120,11 @@ jobs:
sudo mv /usr/bin/firefox /usr/bin/firefox_old sudo mv /usr/bin/firefox /usr/bin/firefox_old
sudo ln -s /opt/firefox/firefox /usr/bin/firefox sudo ln -s /opt/firefox/firefox /usr/bin/firefox
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -125,19 +135,19 @@ jobs:
- name: Install and Build - name: Install and Build
run: | run: |
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
npm run build:server pnpm run build:server
- name: Seed Database - name: Seed Database
run: npm run seed run: pnpm run seed
- name: Cypress run - name: Cypress run
uses: cypress-io/github-action@v4 uses: cypress-io/github-action@v4
with: with:
record: ${{ env.CYPRESS_RECORD_KEY != 0 }} record: ${{ env.CYPRESS_RECORD_KEY != 0 }}
start: npm run start-ci start: pnpm run start-ci
wait-on: http://localhost:8000 wait-on: http://localhost:8000
wait-on-timeout: 1200 wait-on-timeout: 1200
config: baseUrl=http://localhost:8000 config: baseUrl=http://localhost:8000

View File

@@ -15,18 +15,20 @@ jobs:
steps: steps:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Set freeCodeCamp Environment Variables - name: Set freeCodeCamp Environment Variables
run: cp sample.env .env run: cp sample.env .env
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: pnpm install
- name: Validate Challenge Files - name: Validate Challenge Files
run: npm run audit-challenges run: pnpm run audit-challenges

View File

@@ -17,22 +17,24 @@ jobs:
steps: steps:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Set freeCodeCamp Environment Variables - name: Set freeCodeCamp Environment Variables
run: cp sample.env .env run: cp sample.env .env
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: pnpm install
- name: Validate Challenge Files - name: Validate Challenge Files
id: validate id: validate
run: npm run audit-challenges run: pnpm run audit-challenges
- name: Create Comment - name: Create Comment
# Run if the validate challenge files step fails, specifically. Note that we need the failure() call for this step to trigger if the action fails. # Run if the validate challenge files step fails, specifically. Note that we need the failure() call for this step to trigger if the action fails.

View File

@@ -22,7 +22,10 @@ jobs:
steps: steps:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -35,6 +38,6 @@ jobs:
- name: Run Checks - name: Run Checks
run: | run: |
echo npm version $(npm -v) echo pnpm version $(pnpm -v)
npm ci pnpm install
npm run knip pnpm run knip

View File

@@ -33,7 +33,10 @@ jobs:
steps: steps:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -48,12 +51,12 @@ jobs:
- name: Lint Source Files - name: Lint Source Files
run: | run: |
npm ci pnpm install
npm run create:config pnpm run create:config
npm i --prefix=curriculum-server npm i --prefix=curriculum-server
npm i --prefix=web npm i --prefix=web
npm run build:curriculum pnpm run build:curriculum
npm run lint pnpm run lint
test: test:
name: Test name: Test
@@ -68,7 +71,10 @@ jobs:
steps: steps:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -83,9 +89,9 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
- name: Run Tests - name: Run Tests
run: npm test run: pnpm test

View File

@@ -35,12 +35,17 @@ jobs:
- name: Check number of lockfiles - name: Check number of lockfiles
run: | run: |
if [ $(find . -name 'package-lock.json' | grep -vc -e 'node_modules') -gt 1 ] if [ $(find . -name 'package-lock.json' | grep -vc -e 'node_modules') -gt 0 ]
then then
echo -e 'Error: found too many lockfiles in the repository.\nWe use npm workspaces to manage packages so all dependencies should be added to the root package-lock.json' echo -e 'Error: found package-lock files in the repository.\nWe use pnpm workspaces to manage packages so all dependencies should be added via pnpm add'
exit 1 exit 1
fi fi
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -56,13 +61,13 @@ jobs:
# currently, built as workspaces. # currently, built as workspaces.
- name: Lint Source Files - name: Lint Source Files
run: | run: |
echo npm version $(npm -v) echo pnpm version $(pnpm -v)
npm ci pnpm install
npm run create:config pnpm run create:config
npm i --prefix=curriculum-server npm i --prefix=curriculum-server
npm i --prefix=web npm i --prefix=web
npm run build:curriculum pnpm run build:curriculum
npm run lint pnpm run lint
test: test:
name: Test name: Test
@@ -78,6 +83,11 @@ jobs:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -90,13 +100,13 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
echo npm version $(npm -v) echo pnpm version $(pnpm -v)
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
- name: Run Tests - name: Run Tests
run: npm test run: pnpm test
test-upcoming: test-upcoming:
name: Test Upcoming Changes name: Test Upcoming Changes
@@ -112,6 +122,11 @@ jobs:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -125,13 +140,13 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
echo npm version $(npm -v) echo pnpm version $(pnpm -v)
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
- name: Run Tests - name: Run Tests
run: npm test run: pnpm test
test-localization: test-localization:
name: Localize name: Localize
@@ -148,6 +163,11 @@ jobs:
- name: Checkout Source Files - name: Checkout Source Files
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with: with:
@@ -163,13 +183,13 @@ jobs:
CURRICULUM_LOCALE: ${{ matrix.locale }} CURRICULUM_LOCALE: ${{ matrix.locale }}
CLIENT_LOCALE: ${{ matrix.locale }} CLIENT_LOCALE: ${{ matrix.locale }}
run: | run: |
echo npm version $(npm -v) echo pnpm version $(pnpm -v)
npm ci pnpm install
npm run create:config pnpm run create:config
npm run build:curriculum pnpm run build:curriculum
- name: Run Tests - name: Run Tests
env: env:
CURRICULUM_LOCALE: ${{ matrix.locale }} CURRICULUM_LOCALE: ${{ matrix.locale }}
CLIENT_LOCALE: ${{ matrix.locale }} CLIENT_LOCALE: ${{ matrix.locale }}
run: npm test run: pnpm test

View File

@@ -44,28 +44,28 @@ tasks:
# so we should put all the heavy initialization here # so we should put all the heavy initialization here
init: > init: >
cp sample.env .env && cp sample.env .env &&
npm ci && pnpm install &&
gp sync-done npm-ci && gp sync-done pnpm-install &&
gp ports await 27017 && gp ports await 27017 &&
npm run seed && pnpm run seed &&
mongo --eval "db.fsyncLock(); db.fsyncUnlock()" mongo --eval "db.fsyncLock(); db.fsyncUnlock()"
command: > command: >
npm run create:config && pnpm run create:config &&
npm run build:curriculum && pnpm run build:curriculum &&
gp ports await 27017 && gp ports await 27017 &&
npm run develop:server pnpm run develop:server
- name: client - name: client
before: export HOME_LOCATION=$(gp url 8000) && export API_LOCATION=$(gp url 3000) && export CYPRESS_BASE_URL=$(gp url 8000) before: export HOME_LOCATION=$(gp url 8000) && export API_LOCATION=$(gp url 3000) && export CYPRESS_BASE_URL=$(gp url 8000)
init: > init: >
cd ./client && cd ./client &&
gp sync-await npm-ci && gp sync-await pnpm-install &&
npm run predevelop && pnpm run predevelop &&
cd .. cd ..
command: > command: >
gp ports await 3000 && gp ports await 3000 &&
cd ./client && cd ./client &&
npm run develop -- -H '0.0.0.0' pnpm run develop -- -H '0.0.0.0'
openMode: split-right openMode: split-right
github: github:

View File

@@ -43,7 +43,7 @@ module.exports = {
if (files.length > 10) { if (files.length > 10) {
completedStages.add('markdown'); completedStages.add('markdown');
return 'npm run lint:challenges'; return 'pnpm run lint:challenges';
} else { } else {
return files.map( return files.map(
filename => `node ./tools/scripts/lint/index.js '${filename}'` filename => `node ./tools/scripts/lint/index.js '${filename}'`

5
.npmrc
View File

@@ -1 +1,4 @@
CYPRESS_INSTALL_BINARY=0 auto-install-peers=true
strict-peer-dependencies=true
# TODO: consider reworking the scripts to avoid usage of pre/post scripts
enable-pre-post-scripts=true

View File

@@ -20,8 +20,8 @@ utils/get-lines.js
utils/get-lines.test.js utils/get-lines.test.js
utils/validate.js utils/validate.js
utils/validate.test.js utils/validate.test.js
**/package-lock.json pnpm-lock.yaml
web/.next web/.next
curriculum-server/data/curriculum.json curriculum-server/data/curriculum.json
docs/**/*.md docs/**/*.md
client/src/components/Donation/types.js client/src/components/Donation/types.js

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -30,7 +30,7 @@ if (process.env.WEBHOOK_PROXY_URL) {
nodemon({ nodemon({
ext: 'js json', ext: 'js json',
// --silent squashes an ELIFECYCLE error when the server exits // --silent squashes an ELIFECYCLE error when the server exits
exec: 'npm run --silent babel-dev-server', exec: 'pnpm run --silent babel-dev-server',
watch: path.resolve(__dirname, './server'), watch: path.resolve(__dirname, './server'),
spawn: true, spawn: true,
env: { env: {

View File

@@ -14,7 +14,7 @@ module.exports = function mountLoopBackExplorer(app) {
// Do not print any message when the project is used as a component. // Do not print any message when the project is used as a component.
app.once('started', function () { app.once('started', function () {
log( log(
'Run `npm install loopback-component-explorer` to enable ' + 'Run `pnpm add loopback-component-explorer` to enable ' +
'the LoopBack explorer' 'the LoopBack explorer'
); );
}); });

View File

@@ -8,7 +8,8 @@
"@fastify/mongodb": "6.2.0", "@fastify/mongodb": "6.2.0",
"fastify": "4.13.0", "fastify": "4.13.0",
"fastify-auth0-verify": "^1.0.0", "fastify-auth0-verify": "^1.0.0",
"fastify-plugin": "^4.3.0" "fastify-plugin": "^4.3.0",
"nodemon": "2.0.20"
}, },
"description": "The freeCodeCamp.org open-source codebase and curriculum", "description": "The freeCodeCamp.org open-source codebase and curriculum",
"engines": { "engines": {

View File

@@ -22,6 +22,7 @@ module.exports = {
}, },
pathPrefix: pathPrefix, pathPrefix: pathPrefix,
plugins: [ plugins: [
'gatsby-plugin-pnpm',
{ {
resolve: '@sentry/gatsby', resolve: '@sentry/gatsby',
options: { options: {

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -19,25 +19,27 @@
"author": "freeCodeCamp <team@freecodecamp.org>", "author": "freeCodeCamp <team@freecodecamp.org>",
"main": "none", "main": "none",
"scripts": { "scripts": {
"prebuild": "npm --prefix ../ run create:config && npm run build:workers -- --env production", "prebuild": "pnpm -w run create:config && pnpm run build:workers --env production",
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" gatsby build --prefix-paths", "build": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" gatsby build --prefix-paths",
"build:workers": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" webpack --config ./webpack-workers.js", "build:workers": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" webpack --config ./webpack-workers.js",
"clean": "gatsby clean", "clean": "gatsby clean",
"predevelop": "npm --prefix ../ run create:config && npm run build:workers -- --env development", "predevelop": "pnpm -w run create:config && pnpm run build:workers --env development",
"develop": "cross-env NODE_OPTIONS=\"--max-old-space-size=5000\" gatsby develop --inspect=9230", "develop": "cross-env NODE_OPTIONS=\"--max-old-space-size=5000\" gatsby develop --inspect=9230",
"lint": "ts-node ./i18n/schema-validation.ts", "lint": "ts-node ./i18n/schema-validation.ts",
"serve": "gatsby serve -p 8000", "serve": "gatsby serve -p 8000",
"serve-ci": "serve -l 8000 -c serve.json public", "serve-ci": "serve -l 8000 -c serve.json public",
"prestand-alone": "npm run prebuild", "prestand-alone": "pnpm run prebuild",
"stand-alone": "gatsby develop", "stand-alone": "gatsby develop",
"validate-keys": "ts-node --project ../tsconfig.json ../tools/scripts/lint/validate-keys" "validate-keys": "ts-node --project ../tsconfig.json ../tools/scripts/lint/validate-keys"
}, },
"dependencies": { "dependencies": {
"@babel/plugin-proposal-export-default-from": "7.18.10", "@babel/plugin-proposal-export-default-from": "7.18.10",
"@babel/plugin-proposal-function-bind": "7.18.9", "@babel/plugin-proposal-function-bind": "7.18.9",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/polyfill": "7.12.1", "@babel/polyfill": "7.12.1",
"@babel/preset-env": "7.20.2", "@babel/preset-env": "7.20.2",
"@babel/preset-react": "7.18.6", "@babel/preset-react": "7.18.6",
"@babel/runtime": "^7.20.13",
"@babel/standalone": "7.20.15", "@babel/standalone": "7.20.15",
"@fortawesome/fontawesome-svg-core": "6.3.0", "@fortawesome/fontawesome-svg-core": "6.3.0",
"@fortawesome/free-brands-svg-icons": "6.3.0", "@fortawesome/free-brands-svg-icons": "6.3.0",
@@ -51,12 +53,14 @@
"@growthbook/growthbook-react": "0.11.2", "@growthbook/growthbook-react": "0.11.2",
"@loadable/component": "5.15.3", "@loadable/component": "5.15.3",
"@reach/router": "1.3.4", "@reach/router": "1.3.4",
"@redux-saga/core": "^1.2.2",
"@sentry/gatsby": "6.19.7", "@sentry/gatsby": "6.19.7",
"@stripe/react-stripe-js": "1.16.5", "@stripe/react-stripe-js": "1.16.5",
"@stripe/stripe-js": "1.47.0", "@stripe/stripe-js": "1.47.0",
"@types/react-scrollable-anchor": "0.6.1", "@testing-library/jest-dom": "5.16.5",
"algoliasearch": "4.14.3", "algoliasearch": "4.14.3",
"assert": "2.0.0", "assert": "2.0.0",
"babel-loader": "8.3.0",
"babel-plugin-preval": "5.1.0", "babel-plugin-preval": "5.1.0",
"babel-plugin-prismjs": "2.1.0", "babel-plugin-prismjs": "2.1.0",
"bezier-easing": "2.1.0", "bezier-easing": "2.1.0",
@@ -67,6 +71,7 @@
"date-fns": "2.29.3", "date-fns": "2.29.3",
"enzyme": "3.11.0", "enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.7", "enzyme-adapter-react-16": "1.15.7",
"eslint": "7",
"final-form": "4.20.9", "final-form": "4.20.9",
"gatsby": "3.15.0", "gatsby": "3.15.0",
"gatsby-cli": "3.15.0", "gatsby-cli": "3.15.0",
@@ -74,6 +79,7 @@
"gatsby-plugin-advanced-sitemap": "2.1.0", "gatsby-plugin-advanced-sitemap": "2.1.0",
"gatsby-plugin-create-client-paths": "3.15.0", "gatsby-plugin-create-client-paths": "3.15.0",
"gatsby-plugin-manifest": "3.15.0", "gatsby-plugin-manifest": "3.15.0",
"gatsby-plugin-pnpm": "^1.2.10",
"gatsby-plugin-postcss": "4.15.0", "gatsby-plugin-postcss": "4.15.0",
"gatsby-plugin-react-helmet": "4.15.0", "gatsby-plugin-react-helmet": "4.15.0",
"gatsby-plugin-remove-serviceworker": "1.0.0", "gatsby-plugin-remove-serviceworker": "1.0.0",
@@ -136,7 +142,32 @@
"@codesee/tracker": "0.523.0", "@codesee/tracker": "0.523.0",
"@testing-library/jest-dom": "5.16.5", "@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "12.1.5", "@testing-library/react": "12.1.5",
"@types/chai": "^4.3.4",
"@types/enzyme": "^3.10.12",
"@types/enzyme-adapter-react-16": "1.0.6",
"@types/jest": "27.5.2",
"@types/jquery": "^3.5.16",
"@types/loadable__component": "5.13.4",
"@types/lodash-es": "^4.17.6",
"@types/prismjs": "^1.26.0",
"@types/reach__router": "1.3.11",
"@types/react": "16.14.35",
"@types/react-dom": "16.9.17",
"@types/react-gtm-module": "2.0.1", "@types/react-gtm-module": "2.0.1",
"@types/react-helmet": "6.1.6",
"@types/react-instantsearch-core": "6.26.3",
"@types/react-instantsearch-dom": "6.12.3",
"@types/react-redux": "7.1.25",
"@types/react-responsive": "8.0.5",
"@types/react-scrollable-anchor": "0.6.0",
"@types/react-spinkit": "3.0.7",
"@types/react-test-renderer": "16.9.5",
"@types/react-transition-group": "4.4.5",
"@types/redux-actions": "2.6.2",
"@types/sanitize-html": "^2.8.0",
"@types/store": "^2.0.2",
"@types/testing-library__jest-dom": "^5.14.5",
"@types/validator": "^13.7.12",
"autoprefixer": "10.4.13", "autoprefixer": "10.4.13",
"babel-plugin-transform-imports": "2.0.0", "babel-plugin-transform-imports": "2.0.0",
"chokidar": "3.5.3", "chokidar": "3.5.3",

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -6,7 +6,8 @@ import { Col, Grid, Row } from '@freecodecamp/react-bootstrap';
import { graphql } from 'gatsby'; import { graphql } from 'gatsby';
import React, { Component } from 'react'; import React, { Component } from 'react';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import { TFunction, withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import type { TFunction } from 'i18next';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';

19
client/tsconfig.json Normal file
View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"lib": ["WebWorker", "DOM", "DOM.Iterable", "ES2020"],
"target": "es2020",
"module": "es2020",
"moduleResolution": "node",
"allowJs": true,
"jsx": "react",
"strict": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true
},
"include": ["i18n/**/*", "plugins/**/*", "src/**/*", "utils/**/*"]
}

View File

@@ -62,7 +62,7 @@ module.exports = (env = {}) => {
}, },
plugins: [ plugins: [
new CopyWebpackPlugin({ new CopyWebpackPlugin({
patterns: ['../node_modules/sass.js/dist/sass.sync.js'] patterns: ['./node_modules/sass.js/dist/sass.sync.js']
}), }),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
process: 'process/browser' process: 'process/browser'

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -25,8 +25,8 @@
"delete-step": "cross-env CALLING_DIR=$INIT_CWD ts-node --project ../tsconfig.json ../tools/challenge-helper-scripts/delete-step", "delete-step": "cross-env CALLING_DIR=$INIT_CWD ts-node --project ../tsconfig.json ../tools/challenge-helper-scripts/delete-step",
"lint": "ts-node --project ../tsconfig.json lint-localized", "lint": "ts-node --project ../tsconfig.json lint-localized",
"update-step-titles": "cross-env CALLING_DIR=$INIT_CWD ts-node --project ../tsconfig.json ../tools/challenge-helper-scripts/update-step-titles", "update-step-titles": "cross-env CALLING_DIR=$INIT_CWD ts-node --project ../tsconfig.json ../tools/challenge-helper-scripts/update-step-titles",
"test": "ts-node ../node_modules/mocha/bin/mocha.js --delay --exit --reporter progress --bail", "test": "ts-node ./node_modules/mocha/bin/mocha.js --delay --exit --reporter progress --bail",
"test:full-output": "cross-env FULL_OUTPUT=true ts-node ../node_modules/mocha/bin/mocha.js --delay --reporter progress" "test:full-output": "cross-env FULL_OUTPUT=true ts-node ./node_modules/mocha/bin/mocha.js --delay --reporter progress"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.20.12", "@babel/core": "7.20.12",

View File

@@ -110,7 +110,7 @@ setup()
.catch(err => handleRejection(err)); .catch(err => handleRejection(err));
async function setup() { async function setup() {
if (process.env.npm_config_superblock && process.env.npm_config_block) { if (process.env.FCC_SUPERBLOCK && process.env.FCC_BLOCK) {
throw new Error(`Please do not use both a block and superblock as input.`); throw new Error(`Please do not use both a block and superblock as input.`);
} }
@@ -152,9 +152,9 @@ async function setup() {
]; ];
// the next few statements will filter challenges based on command variables // the next few statements will filter challenges based on command variables
if (process.env.npm_config_superblock) { if (process.env.FCC_SUPERBLOCK) {
const filter = stringSimilarity.findBestMatch( const filter = stringSimilarity.findBestMatch(
process.env.npm_config_superblock, process.env.FCC_SUPERBLOCK,
targetSuperBlockStrings targetSuperBlockStrings
).bestMatch.target; ).bestMatch.target;
@@ -168,9 +168,9 @@ async function setup() {
} }
} }
if (process.env.npm_config_block) { if (process.env.FCC_BLOCK) {
const filter = stringSimilarity.findBestMatch( const filter = stringSimilarity.findBestMatch(
process.env.npm_config_block, process.env.FCC_BLOCK,
targetBlockStrings targetBlockStrings
).bestMatch.target; ).bestMatch.target;
@@ -241,7 +241,7 @@ function populateTestsForLang({ lang, challenges, meta }) {
const challengeTitles = new ChallengeTitles(); const challengeTitles = new ChallengeTitles();
const validateChallenge = challengeSchemaValidator(); const validateChallenge = challengeSchemaValidator();
if (!process.env.npm_config_block) { if (!process.env.FCC_BLOCK) {
describe('Assert meta order', function () { describe('Assert meta order', function () {
/** This array can be used to skip a superblock - we'll use this /** This array can be used to skip a superblock - we'll use this
* when we are working on the new project-based curriculum for * when we are working on the new project-based curriculum for

View File

@@ -5,7 +5,7 @@ const version = pkg.version;
(async () => { (async () => {
console.log('Installing Cypress ' + version); console.log('Installing Cypress ' + version);
await execa('npm', ['run', 'cypress:install'], { await execa('pnpm', ['run', 'cypress:install'], {
env: { CYPRESS_INSTALL_BINARY: version } env: { CYPRESS_INSTALL_BINARY: version }
}); });
console.log('Cypress installed'); console.log('Cypress installed');

View File

@@ -13,7 +13,7 @@ module.exports = defineConfig({
config.env = config.env || {}; config.env = config.env || {};
on('before:run', () => { on('before:run', () => {
if (!existsSync('./config/curriculum.json')) { if (!existsSync('./config/curriculum.json')) {
execSync('npm run build:curriculum'); execSync('pnpm run build:curriculum');
} }
}); });

View File

@@ -1,6 +1,6 @@
describe('Donate page', () => { describe('Donate page', () => {
beforeEach(() => { beforeEach(() => {
cy.exec('npm run seed -- --donor'); cy.exec('pnpm run seed -- --donor');
cy.login(); cy.login();
}); });

View File

@@ -1,12 +1,12 @@
describe('Donate page', () => { describe('Donate page', () => {
before(() => { before(() => {
cy.clearCookies(); cy.clearCookies();
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
}); });
after(() => { after(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
}); });
const projects = [ const projects = [

View File

@@ -159,7 +159,7 @@ describe('Language menu keyboard accessibility', () => {
describe('Authenticated Navigation Menu', () => { describe('Authenticated Navigation Menu', () => {
before(() => { before(() => {
cy.clearCookies(); cy.clearCookies();
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
cy.get(selectors['toggle-button']).should('be.visible').click(); cy.get(selectors['toggle-button']).should('be.visible').click();
}); });
@@ -181,7 +181,7 @@ describe('Authenticated Navigation Menu', () => {
describe('Authenticated User Sign Out', () => { describe('Authenticated User Sign Out', () => {
before(() => { before(() => {
cy.clearCookies(); cy.clearCookies();
cy.exec('npm run seed'); cy.exec('pnpm run seed');
}); });
beforeEach(() => { beforeEach(() => {
cy.login(); cy.login();
@@ -207,7 +207,7 @@ describe('Authenticated User Sign Out', () => {
describe('Donor Navigation Menu', () => { describe('Donor Navigation Menu', () => {
before(() => { before(() => {
cy.clearCookies(); cy.clearCookies();
cy.exec('npm run seed -- --donor'); cy.exec('pnpm run seed -- --donor');
cy.login(); cy.login();
cy.visit('/donate'); cy.visit('/donate');
}); });

View File

@@ -4,7 +4,7 @@ const introPageSelectors = {
describe('Certification intro page', () => { describe('Certification intro page', () => {
before(() => { before(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
}); });

View File

@@ -29,7 +29,7 @@ const projects = {
describe('Front End Development Libraries Superblock', () => { describe('Front End Development Libraries Superblock', () => {
before(() => { before(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
cy.visit('/learn/front-end-development-libraries'); cy.visit('/learn/front-end-development-libraries');
}); });
@@ -41,7 +41,7 @@ describe('Front End Development Libraries Superblock', () => {
}); });
describe('After submitting all 5 projects', () => { describe('After submitting all 5 projects', () => {
before(() => { before(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
cy.visit('/settings'); cy.visit('/settings');
cy.setPrivacyTogglesToPublic(); cy.setPrivacyTogglesToPublic();

View File

@@ -3,7 +3,7 @@ import '@testing-library/cypress/add-commands';
describe('Settings certifications area', () => { describe('Settings certifications area', () => {
describe('initially', () => { describe('initially', () => {
before(() => { before(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
}); });
@@ -23,7 +23,7 @@ describe('Settings certifications area', () => {
describe('after isHonest', () => { describe('after isHonest', () => {
before(() => { before(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
}); });

View File

@@ -1,6 +1,6 @@
describe('Email input field', () => { describe('Email input field', () => {
beforeEach(() => { beforeEach(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
cy.visit('/settings'); cy.visit('/settings');
}); });

View File

@@ -1,7 +1,7 @@
describe('User token widget on settings page,', function () { describe('User token widget on settings page,', function () {
describe('initially', function () { describe('initially', function () {
beforeEach(() => { beforeEach(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
}); });
@@ -15,7 +15,7 @@ describe('User token widget on settings page,', function () {
describe('after creating token', function () { describe('after creating token', function () {
beforeEach(() => { beforeEach(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
cy.visit( cy.visit(
'/learn/relational-database/learn-bash-by-building-a-boilerplate/build-a-boilerplate' '/learn/relational-database/learn-bash-by-building-a-boilerplate/build-a-boilerplate'

View File

@@ -2,7 +2,7 @@ const certifiedUser = '/certification/certifieduser/responsive-web-design';
describe('A certification,', function () { describe('A certification,', function () {
before(() => { before(() => {
cy.exec('npm run seed:certified-user'); cy.exec('pnpm run seed:certified-user');
}); });
describe('while viewing your own,', function () { describe('while viewing your own,', function () {

View File

@@ -1,11 +1,11 @@
describe('Top contributor in user profile', () => { describe('Top contributor in user profile', () => {
before(() => { before(() => {
cy.clearCookies(); cy.clearCookies();
cy.exec('npm run seed -- --top-contributor'); cy.exec('pnpm run seed -- --top-contributor');
}); });
after(() => { after(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
}); });
beforeEach(() => { beforeEach(() => {

View File

@@ -1,7 +1,7 @@
describe('Public profile certifications', () => { describe('Public profile certifications', () => {
context('Signed in user viewing their own public profile', () => { context('Signed in user viewing their own public profile', () => {
before(() => { before(() => {
cy.exec('npm run seed:certified-user'); cy.exec('pnpm run seed:certified-user');
}); });
beforeEach(() => { beforeEach(() => {

View File

@@ -7,7 +7,7 @@ describe('Privacy terms', () => {
}).as('updatePrivacyTerms'); }).as('updatePrivacyTerms');
// Seed dev user with `acceptedPrivacyTerms` unset // Seed dev user with `acceptedPrivacyTerms` unset
cy.exec('npm run seed -- --unset-privacy-terms'); cy.exec('pnpm run seed -- --unset-privacy-terms');
// Go to the homepage and log in manually so we can assert the following: // Go to the homepage and log in manually so we can assert the following:
// 1. Redirection to /email-sign-up works properly // 1. Redirection to /email-sign-up works properly
// 2. The /update-privacy-terms has not been requested // 2. The /update-privacy-terms has not been requested

View File

@@ -1,6 +1,6 @@
describe('Report User', () => { describe('Report User', () => {
beforeEach(() => { beforeEach(() => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
}); });
it('should be possible to report a user from their profile page', () => { it('should be possible to report a user from their profile page', () => {

View File

@@ -1,6 +1,6 @@
describe('Donate page', () => { describe('Donate page', () => {
it('Donation ', () => { it('Donation ', () => {
cy.exec('npm run seed'); cy.exec('pnpm run seed');
cy.login(); cy.login();
cy.visit('/donate'); cy.visit('/donate');
cy.get('.donation-elements', { timeout: 10000 }).within(() => { cy.get('.donation-elements', { timeout: 10000 }).within(() => {

View File

@@ -22,7 +22,7 @@ module.exports = (on, config) => {
config.env = config.env || {}; config.env = config.env || {};
on('before:run', () => { on('before:run', () => {
if (!existsSync('../../config/curriculum.json')) { if (!existsSync('../../config/curriculum.json')) {
execSync('npm run build:curriculum'); execSync('pnpm run build:curriculum');
} }
}); });

View File

@@ -9,7 +9,7 @@ COPY --chown=node:node . .
ARG DOPPLER_TOKEN ARG DOPPLER_TOKEN
RUN \ RUN \
doppler secrets download doppler.encrypted.json &&\ doppler secrets download doppler.encrypted.json &&\
npm ci --no-progress --ignore-scripts &&\ pnpm install --no-progress --ignore-scripts &&\
doppler run --fallback=doppler.encrypted.json --command="npm run create:config" &&\ doppler run --fallback=doppler.encrypted.json --command="npm run create:config" &&\
doppler run --fallback=doppler.encrypted.json --command="npm run build:curriculum" &&\ doppler run --fallback=doppler.encrypted.json --command="npm run build:curriculum" &&\
doppler run --fallback=doppler.encrypted.json --command="npm run build:server" doppler run --fallback=doppler.encrypted.json --command="npm run build:server"
@@ -18,7 +18,7 @@ FROM node:16-alpine as depends
USER node USER node
WORKDIR /home/node/depends WORKDIR /home/node/depends
COPY --chown=node:node . . COPY --chown=node:node . .
RUN npm ci --production --workspace=api-server --no-progress --ignore-scripts RUN pnpm install --production --workspace=api-server --no-progress --ignore-scripts
FROM node:16-alpine FROM node:16-alpine
RUN npm i -g pm2@4 RUN npm i -g pm2@4

View File

@@ -10,7 +10,7 @@ ARG DOPPLER_TOKEN
RUN \ RUN \
doppler secrets download doppler.encrypted.json &&\ doppler secrets download doppler.encrypted.json &&\
# Install and donot ignore the scripts for sharp # Install and donot ignore the scripts for sharp
npm ci --no-progress --ignore-scripts=false &&\ pnpm install --no-progress --ignore-scripts=false &&\
doppler run --fallback=doppler.encrypted.json --command="npm run create:config" &&\ doppler run --fallback=doppler.encrypted.json --command="npm run create:config" &&\
doppler run --fallback=doppler.encrypted.json --command="npm run build:curriculum" &&\ doppler run --fallback=doppler.encrypted.json --command="npm run build:curriculum" &&\
doppler run --fallback=doppler.encrypted.json --command="npm run build:client" doppler run --fallback=doppler.encrypted.json --command="npm run build:client"

View File

@@ -96,7 +96,7 @@ Currently, only members on the developer team can push to the production branche
4. Confirm that you are able to build the repository locally. 4. Confirm that you are able to build the repository locally.
``` ```
npm run clean-and-develop pnpm run clean-and-develop
``` ```
5. Move changes from `main` to `prod-staging` via a fast-forward merge 5. Move changes from `main` to `prod-staging` via a fast-forward merge
@@ -476,13 +476,13 @@ Provisioning VMs with the Code
6. Install dependencies 6. Install dependencies
```console ```console
npm ci pnpm install
``` ```
7. Build the server 7. Build the server
```console ```console
npm run prebuild && npm run build:curriculum && npm run build:server pnpm run prebuild && pnpm run build:curriculum && pnpm run build:server
``` ```
8. Start Instances 8. Start Instances
@@ -522,13 +522,13 @@ pm2 stop all
2. Install dependencies 2. Install dependencies
```console ```console
npm ci pnpm install
``` ```
3. Build the server 3. Build the server
```console ```console
npm run create:config && npm run build:curriculum && npm run build:server pnpm run create:config && pnpm run build:curriculum && pnpm run build:server
``` ```
4. Start Instances 4. Start Instances
@@ -824,8 +824,8 @@ ssh into the VM (hosted on Digital Ocean).
```console ```console
cd tools cd tools
git pull origin master git pull origin master
npm ci pnpm install
npm run build pnpm run build
pm2 restart contribute-app pm2 restart contribute-app
``` ```

View File

@@ -28,25 +28,25 @@ To run tests against production builds, replace `dev` with `prd` below.
- To run all tests in the `./cypress` directory: - To run all tests in the `./cypress` directory:
```console ```console
npm run cypress:dev:run pnpm run cypress:dev:run
``` ```
- To run a single test: - To run a single test:
```console ```console
npm run cypress -- run --spec=cypress/<path_to_test_file> pnpm run cypress -- run --spec=cypress/<path_to_test_file>
``` ```
For example: For example:
```console ```console
npm run cypress -- run --spec=cypress/e2e/default/landing.js pnpm run cypress -- run --spec=cypress/e2e/default/landing.js
``` ```
- To create a development build, start the development server, and run all existing cypress end-to-end tests: - To create a development build, start the development server, and run all existing cypress end-to-end tests:
```console ```console
npm run e2e:dev:run pnpm run e2e:dev:run
``` ```
## Cypress-GitPod Setup ## Cypress-GitPod Setup
@@ -64,19 +64,19 @@ mongod
- Seed the database - Seed the database
```console ```console
npm run seed pnpm run seed
``` ```
- Develop the server and client - Develop the server and client
```console ```console
npm run develop pnpm run develop
``` ```
### 2. Install Cypress Build Tools ### 2. Install Cypress Build Tools
```console ```console
npm run cypress:install-build-tools pnpm run cypress:install-build-tools
``` ```
- When prompted in the terminal, select your keyboard layout by language/area - When prompted in the terminal, select your keyboard layout by language/area

View File

@@ -204,13 +204,13 @@ A quick reference to the commands that you will need when working.
| command | description | | command | description |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `npm test` | Run all JS tests in the system, including client, server, lint and challenge tests. | | `pnpm test` | Run all JS tests in the system, including client, server, lint and challenge tests. |
| `npm run test-client` | Run the client test suite. | | `pnpm run test-client` | Run the client test suite. |
| `npm run test:curriculum` | Run the curriculum test suite. | | `pnpm run test:curriculum` | Run the curriculum test suite. |
| `npm run test:curriculum --block='Basic HTML and HTML5'` | Test a specific Block. | | `FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum` | Test a specific Block. |
| `npm run test:curriculum --superblock='responsive-web-design'` | Test a specific SuperBlock. | | `FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum` | Test a specific SuperBlock. |
| `npm run test-curriculum-full-output` | Run the curriculum test suite, without bailing after the first error | | `pnpm run test-curriculum-full-output` | Run the curriculum test suite, without bailing after the first error |
| `npm run test-server` | Run the server test suite. | | `pnpm run test-server` | Run the server test suite. |
| `npm run e2e` | Run the Cypress end to end tests. | | `pnpm run e2e` | Run the Cypress end to end tests. |
| `npm run clean` | Uninstalls all dependencies and cleans up caches. | | `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
| `npm run storybook` | Starts Storybook for component library development. | | `pnpm run storybook` | Starts Storybook for component library development. |

View File

@@ -297,10 +297,10 @@ Once you have the files, you will need to place them in the correct directory. F
Update your `.env` file to use your new language for `CLIENT_LOCALE` and `CURRICULUM_LOCALE`. Update your `.env` file to use your new language for `CLIENT_LOCALE` and `CURRICULUM_LOCALE`.
Once these are in place, you should be able to run `npm run develop` to view your translated version of freeCodeCamp. Once these are in place, you should be able to run `pnpm run develop` to view your translated version of freeCodeCamp.
> [!TIP] > [!TIP]
> If you build the client in one language and then want to build it in a different language, you will need to use the command `npm run clean-and-develop` after changing the `.env` file, as Gatsby will cache the first language. > If you build the client in one language and then want to build it in a different language, you will need to use the command `pnpm run clean-and-develop` after changing the `.env` file, as Gatsby will cache the first language.
> [!ATTENTION] > [!ATTENTION]
> While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing. > While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.

View File

@@ -191,14 +191,14 @@ When you are working on features for our upcoming curriculum `next-*` branches,
4. Resolve any conflicts, cleanup, install dependencies and run tests 4. Resolve any conflicts, cleanup, install dependencies and run tests
```console ```console
npm run clean pnpm run clean
npm ci pnpm install
npm run test:curriculum --superblock=<superblock-name> FCC_SUPERBLOCK='<superblock-name>' pnpm run test:curriculum
# example: # example:
# npm run test:curriculum --superblock=python-for-everybody # FCC_SUPERBLOCK='python-for-everybody' pnpm run test:curriculum
``` ```

View File

@@ -76,7 +76,7 @@ Some community members also develop on Windows natively with Git for Windows (Gi
| Prerequisite | Version | Notes | | Prerequisite | Version | Notes |
| --------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- | | --------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| [Node.js](http://nodejs.org) | `18.x` | We use the "Active LTS" version, See [LTS Schedule](https://nodejs.org/en/about/releases/). | | [Node.js](http://nodejs.org) | `18.x` | We use the "Active LTS" version, See [LTS Schedule](https://nodejs.org/en/about/releases/). |
| npm (comes bundled with Node) | `8.x` | We use the version bundled with Node.js Active LTS. | | [pnpm](https://pnpm.io/installation) | `7.x` |- |
| [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `4.2.x` | - | | [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `4.2.x` | - |
> [!ATTENTION] > [!ATTENTION]
@@ -86,7 +86,7 @@ If Node.js is already installed on your machine, run the following commands to v
```console ```console
node -v node -v
npm -v pnpm -v
``` ```
> [!TIP] > [!TIP]
@@ -221,7 +221,7 @@ The keys in the `.env` file are _not_ required to be changed to run the app loca
This step will install the dependencies required for the application to run: This step will install the dependencies required for the application to run:
```console ```console
npm ci pnpm install
``` ```
#### Step 3: Start MongoDB and seed the database #### Step 3: Start MongoDB and seed the database
@@ -261,7 +261,7 @@ Make sure to replace `3.6` with the version you have installed
Next, let's seed the database. In this step, we run the below command that fills the MongoDB server with some initial data sets that are required by services. These include a few schemas, among other things. Next, let's seed the database. In this step, we run the below command that fills the MongoDB server with some initial data sets that are required by services. These include a few schemas, among other things.
```console ```console
npm run seed pnpm run seed
``` ```
#### Step 4: Start the freeCodeCamp client application and API server #### Step 4: Start the freeCodeCamp client application and API server
@@ -269,7 +269,7 @@ npm run seed
You can now start up the API server and the client applications. You can now start up the API server and the client applications.
```console ```console
npm run develop pnpm run develop
``` ```
This single command will fire up all the services, including the API server and the client applications available for you to work on. This single command will fire up all the services, including the API server and the client applications available for you to work on.
@@ -281,7 +281,7 @@ The API serves endpoints at `http://localhost:3000`. The Gatsby app serves the c
While you are logged in, if you visit <http://localhost:3000/explorer> you should see the available APIs. While you are logged in, if you visit <http://localhost:3000/explorer> you should see the available APIs.
> [!WARNING] > [!WARNING]
> Clearing your cookies or running `npm run seed:certified-user` will log you out, and you will have to sign in again. > Clearing your cookies or running `pnpm run seed:certified-user` will log you out, and you will have to sign in again.
If you have issues while installing it, check out the [troubleshooting section](troubleshooting-development-issues.md) If you have issues while installing it, check out the [troubleshooting section](troubleshooting-development-issues.md)
@@ -291,7 +291,7 @@ A quick reference to the commands that you will need when working locally.
| command | description | | command | description |
| ----------------- | ----------------------------------------------------------------------------- | | ----------------- | ----------------------------------------------------------------------------- |
| `npm ci` | Installs / re-install all dependencies and bootstraps the different services. | | `pnpm install` | Installs / re-install all dependencies and bootstraps the different services. |
| `npm run seed` | Creates authorized test users and inserts them into mongodb. | | `pnpm run seed` | Creates authorized test users and inserts them into mongodb. |
| `npm run develop` | Starts the freeCodeCamp API Server and Client Applications. | | `pnpm run develop` | Starts the freeCodeCamp API Server and Client Applications. |
| `npm run clean` | Uninstalls all dependencies and cleans up caches. | | `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |

View File

@@ -12,4 +12,4 @@ If you see messages like
bash: change_volumes_owner.sh: No such file or directory bash: change_volumes_owner.sh: No such file or directory
``` ```
when you `npm run docker:init` this is likely the culprit. when you `pnpm run docker:init` this is likely the culprit.

View File

@@ -457,17 +457,17 @@ Before you [create a pull request](how-to-open-a-pull-request.md) for your chang
1. To test all challenges run the below command from the root directory 1. To test all challenges run the below command from the root directory
``` ```
npm run test:curriculum pnpm run test:curriculum
``` ```
2. You can also test a block or a superblock of challenges with these commands 2. You can also test a block or a superblock of challenges with these commands
``` ```
npm run test:curriculum --block='Basic HTML and HTML5' FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum
``` ```
``` ```
npm run test:curriculum --superblock=responsive-web-design FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum
``` ```
You are also able to test one challenge individually by performing the following steps: You are also able to test one challenge individually by performing the following steps:
@@ -481,7 +481,7 @@ You are also able to test one challenge individually by performing the following
2. Run the following for each challenge file for which you have changed (replacing `challenge-title-goes-here` with the full title of the challenge): 2. Run the following for each challenge file for which you have changed (replacing `challenge-title-goes-here` with the full title of the challenge):
``` ```
npm run test -- -g challenge-title-goes-here pnpm run test -- -g challenge-title-goes-here
``` ```
Once you have verified that each challenge you've worked on passes the tests, [please create a pull request](how-to-open-a-pull-request.md). Once you have verified that each challenge you've worked on passes the tests, [please create a pull request](how-to-open-a-pull-request.md).

View File

@@ -10,7 +10,7 @@ These instructions will tell you how to use our challenge editor tool to work on
### Starting the Editor ### Starting the Editor
To start the editor, make sure you are in the root freecodecamp directory. Then, run `npm run challenge-editor` to start both the client and the API that powers the editor. To start the editor, make sure you are in the root freecodecamp directory. Then, run `pnpm run challenge-editor` to start both the client and the API that powers the editor.
The client will run on port `3300`, so you can access it at `http://localhost:3300`. The API runs on port `3200`, to avoid conflicts with the learn client and server. This will allow you to run the freeCodeCamp application at the same time as the editor, so you can test your changes locally. The client will run on port `3300`, so you can access it at `http://localhost:3300`. The API runs on port `3200`, to avoid conflicts with the learn client and server. This will allow you to run the freeCodeCamp application at the same time as the editor, so you can test your changes locally.
@@ -60,7 +60,7 @@ The `tools/challenge-helper-scripts` folder contains tools to help facilitate th
### Create a new project ### Create a new project
Run `npm run create-project` from the root directory. This opens up a command line ui that guides you through the process. Once that has finished, there should be a new challenge in the English curriculum that you can use for the first step of the project. For example, if you created a project called `test-project` in the Responsive Web Design certification, it would be in `curriculum/challenges/english/01-responsive-web-design/test-project`. Run `pnpm run create-project` from the root directory. This opens up a command line ui that guides you through the process. Once that has finished, there should be a new challenge in the English curriculum that you can use for the first step of the project. For example, if you created a project called `test-project` in the Responsive Web Design certification, it would be in `curriculum/challenges/english/01-responsive-web-design/test-project`.
If you want to create new steps, the following tools simplify that process. If you want to create new steps, the following tools simplify that process.
@@ -71,10 +71,10 @@ A one-off script that will automatically add the next step based on the last ste
#### How to run script: #### How to run script:
1. Change to the directory of the project. 1. Change to the directory of the project.
2. Run the following npm command: 2. Run the following command:
```bash ```bash
npm run create-next-step pnpm run create-next-step
``` ```
### create-empty-steps ### create-empty-steps
@@ -86,10 +86,10 @@ A one-off script that automatically adds a specified number of steps. The challe
#### How to run script: #### How to run script:
1. Change to the directory of the project. 1. Change to the directory of the project.
2. Run the following npm command: 2. Run the following command:
```bash ```bash
npm run create-empty-steps X # where X is the number of steps to create. pnpm run create-empty-steps X # where X is the number of steps to create.
``` ```
### insert-step ### insert-step
@@ -101,10 +101,10 @@ A one-off script that automatically adds a new step at a specified position, inc
#### How to run script: #### How to run script:
1. Change to the directory of the project. 1. Change to the directory of the project.
2. Run the following npm command: 2. Run the following command:
```bash ```bash
npm run insert-step X # where X is the position to insert the new step. pnpm run insert-step X # where X is the position to insert the new step.
``` ```
### delete-step ### delete-step
@@ -116,10 +116,10 @@ A one-off script that deletes an existing step, decrementing all subsequent step
#### How to run script #### How to run script
1. Change to the directory of the project. 1. Change to the directory of the project.
2. Run the following npm command: 2. Run the following command:
```bash ```bash
npm run delete-step X # where X is the step number to be deleted. pnpm run delete-step X # where X is the step number to be deleted.
``` ```
### update-step-titles ### update-step-titles
@@ -129,8 +129,8 @@ A one-off script that automatically updates the frontmatter in a project's markd
#### How to run script #### How to run script
1. Change to the directory of the project. 1. Change to the directory of the project.
2. Run the following npm command: 2. Run the following command:
```bash ```bash
npm run update-step-titles pnpm run update-step-titles
``` ```

View File

@@ -30,7 +30,7 @@ A new component can be created using the following command from the root directo
```bash ```bash
cd tools/ui-components cd tools/ui-components
npm run gen-component MyComponent pnpm run gen-component MyComponent
``` ```
The command will generate a new folder inside the `ui-components` directory, with the following files: The command will generate a new folder inside the `ui-components` directory, with the following files:
@@ -77,7 +77,7 @@ Use cases of the component should be added to the Storybook file (`.stories.tsx`
To start Storybook, run the following command from the root directory: To start Storybook, run the following command from the root directory:
```bash ```bash
npm run storybook pnpm run storybook
``` ```
The Storybook page is available on [http://localhost:6006](http://localhost:6006). The Storybook page is available on [http://localhost:6006](http://localhost:6006).
@@ -89,7 +89,7 @@ We use [React Testing Library](https://testing-library.com/docs/react-testing-li
To run tests against the component library, run the following command from the root directory: To run tests against the component library, run the following command from the root directory:
```bash ```bash
npm run test-ui-components pnpm run test-ui-components
``` ```
## Adding packages to the UI-Component library ## Adding packages to the UI-Component library
@@ -97,7 +97,8 @@ npm run test-ui-components
We restrict adding new packages to the UI Components to help with the project's maintainability. In the rare chance that you think a dependency is needed, please check with the maintainers first and then use the following command to add a package: We restrict adding new packages to the UI Components to help with the project's maintainability. In the rare chance that you think a dependency is needed, please check with the maintainers first and then use the following command to add a package:
```bash ```bash
npm i -w=tools/ui-components package_name cd tools/ui-components
pnpm add package_name
``` ```
### Useful links ### Useful links

View File

@@ -51,13 +51,13 @@ Install freeCodeCamp locally ([see the local setup guide](how-to-setup-freecodec
#### Serve and launch the documentation site only #### Serve and launch the documentation site only
```console ```console
npm run docs:serve pnpm run docs:serve
``` ```
#### Serve the documentation site alongside freeCodeCamp locally: #### Serve the documentation site alongside freeCodeCamp locally:
```console ```console
npm run develop pnpm run develop
``` ```
> The documentation site should be available at <http://localhost:3400> > The documentation site should be available at <http://localhost:3400>

View File

@@ -17,10 +17,10 @@ If you are on a different OS or are still facing issues, see [getting help](#get
When you build the client, Gatsby will cache the Fonts, language strings and UI. If one of them isn't cached, run the following: When you build the client, Gatsby will cache the Fonts, language strings and UI. If one of them isn't cached, run the following:
```console ```console
npm run clean pnpm run clean
npm ci pnpm install
npm run seed pnpm run seed
npm run develop pnpm run develop
``` ```
OR OR
@@ -28,7 +28,7 @@ OR
Use the shortcut Use the shortcut
``` ```
npm run clean-and-develop pnpm run clean-and-develop
``` ```
If you continue to face issues with the build, cleaning up the workspace is recommend. If you continue to face issues with the build, cleaning up the workspace is recommend.
@@ -77,7 +77,7 @@ TCP 0.0.0.0:3000 DESKTOP LISTENING
While in development, your session is stored as cookies. Clearing them will sign you out of your development account. While in development, your session is stored as cookies. Clearing them will sign you out of your development account.
Running `npm run seed:certified-user` will log you out, too. It will overwrite the development user in your local database. Running `pnpm run seed:certified-user` will log you out, too. It will overwrite the development user in your local database.
### Issue getting 404 when navigating profile page ### Issue getting 404 when navigating profile page

55038
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -18,59 +18,44 @@
"homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme", "homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme",
"author": "freeCodeCamp <team@freecodecamp.org>", "author": "freeCodeCamp <team@freecodecamp.org>",
"main": "none", "main": "none",
"workspaces": [
"api",
"api-server",
"client",
"client/plugins/fcc-source-challenges",
"client/plugins/gatsby-remark-node-identity",
"curriculum",
"tools/challenge-editor/api",
"tools/challenge-editor/client",
"tools/challenge-helper-scripts",
"tools/challenge-parser",
"tools/scripts/build",
"tools/scripts/seed",
"tools/ui-components"
],
"scripts": { "scripts": {
"audit-challenges": "npm run create:config && ts-node tools/challenge-auditor/index.ts", "audit-challenges": "pnpm run create:config && ts-node tools/challenge-auditor/index.ts",
"analyze-bundle": "webpack-bundle-analyzer", "analyze-bundle": "webpack-bundle-analyzer",
"prebuild": "npm-run-all create:*", "prebuild": "npm-run-all create:*",
"build": "npm-run-all -p build:*", "build": "npm-run-all -p build:*",
"build-workers": "cd ./client && npm run prebuild", "build-workers": "cd ./client && pnpm run prebuild",
"build:client": "cd ./client && npm run build", "build:client": "cd ./client && pnpm run build",
"build:curriculum": "cd ./curriculum && npm run build", "build:curriculum": "cd ./curriculum && pnpm run build",
"build:server": "cd ./api-server && npm run build", "build:server": "cd ./api-server && pnpm run build",
"challenge-editor": "npm-run-all -p challenge-editor:*", "challenge-editor": "npm-run-all -p challenge-editor:*",
"challenge-editor:client": "cd ./tools/challenge-editor/client && npm start", "challenge-editor:client": "cd ./tools/challenge-editor/client && pnpm start",
"challenge-editor:server": "cd ./tools/challenge-editor/api && npm start", "challenge-editor:server": "cd ./tools/challenge-editor/api && pnpm start",
"clean": "npm-run-all -p clean:*", "clean": "npm-run-all -p clean:*",
"clean-and-develop": "npm run clean && npm ci && npm run develop", "clean-and-develop": "pnpm run clean && pnpm install && pnpm run develop",
"clean:client": "cd ./client && npm run clean", "clean:client": "cd ./client && pnpm run clean",
"clean:curriculum": "npx --yes rimraf ./config/curriculum.json", "clean:curriculum": "npx --yes rimraf ./config/curriculum.json",
"clean:packages": "npx --yes rimraf ./**/node_modules", "clean:packages": "npx --yes rimraf ./**/node_modules",
"clean:server": "npx --yes rimraf ./api-server/lib", "clean:server": "npx --yes rimraf ./api-server/lib",
"create:config": "tsc -p config && npm run ensure-env && npm run download-trending", "create:config": "tsc -p config && pnpm run ensure-env && pnpm run download-trending",
"create:utils": "tsc -p utils", "create:utils": "tsc -p utils",
"precypress": "node ./cypress-install.js", "precypress": "node ./cypress-install.js",
"cypress": "cypress", "cypress": "cypress",
"cypress:dev:run": "npm run cypress -- run --spec cypress/e2e/default/**/*.js", "cypress:dev:run": "pnpm run cypress -- run --spec cypress/e2e/default/**/*.js",
"cypress:dev:watch": "npm run cypress -- open", "cypress:dev:watch": "pnpm run cypress -- open",
"cypress:prd:run": "npm run cypress -- run --spec cypress/e2e/default/**/*.js", "cypress:prd:run": "pnpm run cypress -- run --spec cypress/e2e/default/**/*.js",
"cypress:prd:watch": "npm run cypress -- open", "cypress:prd:watch": "pnpm run cypress -- open",
"cypress:install": "cypress install && echo 'for use with ./cypress-install.js'", "cypress:install": "cypress install && echo 'for use with ./cypress-install.js'",
"cypress:install-build-tools": "sh ./cypress-install.sh", "cypress:install-build-tools": "sh ./cypress-install.sh",
"predevelop": "npm-run-all create:*", "predevelop": "npm-run-all create:*",
"develop": "npm-run-all build:curriculum -p develop:*", "develop": "npm-run-all build:curriculum -p develop:*",
"develop:client": "npm run build:curriculum && cd ./client && npm run develop", "develop:client": "pnpm run build:curriculum && cd ./client && pnpm run develop",
"develop:server": "npm run predevelop && cd ./api-server && npm run develop", "develop:server": "pnpm run predevelop && cd ./api-server && pnpm run develop",
"docs:serve": "docsify serve ./docs -o --port 3400", "docs:serve": "docsify serve ./docs -o --port 3400",
"e2e": "npm run e2e:dev:run", "e2e": "pnpm run e2e:dev:run",
"e2e:dev:run": "start-test develop ':3000/status/ping|8000' cypress:dev:run", "e2e:dev:run": "start-test develop ':3000/status/ping|8000' cypress:dev:run",
"e2e:dev:watch": "start-test develop ':3000/status/ping|8000' cypress:dev:watch", "e2e:dev:watch": "start-test develop ':3000/status/ping|8000' cypress:dev:watch",
"e2e:prd:run": "npm run build && start-test ':3000/status/ping|8000' cypress:dev:run", "e2e:prd:run": "pnpm run build && start-test ':3000/status/ping|8000' cypress:dev:run",
"e2e:prd:watch": "npm run build && start-test ':3000/status/ping|8000' cypress:dev:watch", "e2e:prd:watch": "pnpm run build && start-test ':3000/status/ping|8000' cypress:dev:watch",
"download-trending": "ts-node ./tools/scripts/build/download-trending.ts", "download-trending": "ts-node ./tools/scripts/build/download-trending.ts",
"ensure-env": "cross-env DEBUG=fcc:* ts-node ./tools/scripts/build/ensure-env.ts", "ensure-env": "cross-env DEBUG=fcc:* ts-node ./tools/scripts/build/ensure-env.ts",
"format": "run-s format:eslint format:prettier", "format": "run-s format:eslint format:prettier",
@@ -83,24 +68,24 @@
"hooks:uninstall": "node node_modules/husky/husky.js uninstall", "hooks:uninstall": "node node_modules/husky/husky.js uninstall",
"knip": "npx -y knip@^1.0.0-beta.10 --include files", "knip": "npx -y knip@^1.0.0-beta.10 --include files",
"knip:all": "npx -y knip@^1.0.0-beta.10", "knip:all": "npx -y knip@^1.0.0-beta.10",
"prelint": "npm run -w=client predevelop", "prelint": "pnpm run -F=client predevelop",
"lint": "npm-run-all create:* -p lint:*", "lint": "npm-run-all create:* -p lint:*",
"lint:challenges": "cd ./curriculum && npm run lint", "lint:challenges": "cd ./curriculum && pnpm run lint",
"lint:js": "eslint --max-warnings 0 .", "lint:js": "eslint --max-warnings 0 .",
"lint:ts": "tsc && tsc -p config && tsc -p tools/ui-components && tsc -p utils", "lint:ts": "tsc && tsc -p config && tsc -p tools/ui-components && tsc -p utils",
"lint:prettier": "prettier --list-different .", "lint:prettier": "prettier --list-different .",
"seed": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedAuthUser", "seed": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedAuthUser",
"seed:certified-user": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedAuthUser certUser", "seed:certified-user": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedAuthUser certUser",
"serve:client": "cd ./client && npm run serve", "serve:client": "cd ./client && pnpm run serve",
"serve:client-ci": "cd ./client && npm run serve-ci", "serve:client-ci": "cd ./client && pnpm run serve-ci",
"start": "npm-run-all create:* -p develop:server serve:client", "start": "npm-run-all create:* -p develop:server serve:client",
"start-ci": "npm-run-all create:* -p start:server serve:client-ci", "start-ci": "npm-run-all create:* -p start:server serve:client-ci",
"start:server": "cd ./api-server && npm start", "start:server": "cd ./api-server && pnpm start",
"storybook": "cd ./tools/ui-components && npm run storybook", "storybook": "cd ./tools/ui-components && pnpm run storybook",
"test": "run-s create:* build:curriculum build-workers test:*", "test": "run-s create:* build:curriculum build-workers test:*",
"test:source": "jest", "test:source": "jest",
"test:curriculum": "cd ./curriculum && npm test", "test:curriculum": "cd ./curriculum && pnpm test",
"test-curriculum-full-output": "cd ./curriculum && npm run test:full-output", "test-curriculum-full-output": "cd ./curriculum && pnpm run test:full-output",
"test-client": "jest client", "test-client": "jest client",
"test-config": "jest config", "test-config": "jest config",
"test-curriculum-js": "jest curriculum", "test-curriculum-js": "jest curriculum",
@@ -125,36 +110,10 @@
"@testing-library/dom": "8.20.0", "@testing-library/dom": "8.20.0",
"@testing-library/jest-dom": "5.16.5", "@testing-library/jest-dom": "5.16.5",
"@testing-library/user-event": "13.5.0", "@testing-library/user-event": "13.5.0",
"@types/chai": "4.3.4",
"@types/enzyme": "3.10.12",
"@types/enzyme-adapter-react-16": "1.0.6",
"@types/eslint": "7.29.0",
"@types/estree": "0.0.52",
"@types/inquirer": "8.2.6",
"@types/jest": "27.5.2", "@types/jest": "27.5.2",
"@types/jquery": "3.5.16", "@types/lodash": "4.14.191",
"@types/loadable__component": "5.13.4",
"@types/lodash-es": "4.17.6",
"@types/node": "18.14.2", "@types/node": "18.14.2",
"@types/prismjs": "1.26.0",
"@types/reach__router": "1.3.11",
"@types/react": "17.0.53",
"@types/react-dom": "17.0.19",
"@types/react-helmet": "6.1.6",
"@types/react-instantsearch-core": "6.26.3",
"@types/react-instantsearch-dom": "6.12.3",
"@types/react-monaco-editor": "0.16.0",
"@types/react-redux": "7.1.25",
"@types/react-responsive": "8.0.5",
"@types/react-spinkit": "3.0.7",
"@types/react-test-renderer": "17.0.2",
"@types/react-transition-group": "4.4.5",
"@types/redux-actions": "2.6.2",
"@types/sanitize-html": "2.8.0",
"@types/store": "2.0.2", "@types/store": "2.0.2",
"@types/validator": "13.7.12",
"@typescript-eslint/eslint-plugin": "5.53.0",
"@typescript-eslint/parser": "5.53.0",
"babel-eslint": "10.1.0", "babel-eslint": "10.1.0",
"babel-plugin-transform-imports": "2.0.0", "babel-plugin-transform-imports": "2.0.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
@@ -187,6 +146,7 @@
"process": "0.11.10", "process": "0.11.10",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"start-server-and-test": "1.15.5", "start-server-and-test": "1.15.5",
"store": "2.0.12",
"ts-node": "10.9.1", "ts-node": "10.9.1",
"typescript": "4.9.5", "typescript": "4.9.5",
"webpack-bundle-analyzer": "4.8.0" "webpack-bundle-analyzer": "4.8.0"

30002
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

15
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,15 @@
packages:
- 'api'
- 'api-server'
- 'client'
- 'client/plugins/fcc-source-challenges'
- 'client/plugins/gatsby-remark-node-identity'
- 'curriculum'
- 'tools/challenge-editor/api'
- 'tools/challenge-editor/client'
- 'tools/challenge-helper-scripts'
- 'tools/challenge-parser'
- 'tools/crowdin'
- 'tools/scripts/build'
- 'tools/scripts/seed'
- 'tools/ui-components'

View File

@@ -10,9 +10,22 @@ config({ path: envPath });
import { availableLangs } from '../../config/i18n'; import { availableLangs } from '../../config/i18n';
import { getChallengesForLang } from '../../curriculum/getChallenges'; import { getChallengesForLang } from '../../curriculum/getChallenges';
import { SuperBlocks } from '../../config/certification-settings'; import { SuperBlocks } from '../../config/certification-settings';
import { ChallengeNode } from '../../client/src/redux/prop-types';
import { getAuditedSuperBlocks } from '../../config/superblock-order'; import { getAuditedSuperBlocks } from '../../config/superblock-order';
// TODO: re-organise the types to a common 'types' folder that can be shared
// between the workspaces so we don't have to declare ChallengeNode here and in
// the client.
// This cannot be imported from the client, without causing tsc to attempt to
// compile the client (something it cannot do)
type ChallengeNode = {
block: string;
dashedName: string;
superBlock: SuperBlocks;
id: string;
challengeType: number;
};
const superBlockFolderMap = { const superBlockFolderMap = {
'responsive-web-design': '01-responsive-web-design', 'responsive-web-design': '01-responsive-web-design',
'javascript-algorithms-and-data-structures': 'javascript-algorithms-and-data-structures':
@@ -53,7 +66,7 @@ const getChallenges = async (lang: string) => {
key => superBlock[key].challenges key => superBlock[key].challenges
); );
return [...challengeArray, ...flatten(challengesForBlock)]; return [...challengeArray, ...flatten(challengesForBlock)];
}, []) as unknown as ChallengeNode['challenge'][]; }, []) as unknown as ChallengeNode[];
}; };
/* eslint-enable @typescript-eslint/no-unsafe-return */ /* eslint-enable @typescript-eslint/no-unsafe-return */

View File

@@ -16,6 +16,7 @@
"ts-node": "10.9.1" "ts-node": "10.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.13",
"@types/express": "4.17.17", "@types/express": "4.17.17",
"dotenv": "16.0.3", "dotenv": "16.0.3",
"shx": "0.3.4", "shx": "0.3.4",

View File

@@ -9,19 +9,19 @@ const asyncExec = promisify(exec);
const toolsSwitch: ToolsSwitch = { const toolsSwitch: ToolsSwitch = {
'create-next-step': directory => { 'create-next-step': directory => {
return asyncExec(`cd ${directory} && npm run create-next-step`); return asyncExec(`cd ${directory} && pnpm run create-next-step`);
}, },
'create-empty-steps': (directory, num) => { 'create-empty-steps': (directory, num) => {
return asyncExec(`cd ${directory} && npm run create-empty-steps ${num}`); return asyncExec(`cd ${directory} && pnpm run create-empty-steps ${num}`);
}, },
'insert-step': (directory, num) => { 'insert-step': (directory, num) => {
return asyncExec(`cd ${directory} && npm run insert-step ${num}`); return asyncExec(`cd ${directory} && pnpm run insert-step ${num}`);
}, },
'delete-step': (directory, num) => { 'delete-step': (directory, num) => {
return asyncExec(`cd ${directory} && npm run delete-step ${num}`); return asyncExec(`cd ${directory} && pnpm run delete-step ${num}`);
}, },
'update-step-titles': directory => { 'update-step-titles': directory => {
return asyncExec(`cd ${directory} && npm run update-step-titles`); return asyncExec(`cd ${directory} && pnpm run update-step-titles`);
} }
}; };

View File

@@ -6,6 +6,7 @@
"@testing-library/jest-dom": "5.16.5", "@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "12.1.5", "@testing-library/react": "12.1.5",
"@testing-library/user-event": "13.5.0", "@testing-library/user-event": "13.5.0",
"codemirror": "5",
"react": "16.14.0", "react": "16.14.0",
"react-codemirror2": "7.2.1", "react-codemirror2": "7.2.1",
"react-dom": "16.14.0", "react-dom": "16.14.0",
@@ -33,8 +34,16 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"devDependencies": { "devDependencies": {
"@types/codemirror": "5.60.7", "@types/codemirror": "5.60.7",
"@types/react": "16.14.0",
"@types/react-dom": "^16.9.17",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-react-hooks": "4.6.0",
"shx": "0.3.4" "shx": "0.3.4"

View File

@@ -54,7 +54,7 @@ const SuperBlock = () => {
<p> <p>
Want to create a new project? Open your terminal, point to the{' '} Want to create a new project? Open your terminal, point to the{' '}
<code>tools/challenge-helper-scripts</code> directory, and run{' '} <code>tools/challenge-helper-scripts</code> directory, and run{' '}
<code>npm run create-project</code> <code>pnpm run create-project</code>
</p> </p>
</div> </div>
); );

View File

@@ -262,6 +262,6 @@ void prompt([
) )
.then(() => .then(() =>
console.log( console.log(
'All set. Now use npm run clean:client in the root and it should be good to go.' 'All set. Now use pnpm run clean:client in the root and it should be good to go.'
) )
); );

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -23,9 +23,12 @@
"create-project": "ts-node create-project" "create-project": "ts-node create-project"
}, },
"devDependencies": { "devDependencies": {
"@types/glob": "^8.0.1",
"@types/inquirer": "^8.2.5",
"@types/mock-fs": "4.13.1", "@types/mock-fs": "4.13.1",
"bson-objectid": "2.0.4", "bson-objectid": "2.0.4",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"glob": "^8.1.0",
"gray-matter": "4.0.3", "gray-matter": "4.0.3",
"inquirer": "8.2.5", "inquirer": "8.2.5",
"prettier": "2.8.4", "prettier": "2.8.4",

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -2,6 +2,7 @@ import path from 'path';
import fs from 'fs'; import fs from 'fs';
import readdirp from 'readdirp'; import readdirp from 'readdirp';
// TODO: remove chai and use jest's assertion errors
import { AssertionError } from 'chai'; import { AssertionError } from 'chai';
import envData from '../../../config/env.json'; import envData from '../../../config/env.json';
import { SuperBlocks } from '../../../config/certification-settings'; import { SuperBlocks } from '../../../config/certification-settings';

View File

@@ -131,7 +131,7 @@ if (FREECODECAMP_NODE_ENV !== 'development') {
) { ) {
/* eslint-enable @typescript-eslint/no-unsafe-member-access */ /* eslint-enable @typescript-eslint/no-unsafe-member-access */
console.log('Feature flags have been changed, cleaning client cache.'); console.log('Feature flags have been changed, cleaning client cache.');
const child = spawn('npm', ['run', 'clean:client']); const child = spawn('pnpm', ['run', 'clean:client']);
child.stdout.setEncoding('utf8'); child.stdout.setEncoding('utf8');
child.stdout.on('data', function (data) { child.stdout.on('data', function (data) {
console.log(data); console.log(data);

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -20,9 +20,13 @@
"main": "none", "main": "none",
"devDependencies": { "devDependencies": {
"@types/js-yaml": "4.0.5", "@types/js-yaml": "4.0.5",
"@types/node-fetch": "2.6.2",
"chai": "4.3.7",
"debug": "4.3.4", "debug": "4.3.4",
"dotenv": "16.0.3", "dotenv": "16.0.3",
"joi": "17.7.0",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"node-fetch": "2.6.9",
"readdirp": "3.6.0" "readdirp": "3.6.0"
} }
} }

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -8,7 +8,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -43,6 +43,9 @@
"@testing-library/jest-dom": "5.16.5", "@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "12.1.5", "@testing-library/react": "12.1.5",
"@types/jest": "27.5.2", "@types/jest": "27.5.2",
"@types/react": "16.14.35",
"@types/react-dom": "^16.9.17",
"@types/testing-library__jest-dom": "^5",
"autoprefixer": "10.4.13", "autoprefixer": "10.4.13",
"babel-loader": "8.3.0", "babel-loader": "8.3.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.24", "babel-plugin-transform-react-remove-prop-types": "0.4.24",
@@ -57,7 +60,7 @@
}, },
"scripts": { "scripts": {
"storybook": "start-storybook -p 6006", "storybook": "start-storybook -p 6006",
"storybook:theming": "npm run storybook --no-manager-cache", "storybook:theming": "pnpm run storybook --no-manager-cache",
"build-storybook": "build-storybook", "build-storybook": "build-storybook",
"build": "cross-env NODE_ENV=production rollup -c", "build": "cross-env NODE_ENV=production rollup -c",
"build:css": "npx tailwindcss -i ./src/base.css -o ./dist/base.css --minify", "build:css": "npx tailwindcss -i ./src/base.css -o ./dist/base.css --minify",

View File

@@ -8,8 +8,7 @@
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "node", "moduleResolution": "node",
"strict": true, "strict": true,
"noEmit": true, "noEmit": true
"typeRoots": ["../../node_modules/@types"]
}, },
"ts-node": { "ts-node": {
"compilerOptions": { "compilerOptions": {

View File

@@ -14,7 +14,7 @@
"noEmit": true, "noEmit": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"types": ["node", "jest", "@testing-library/jest-dom", "cypress"] "types": ["node", "jest", "cypress"]
}, },
// since ts-node compiles ts on the fly and then uses node, it needs to // since ts-node compiles ts on the fly and then uses node, it needs to
// compile the scripts to commonjs (or node will complain about the requires) // compile the scripts to commonjs (or node will complain about the requires)

View File

@@ -1,9 +1,5 @@
{ {
"include": [ "include": [
"client/i18n/**/*",
"client/plugins/**/*",
"client/src/**/*",
"client/utils/**/*",
"curriculum/*.test.ts", "curriculum/*.test.ts",
"tools/challenge-auditor/index.ts", "tools/challenge-auditor/index.ts",
"tools/challenge-editor/**/*", "tools/challenge-editor/**/*",

View File

@@ -11,7 +11,7 @@ cd ../curriculum-server
npm i npm i
cd ../web cd ../web
npm i npm i
npm run dev pnpm run dev
``` ```
Now the server should be running on port 3000 and the client on port 8000. Now the server should be running on port 3000 and the client on port 8000.

View File

@@ -6,7 +6,7 @@
"private": true, "private": true,
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"npm": ">=8" "pnpm": "7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",