|
| 1 | +# sample-monorepo |
| 2 | + |
| 3 | +[](https://github.com/wixplosives/sample-monorepo/actions) [](https://lerna.js.org) |
| 4 | + |
| 5 | +Sample monorepo setup with yarn workspaces, typescript, and lerna. |
| 6 | + |
| 7 | +## Setup explained |
| 8 | + |
| 9 | +### Tooling |
| 10 | + |
| 11 | +- Monorepo is installed using [yarn](https://github.com/yarnpkg/yarn). |
| 12 | + |
| 13 | + - Packages are automatically linked together, meaning you can do cross-package work within the repo. |
| 14 | + - `devDependencies` are common, and only appear in the root `package.json`. Easier to manage and upgrade. |
| 15 | + - Each package has its own `scripts` and `dependencies`. They are being installed in the root `node_modules`, using the same deduping mechanism `yarn` uses for single packages. |
| 16 | + - Adding new packages is as simple as dropping an existing package in the `packages` folder, and re-running `yarn`. |
| 17 | + |
| 18 | +- Monorepo scripts are being executed using [lerna](https://github.com/lerna/lerna). |
| 19 | + |
| 20 | + - `lerna publish` - multi-package publishing. |
| 21 | + - `lerna run` - running package scripts. |
| 22 | + - `lerna updated` - shows changed packages (since last tag). |
| 23 | + |
| 24 | +- Sources and tests are written in strict [TypeScript](https://github.com/Microsoft/TypeScript). |
| 25 | + |
| 26 | + - Common base `tsconfig.json`. |
| 27 | + - [@ts-tools/node](https://github.com/AviVahl/ts-tools) is used to run code directly from sources. |
| 28 | + |
| 29 | +- Testing is done using [mocha](https://github.com/mochajs/mocha) and [chai](https://github.com/chaijs/chai). |
| 30 | + - Light, battle-tested, projects with few dependencies. |
| 31 | + - Can be bundled and used in the browser. |
| 32 | + |
| 33 | +### Included sample packages |
| 34 | + |
| 35 | +- **@sample/components** |
| 36 | + |
| 37 | + - [React](https://github.com/facebook/react) components library. |
| 38 | + - Built as `cjs` (Node consumption) and `esm` (bundler consumption). |
| 39 | + |
| 40 | +- **@sample/app** |
| 41 | + |
| 42 | + - [React](https://github.com/facebook/react) application. |
| 43 | + - Uses the `@sample/components` package (also inside monorepo). |
| 44 | + - Built as `cjs` (Node consumption) and `umd` (browser consumption). |
| 45 | + |
| 46 | +- **@sample/server** |
| 47 | + - [Express](https://github.com/expressjs/express) application. |
| 48 | + - Uses the `@sample/app` package (also inside monorepo). |
| 49 | + - Listens on http://localhost:3000 (client only rendering) http://localhost:3000/server (SSR rendering). |
| 50 | + - Built as `cjs` (Node consumption). |
| 51 | + |
| 52 | +### Basic structure and configurations |
| 53 | + |
| 54 | +``` |
| 55 | +.github // CI flow configuration (GitHub Actions) |
| 56 | +packages/ |
| 57 | + some-package/ |
| 58 | + src/ |
| 59 | + index.ts |
| 60 | + test/ |
| 61 | + test.spec.ts |
| 62 | + LICENSE // license file. included in npm artifact |
| 63 | + package.json // package-specific deps and scripts |
| 64 | + README.md // shown in npmjs.com. included in npm artifact |
| 65 | +
|
| 66 | +.eslintignore // eslint (linter) ignored directories/files |
| 67 | +.eslintrc // eslint (linter) configuration |
| 68 | +.gitignore // github's default node gitignore with customizations |
| 69 | +.mocharc.js // mocha (test runner) configuration |
| 70 | +lerna.json // lerna configuration |
| 71 | +LICENSE // root license file. picked up by github |
| 72 | +package.json // common dev deps and workspace-wide scripts |
| 73 | +README.md // workspace-wide information. shown in github |
| 74 | +tsconfig.json // common typescript configuration |
| 75 | +yarn.lock // the only lock file in the repo. all packages combined |
| 76 | +``` |
| 77 | + |
| 78 | +### Dependency management |
| 79 | + |
| 80 | +Traditionally, working with projects in separate repositories makes it difficult to keep versions of `devDependencies` aligned, as each project can specify its own `devDependency` versions. |
| 81 | + |
| 82 | +Monorepos simplify this, because `devDependencies` are shared between all packages within the monorepo. |
| 83 | + |
| 84 | +Taking this into account, we use the following dependency structure: |
| 85 | + |
| 86 | +- `devDependencies` are placed in the root `package.json` |
| 87 | +- `dependencies` and `peerDependencies` are placed in the `package.json` of the relevant package requiring them, as each package is published separately |
| 88 | + |
| 89 | +New `devDependencies` can be added to the root `package.json` using yarn: |
| 90 | + |
| 91 | +```sh |
| 92 | +yarn add <package name> --dev -W |
| 93 | +``` |
| 94 | + |
| 95 | +Some packages depend on sibling packages within the monorepo. For example, in this repo, `@sample/app` depends on `@sample/components`. This relationship is just a normal dependency, and can be described in the `package.json` of `app` like so: |
| 96 | + |
| 97 | +```json |
| 98 | + "dependencies": { |
| 99 | + "@sample/components": "<package version>" |
| 100 | + } |
| 101 | +``` |
| 102 | + |
| 103 | +### Deployment |
| 104 | + |
| 105 | +`yarn lerna publish` will publish new versions of the packages to npm. |
| 106 | + |
| 107 | +Lerna asks for new version numbers for packages that changed since last release and their dependencies. Every package has a `prepack` script which automatically runs `build` prior to packing. |
| 108 | + |
| 109 | +`yarn lerna publish --force-publish` will force a release of _all_ packages, regardless of which ones actually changed. |
| 110 | + |
| 111 | +Deployment of app/server assets to any actual production servers is not shown. |
0 commit comments