Shared frontend design system for Codecademy! ✨
The component library & design system for Codecademy. ✨
This repository is a monorepo that we manage using Lerna. That means that we publish several packages to npm from the same codebase, including:
We provide a single package to manage the versions of a few core dependencies: gamut
, gamut-icons
, gamut-illustrations
, gamut-patterns
, gamut-styles
. Since these packages are highly intertwined we suggest only installing @codecademy/gamut-kit
when your app needs all of these.
yarn add @codecademy/gamut-kit
{
"peerDependencies": {
"@codecademy/gamut": "*",
"@codecademy/gamut-icons": "*",
"@codecademy/gamut-patterns": "*",
"@codecademy/gamut-illustrations": "*",
"@codecademy/gamut-styles": "*",
"@codecademy/gamut-tests": "*",
"@codecademy/variance": "*"
}
}
gamut
: Our React UI component library
gamut-styles
: Utility styles for Gamut components and codecademy apps
gamut-icons
: SVG Icons for Gamut components and codecademy apps
variance
: TypeScript CSS in JS utility library
styleguide
: Styleguide Documentation & storybook development sandbox
yarn
in the root directoryyarn build
to build all of the packages (certain packages like gamut-icons
need to be built to function in storybook).yarn start
to start the storybook serverpackages/styleguide/stories
Ship It
label to your Pull Request.package.json
on the main
branchEvery PR that changes files in a package publishes alpha releases that you can use to test your changes across applications.
NOTE: in case an alpha build is not published upon opening of the PR or Draft PR, re-run the
build-test
check and that will re-run the alpha build publishing flows
codecademydev
bot should comment on your PR with the names of the published alpha packages. NOTE: Due to the inconsistencies of symlinks in a lerna repo, instead of using
yarn link
, we recommend using thenpm-link-better
package with the--copy
flag to copy packages into your local repo'snode_modules
directory.
Initial Setup:
npm install -g npm-link-better
gamut
repo since you last synced: yarn build
Instructions:
For each of your local gamut
packages (e.g. gamut
), you'll need to do 2 things to get it working in your project:
Make sure your package changes have been built into the gamut/packages/[package]/dist
folder.
yarn build
yarn build:watch
(not all packages support this yet)Copy that built /dist
folder to your project's node_modules/@codecademy/[package]
folder.
cd myProjectRepo
npm-link-better --copy --watch path/to/gamut/packages/[package]
NOTE: The
--watch
flag will automatically copy your package intonode_modules
everytime it is built.
Let's say we are making changes to the gamut
package, and our app that uses the gamut
package uses yarn start
to build, serve, and watch our app for changes.
Let's also assume these two repos are sibling directories inside of a folder called repos
repos
|- gamut
|- my-app
We would run the following commands in 3 separate shells
# Shell 1: Auto-build Gamut changes
cd repos/gamut/packages/gamut
yarn build:watch
# Shell 2: Auto-copy built Gamut changes to my-app.
cd repos/my-app
npm-link-better --copy --watch ../gamut/packages/gamut
# Shell 3: Auto-update app when anything changes.
cd repos/my-app
yarn start
This would allow us to make a change in our gamut
package, and see that change automatically reflected in our local app in the browser.
If you see compilation issues in your project's dev server after running npm-link-better
, you may have to restart your app's dev server.
If you are seeing compilation issues in a gamut
package, you may need to rebuild the whole repository via
yarn build
For quicker development cycles, it's possible to run a pre-published version of Gamut in another project. We do that using symlinks (the following instructions assume you have set up and built Gamut):
cd /path/to/gamut/packages/gamut
yarn link
cd path/to/other/repo
yarn link @codecademy/gamut
yarn install
If your other project uses React, you must link that copy of React in Gamut:
cd path/to/other/repo
cd node_modules/react
yarn link
cd /path/to/gamut/packages/gamut
yarn link react
yarn build
See the docs for more information for why you have to do this.
packages/<package-name>/package.json
.yarn lerna create
to create the new package, copying values from existing package.json
s when unsure.
publishConfig
field to let your published package be public by defaulttsconfig.json
with a index.ts
exporting a single objectyarn lerna bootstrap
from the repository rootfeat
PR adding that packageyarn lerna bootstrap
after they merge from main
Notes:
If your package will be used in other packages in the monorepo, you may need to set up aliases in jest and storybook so that they can be run without building your package first. You can find these aliases in jest.config.js and the styleguide storybook config.
NX
This monorepo uses NX to cache previous builds locally and in CI.
The config for NX is located at /nx.json, along with project.json
files for each package.
For new packages, please use an NX generator plugin to create your initial package, this will ensure that all of the configuration for linting & testing is set up correctly.
Your PR Title should follow the Conventional Commits Format.
Because we automatically squash merge Pull Requests, you'll need to format your PR title to match these guidelines since the title will become the commit message.
Your individual commits will affect the alpha
version number, but not the final version once you merge to main.
This Title format will be linted in the conventional-pr-title
status check and prevent merging if you do not follow the correct format.
When you click squash and merge, the title should follow this format:
type(scope): message
Examples:
fix: fixes a bug in some component
test: adds test to component
With a scope:
feat(Button): :sparkles: An awesome feature for the Button component
Breaking change:
feat(Button)!: :fire: Deleted the Button component
Check out the Conventional Commits page for more detailed options
Type
The type
determines what kind of version bump is needed. A fix
will create a patch
release, while a feat
will create a minor
release. Major version updates require a special syntax that is described below.
type
must be one of the following options:
Standard types:
Scope
A scope is optional and consists of a noun describing a section of the codebase surrounded by parenthesis, e.g., feat(Button):
Breaking Changes
Adding an exclamation point after your type, before the colon, will indicate that your PR contains a breaking change, and increment the major version number of the modules you changed.
Examples:
feat!: made a breaking change in the Button component
feat(Button)!: made a breaking change in the Button component
You should do this if your changes introduce any incompatibilities with previous versions of the module. This will indicate to package consumers that they need to refactor their usage of the module to upgrade.
Because Gamut is a separate repository from its consumers, it can be tricky to coordinate technically breaking changes. If your changes will require changes in any downstream repositories:
This process minimizes the likelihood of accidental breaking changes in Gamut negatively affecting development on our other repositories.
Body
Optional extra description for your changes.
This goes in the description for your PR, between the <!--- CHANGELOG-DESCRIPTION -->
comment tags in the PR template.
If you include the text BREAKING CHANGE:
in your description it will trigger a major version bump. We prefer to use the feat!:
syntax for breaking changes described above.
Storybook is built and published automatically when there are merges into the main branch.