bitrock-design-system v0.1.0
Bitrock Design System (TDS)
Introduction
This repository showcases using a monorepo to house a design system and the various packages one could contain. It is built for React and uses a number of different tools to create and maintain packages:
- ๐ Turborepo โ High-performance build system for monorepos
- ๐ท Vite โ ES Module focused build tool and bundler
- ๐งช Cypress โ Browser based test runner
- ๐ Storybook โ UI component environment powered by Vite
- ๐ Syncpack โ Ensures consistent dependencies within monorepos
- ๐ Commitlint โ Checks commits follow conventional commits format
- ๐ Changesets โ Managing versioning, publishing and changelogs
- ๐ GitHub Actions โ Running workflows in continuous integration
Turborepo
Turborepo is a high-performance build system for JavaScript and TypeScript codebases. It was designed after the workflows used by massive software engineering organizations to ship code at scale. Turborepo abstracts the complex configuration needed for monorepos and provides fast, incremental builds with zero-configuration remote caching.
Using Turborepo simplifes managing your design system monorepo, as you can have a single lint, build, test, and release process for all packages. Learn more about how monorepos improve your development workflow.
Main Features & Benefits
Highlights of benefits from using this monorepo are:
- Turborepo caching so commands don't re-run unless changed detected.
- Internal packages to house common configuration for tools like ESLint, Prettier, TypeScript.
- Ensures consistent package versioning via syncpack.
- Type-checking method within each package that turborepo can cache.
- Shared Storybook (
apps/docs
) across all React related packages.
How Do Workspaces Work?
Each application and package added to the monorepo will operate within its own workspace (specified within the top-level package file). Workspaces maintain their own package files but the entire monorepo has a single top-level lock file. All of a projects dependencies are installed together at the top-level which gives Yarn the ability to de-dupe and optimize them.
Each workspace has a symlink created for it within the top-level node_modules
folder which is what allows packages to depend on each other and have up to date code without requiring publishing. This is a better mechanism than yarn link
because it only affects the current project tree and not the whole file systems module system.
When importing from other workspaces, you can import the built version of the workspace by importing from its root where your tooling might pick the package files main
, module
or exports
fields. Alternatively you could also directly import the workspaces source files. For example, the <Button />
story imports the components source file from @acme/core/src
.
Useful Commands
yarn build
- Build all applications and packagesyarn clean
- Clean all.turbo
,node_modules
anddist
foldersyarn lint
- Lint all relevant packagesyarn lint:packages
- Validate package dependencies are in syncyarn test
- Test all relevant packagesyarn types:check
- Type-check all relevant packages
Applications & Packages
This Turborepo includes the following packages and applications:
apps/docs
: Component documentation site with Storybookpackages/config-eslint
: Internal package for ESLint shared configurationpackages/config-pretter
: Internal package for Prettier shared configurationpackages/config-tsconfig
: Internal package for TypeScript shared configurationpackages/ds-core
: core components of MUI wrapped from us (including provider Wrapper and useTheme)(simple component, button, typography, etc)packages/ds-themes
: Only theme objectpackages/ds-components
: Complex component composed by ds-core components (es widget, wizards, submenu)packages/utils
: only generalized services for the different MFE
Each application and package is a TypeScript project. Yarn Workspaces enables us to "hoist" dependencies that are shared between packages to the root package file. This means smaller node_modules
folders and a better local dev experience. They also have common commands such as build
, clean
, lint
and test
where appropriate.
Compilation
To make the core library code work across all browsers, we need to compile the raw TypeScript and React code to plain JavaScript. We can accomplish this with vite
, which uses esbuild
to greatly improve performance. Running yarn build
from the root of the Turborepo will run the build
command defined in each package file. Turborepo runs each build
in parallel and caches & hashes the output to speed up future builds.
Testing
Relevant monorepo packages use Cypress for browser based component testing. The yarn test
command will run these commands in parallel, caching and hashing the output to speed up future runs. When this command is run locally there are no further considerations, however, in CI the turbo command will try to run these in parallel. Each process will try to insantiate xvfb
which causes issues. The CI script instantiates this before running the turbo command.
Storybook
Storybook provides us with an interactive UI playground for our components. This allows us to preview our components in the browser and instantly see changes when developing locally. This example preconfigures Storybook to:
- Use Vite to bundle stories instantly (in milliseconds)
- Automatically find any stories inside the
stories/
folder - Support using module path aliases like
@bitrock/ds-core
for imports - Write MDX for component documentation pages
Versioning & Publishing Packages
yarn changeset
- Generate a changeset fileyarn version-packages
- Update versions, changelogs and dependencies of packages.yarn release
- Publishes changes to package registry and creates git tags.
The monorepo uses Changesets to manage versions, create changelogs, and publish to the package registry. You'll need to create an NPM_TOKEN
and GITHUB_TOKEN
and add it to your GitHub repository settings to enable access to the package registry.
Generating the Changelog
To generate your changelog, run yarn changeset
locally:
- Which packages would you like to include? โ This shows which packages and changed and which have remained the same. By default, no packages are included. Press
space
to select the packages you want to include in thechangeset
. - Which packages should have a major bump? โ Press
space
to select the packages you want to bump versions for. - If doing the first major version, confirm you want to release.
- Write a summary for the changes.
- Confirm the changeset looks as expected.
- A new Markdown file will be created in the
changeset
folder with the summary and a list of the packages included.
These changeset files should be part of your PR and committed into the trunk branch, ready for future release.
Releasing
When you merge your PR into the trunk branch, the GitHub Action will create a PR with all of the package versions updated and changelogs updated. If more PRs get merged with more changesets then the PR opened by the GitHub Action will be updated.
Merging this PR will, along with updating all of the files it changed, make the GitHub Action trigger it's release cycle where it attempts to publish each package not marked as private
within the workspaces package file.
Further Information
- Understanding Monorepos
- Node.js - Loading from
node_module
folders - Yarn Workspaces
- Turborepo - Workspaces
- Turborepo - Design System Example
- Changesets - CLI
#TODO:
- cambiare con suffisso lux (eg: )
1 year ago