Skip to content

Commit

Permalink
New section docs and script fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
macieklad committed Oct 23, 2024
1 parent 53b7e7e commit 9d1050b
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 52 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/changesets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ jobs:
with:
node-version: 22.10.0

- name: Create Release Pull Request
- name: Tag or publish packages
id: changesets
uses: changesets/action@v1
with:
publish: pnpm release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7 changes: 5 additions & 2 deletions .github/workflows/check-packages.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
name: Ensure package structure and dependencies are correct

on:
pull_request:
types: [opened, reopened, edited]
workflow_dispatch:
push:
branches:
- '*'
- '!master'

concurrency: ${{ github.workflow }}-${{ github.ref }}

Expand Down
64 changes: 48 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1 align="center">Monoplate</h1>
</p>

Go from cloning to coding in minutes. Monoplate is an opinionated template for starting a javascript monorepo. Aimed at supporting application development, it comes preconfigured with an ecosystem of tools and best practices to get you started quickly.
Monoplate is an opinionated template for starting a javascript monorepo. Aimed at parallel application development, it comes preconfigured with an ecosystem of tools for quick addition and maintenance of new apps and libraries.

**Powered by:**

Expand All @@ -27,8 +27,8 @@ Go from cloning to coding in minutes. Monoplate is an opinionated template for s

- 🧰 Presets for ESLint, Prettier, and Lint Staged
- ∫∫ Integration packages for vite, tailwindcss and react
- 🧑‍🏭 GitHub actions for testing, releasing, and deploying your projects, with goodies like caching and environment setup
- ⛩️ Package and application templates for starting your next docs, component library, API, or web application.
- 🧑‍🏭 GitHub actions for testing, releasing, and deploying your projects, with caching and environment setup
- ⛩️ Minimal package and application templates for starting your next docs, component library, API, or web application.
- 🎒 Extensive syncpack configuration for keeping your dependencies in check

### First steps
Expand All @@ -47,6 +47,8 @@ cd monoplate
pnpm install
```

❗ Now if you use your own organisation name, replace every occurrence of `@acme` in the repository with your own `@name`.

If you want to run any application, make sure every dependency is built first:

```bash
Expand All @@ -62,41 +64,43 @@ pnpm --filter remix dev
You can run whole monorepo in dev mode with `pnpm dev` command. It will start the `dev` script in every repository, but this is rarely what you want. You most likely want to run a single app dev script together with its dependencies:

```bash
p dev --filter remix...
pnpm dev --filter remix...
```

The `...` syntax is taken directly from [turborepo configuration](https://turbo.build/repo/docs/core-concepts/monorepos/filtering#include-dependents-of-matched-workspaces)

🙋 Using monorepos is hard. To develop projects using monoplate you will soon have to understand how to use the tools in the repo. See the [documentation](#documentation) when you are ready.
Package release is done automatically through the `release` script. Make sure that after you clone this repository, you will set up your npm/github packages/jsr connection in the repository. We pass `GITHUB_TOKEN` to the changeset action by default, so if you set write access for it, it will publish to GitHub packages.

🙋 Using monorepos is hard. To develop projects using Monoplate you will soon have to understand how to use the tools in the repo. You can start with great resources like the [monorepo tools](https://monorepo.tools/) first. The read [Monoplate documentation](#documentation) when you are ready.

## Philosophy

[Monorepos](https://monorepo.tools/) allow for simplified cross-project refactoring, unified versioning, and cohesive tooling strategies.
[Monorepos](https://monorepo.tools/) enable simplified cross-project refactoring, unified versioning, and cohesive tooling strategies.

You may decide to use them for different purposes - the use cases change mostly when you are a single developer, a team, or a company. For example:

- You may want to publish a package and have some applications that use it in a single place
- You develop a lot of co-dependent projects, and it is a hassle to manage them separately
- Your teams grow, and you want to enforce a unified tooling and standards across all projects

Monorepo tooling has come a long way, and it is now easier than ever to set up a monorepo. Not long ago, you had to jump into lerna and hope that everything builds nicely, that your dependencies won't collide, and that your node_modules mess won't explode. Did I mention versioning, robust testing and linting? Without good caching, you could be waiting for your CI to finish for hours.
Monorepo tooling has come a long way, and it is now easier than ever to set up a monorepo. Not long ago, you had to jump into lerna and hope that everything builds nicely, that your dependencies won't collide, and that your node_modules mess won't explode. Did I mention versioning, testing and linting? Without good caching, you could be waiting for your CI to finish for hours.

Now we have turborepo, pnpm, changesets, and a lot of other tools that make monorepos a breeze. Still, after the initial setup, there is a lot of configuration to do:
Now we have Turborepo, pnpm, changesets, and a lot of other tools that make monorepos a lot better. Still, after the initial setup, there is a lot of configuration to do:

- How do you lint your code? ESLint? Which of a few hundred rules and plugins do you use? What about TypeScript linting? A simple app is taking 30 seconds to lint? Good luck!
- Formatting and code style? Prettier? How to run it before committing? What about the configuration? Oh, a global config? I hope you won't run it on node_modules!
- Building your app? Vite? Webpack? Rollup? What about the configuration? How do you run it in production? What about the environment variables? External modules? Peer dependencies? I hope your clients use evergreen browsers!
- Building your app? Vite? Webpack? Rollup? What about the configuration? What config do you use in production? What about the environment variables? External modules? Peer dependencies? Browser support?
- Dependency management? Three version of React in your apps? You just bundled one with your package? Too bad.

If you have an expert to configure all of this, you are golden. If you are a team of one, you are in for a ride. And how to teach that to new developers?

We have created monoplate to be the next layer in the puzzle, the kind of you see more and more like `shadcn/ui`. You can clone this repo and have a working setup, with common configuration packaged away so the only thing you need to do is to write your own, business code. From the moment you clone it, the code is yours, and we provide a lot of docs and examples to help you along the way. This is crucial as monorepos by nature are heavily dependent on your own tools and practices.
We have created Monoplate to be a point of reference. You can clone this repo and have a working setup, with common configuration packaged away so that the only thing you need to do is to write your own, business code. From the moment you clone it, the code is yours, and we provide docs and examples to help you along the way. This is crucial as monorepos by nature are heavily dependent on your own tools and practices.

We also try to learn as much as you do, and look for best ways to solve monorepo issues, to provide modern configuration and build optimised apps. We are open to suggestions and PRs, and we hope that monoplate will be a good starting point for your next project.
We also try to learn as much as you do, and look for best ways to solve monorepo issues, to provide modern configuration and build optimised apps. We are open to suggestions and PRs, and we hope that Monoplate will be a good starting point for your next project.

## Documentation

This section strives to guide you through everything available in the monoplate. We will overview most things here, but deeper knowledge is hidden in the individual package documentation. If you want to understand how everything comes together from the ground up, get familiar with the tools mentioned in the README introduction `Powered by` list, and then go through the repository packages and files in the following order:
This section strives to guide you through concepts available in Monoplate. We will overview most things here, but deeper knowledge is hidden in the individual package documentation. If you want to understand how everything comes together from the ground up, get yourself familiar with the tools mentioned in the README introduction `Powered by` list, and then go through the repository packages and files in the following order:

- root [`package.json`](./package.json)
- [`pnpm-workspace.yaml`](./pnpm-workspace.yaml)
Expand All @@ -108,10 +112,37 @@ This section strives to guide you through everything available in the monoplate.
- [`@acme/react-package-template`](./packages/react-package-template/README.md)
- [`@acme/components`](./packages/components/README.md)
- `@acme/any_app`
-

### Project management

Packages (directories with `package.json`) form the base of any javascript monorepo. We use pnpm to manage their dependencies and define how to locate them. In `pnpm-workspace.yaml` you can find which directories will be scanned for the `package.json` files and registered as **workspaces**, places where you can run scripts and install dependencies which will be centrally tracked. Pnpm does not care about relations between packages, so you can't say "build this package before that one". This is where Turbo comes in. In `turbo.json` you can define global tasks that will run a command of the same name in each of your workspaces. You define how they relate to each other, what outputs they produce, and how to cache them. Turbo will take care of the rest and make running loads of scripts a lot faster (if outputs don't change, cache will be used, making running scripts super fast even when you have tens or hundreds of packages). From this moment onward, you invoke turbo through pnpm scripts, and use it by default.

Pnpm installs dependencies of all packages in a single place - root directory `node_modules`, and symlinks them to the packages. This is a huge advantage over npm and yarn, as it saves disk space and speeds up the installation process. If two packages use the same dependency and its version, it will be installed only once. You can install the same dependency in two different versions, and they will be both installed. Pnpm will isolate those packages, but from time to time, especially because of the inherent nature of javascript and global scope, you may encounter issues, for example when you will bundle two dependency versions in your final code because of the way they are imported. Also, from the organisation perspective, you probably want everyone to use the same, up-to-date version of the dependency.

Pnpm and turbo don't concern themselves with this issue. This is where syncpack comes in. Syncpack is a tool that you provide with a versioning strategy for your packages, and it will ensure that everyone follows it. In Monoplate, we use a simple strategy - the newest version of dependency wins, and syncpack will bump all packages to the newest version of the dependency. This isn't always feasible, so we provide a big `syncpack.config` for you, where we fix some common versioning issues with javascript ecosystem.

❓You may ask, why not a single tool that does everything? You can! Try `nx` if you want to go with this solution. What we like about our setup is that packages are totally independent. You can pull a folder out of this monorepo, replace `workspace:*` dependencies in `package.json` with precise semver versions, run pnpm install, and everything will work as if the monorepo never existed - besides CI of course.

### Defining dependencies between packages

Turbo operates on tasks, but you configure your package dependencies as you would install any normal package from npm. If you want to depend on a project in the repository, you use its `name` field in the `package.json` and version it with `workspace:*`. You can also use a specific version, but it will be sourced directly from your registry, not from the monorepo code itself. Publishing to registry is set up with `release` command in the `package.json`.

### Scripts glossary

### Code quality

### Build toolchain and best practices

### CI/CD

### Component library

### Default applications

## Thanks

Huge shutout to [@miikebar](https://github.com/miikebar) for his work on this project. Without his ideas and contributions to the project architecture, vite presets and linters, we would not have created it.
Huge shutout to [@miikebar](https://github.com/miikebar) for his work on this project. Without his ideas and contributions, vite presets and linters, we would not have created it.

## TODO

Expand Down Expand Up @@ -156,20 +187,21 @@ Huge shutout to [@miikebar](https://github.com/miikebar) for his work on this pr
- [ ] CI/CD Pipeline
- [x] Testing
- [x] Linting
- [x] Caching
- [x] Cachingcccc
- [x] Versioning
- [ ] Docs
- [ ] Documentation
- [x] Included tool links
- [ ] Configuration after cloning
- [x] Configuration after cloning
- [x] Renaming example `acme` names
- [ ] Getting started
- [x] Getting started
- [ ] Explanation for each used tool with best practices
- [ ] Hoisting configuration and why it matters to build packages (workspace:\* dependency resolving and externalisation)
- [x] Thanks

V2 Ideas

- [ ] Dependency graph
- [ ] E2E test setup
- [ ] Startup tests for each template
- [ ] Module federation
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"format": "prettier --write \"**/*.{ts,tsx,md,mdx}\"",
"lint": "turbo run lint --cache-dir=.turbo",
"prepare": "is-ci || husky install",
"release": "turbo run build --filter='./packages/*' && changeset publish",
"release": "pnpm build:ecosystem && changeset publish",
"sync": "syncpack fix-mismatches",
"test": "turbo run test --cache-dir=.turbo",
"test": "turbo run test",
"version-packages": "changeset version"
},
"devDependencies": {
Expand All @@ -29,7 +29,7 @@
"lint-staged": "^15.2.10",
"prettier": "~3.3.3",
"syncpack": "^12.4.0",
"turbo": "^2.2.1"
"turbo": "^2.2.3"
},
"packageManager": "[email protected]"
}
61 changes: 31 additions & 30 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9d1050b

Please sign in to comment.