From 90a449809cd83e2499bdd377538bd77d0fd51167 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 21 Jul 2025 13:22:05 +0200 Subject: [PATCH 1/3] Add initial guide on monorepos --- data/sidebar_manual_v1200.json | 1 + .../manual/v12.0.0/build-monorepo-setup.mdx | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 pages/docs/manual/v12.0.0/build-monorepo-setup.mdx diff --git a/data/sidebar_manual_v1200.json b/data/sidebar_manual_v1200.json index 5269c67c9..a557f0d45 100644 --- a/data/sidebar_manual_v1200.json +++ b/data/sidebar_manual_v1200.json @@ -63,6 +63,7 @@ "build-configuration-schema", "build-external-stdlib", "build-pinned-dependencies", + "build-monorepo-setup", "interop-with-js-build-systems", "build-performance", "warning-numbers" diff --git a/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx b/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx new file mode 100644 index 000000000..11b8d51a6 --- /dev/null +++ b/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx @@ -0,0 +1,102 @@ +--- +title: "Setting up a monorepo" +metaTitle: "Setting up a monorepo" +description: "Setting up a monorepo" +canonical: "/docs/manual/v12.0.0/build-monorepo-setup" +--- + +# Setting up a monorepo with ReScript + +**Since 12.0** + +> A monorepo is a single repository containing multiple distinct projects, with well-defined relationships. + +ReScript 12.0 introduces native monorepo support via the new "Rewatch" build system. This guide shows you how to set it up. + +**Note:** This feature requires the new build system and is **not compatible** with `rescript legacy`. + +## Project Structure + +A ReScript monorepo requires a `rescript.json` file at the repository root, plus a `rescript.json` file in each sub-project directory. + +A typical structure looks like this: + +``` +my-monorepo/ +├── rescript.json +├── packages/ +│ ├── package-1/ +│ │ ├── rescript.json +│ │ ├── src/ +│ ├── package-2/ +│ │ ├── rescript.json +│ │ ├── src/ +│ ├── ... +``` + +## Root `rescript.json` Configuration + +The root `rescript.json` orchestrates the monorepo by listing its constituent packages. + +```json +{ + "name": "my-monorepo", + "dependencies": [ + "package-1", + "package-2" + ], + "package-specs": { + "module": "esmodule", + "in-source": true + }, + "suffix": ".res.mjs", + "bsc-flags": [] +} +``` + +The "dependencies" array specifies the names of your packages, which must correspond to the "name" fields in their respective sub-rescript.json files. + +Inheritance: By default, all settings defined in the root rescript.json are inherited by the individual packages. + +## Package `rescript.json` Configuration + +Each nested rescript.json configures a specific package. + +`packages/package-1/rescript.json`: + +```json +{ + "name": "package-1", + "sources": ["src"], + "dependencies": [] +} +``` + +`packages/package-2/rescript.json`: + +```json +{ + "name": "package-2", + "sources": ["src"], + "dependencies": ["package-1"], + "warnings": { + "number":"-27" + } +} +``` + +In `package-2`, we demonstrate overriding a root setting by specifically disabling warning 27 (unused variable) for this package only. + +Note the dependencies array here, which allows one package to depend on another within the monorepo. + +## Building the monorepo + +From the root directory, build all packages with: + +```bash +rescript build +``` + +Note on package.json: ReScript's build system manages the compilation of your ReScript code. +It does not directly interact with your `package.json` setup or `node_modules`. +You might need a separate monorepo tool (like Yarn Workspaces, pnpm, or npm Workspaces) to manage your JavaScript/Node.js dependencies across packages if applicable. \ No newline at end of file From a845d08045acbdc6f9262937c70761cbeaa46ea2 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 23 Jul 2025 08:28:12 +0200 Subject: [PATCH 2/3] Remove pinned dependencies --- data/sidebar_manual_v1200.json | 1 - .../manual/v12.0.0/build-configuration.mdx | 6 - .../v12.0.0/build-pinned-dependencies.mdx | 105 ------------------ 3 files changed, 112 deletions(-) delete mode 100644 pages/docs/manual/v12.0.0/build-pinned-dependencies.mdx diff --git a/data/sidebar_manual_v1200.json b/data/sidebar_manual_v1200.json index a557f0d45..dd7af60ba 100644 --- a/data/sidebar_manual_v1200.json +++ b/data/sidebar_manual_v1200.json @@ -62,7 +62,6 @@ "build-configuration", "build-configuration-schema", "build-external-stdlib", - "build-pinned-dependencies", "build-monorepo-setup", "interop-with-js-build-systems", "build-performance", diff --git a/pages/docs/manual/v12.0.0/build-configuration.mdx b/pages/docs/manual/v12.0.0/build-configuration.mdx index d7c7dfaa6..8d4240299 100644 --- a/pages/docs/manual/v12.0.0/build-configuration.mdx +++ b/pages/docs/manual/v12.0.0/build-configuration.mdx @@ -85,12 +85,6 @@ List of ReScript dependencies. Just like `package.json`'s dependencies, they'll Note that only sources marked with `"type":"dev"` will be able to resolve modules from `bs-dev-dependencies`. -## pinned-dependencies - -**Since 8.4**: List of pinned dependencies. A pinned dependency will always be rebuilt whenever you build a toplevel package (e.g. your main app) with `rescript`. - -This is useful for working on multiple independent ReScript packages simultaneously. More usage details can be found in our dedicated [pinned dependencies](./build-pinned-dependencies) page. - ## external-stdlib **Since 9.0**: This setting allows depending on an externally built stdlib package (instead of a locally built stdlib runtime). Useful for shipping packages that are only consumed in JS or TS without any dependencies to the ReScript development toolchain. diff --git a/pages/docs/manual/v12.0.0/build-pinned-dependencies.mdx b/pages/docs/manual/v12.0.0/build-pinned-dependencies.mdx deleted file mode 100644 index 405ac7f7c..000000000 --- a/pages/docs/manual/v12.0.0/build-pinned-dependencies.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "Pinned Dependencies" -metaTitle: "Pinned Dependencies" -description: "Handling multiple packages within one ReScript project with pinned dependencies" -canonical: "/docs/manual/v12.0.0/build-pinned-dependencies" ---- - -# Pinned Dependencies - -Usually we'd recommend to use ReScript in a single-codebase style by using one `rescript.json` file for your whole codebase. - -There are scenarios where you still want to connect and build multiple independent ReScript packages for one main project though (`npm` workspaces-like "monorepos"). This is where `pinned-dependencies` come into play. - -## Package Types - -Before we go into detail, let's first explain all the different package types recognized by the build system: - -- Toplevel (this is usually the final app you are building, which has dependencies to other packages) -- Pinned dependencies (these are your local packages that should always rebuild when you build your toplevel, those should be listed in `bs-dependencies` and `pinned-dependencies`) -- Normal dependencies (these are packages that are consumed from npm and listed via `bs-dependencies`) - -Whenever a package is being built (`rescript build`), the build system will build the toplevel package with its pinned-dependencies. So any changes made in a pinned dependency will automatically be reflected in the final app. - -## Build System Package Rules - -The build system respects the following rules for each package type: - -**Toplevel** - -- Warnings reported -- Warn-error respected -- Builds dev dependencies -- Builds pinned dependencies -- Runs custom rules -- Package-specs like JavaScript module or CommonJS overrides all its dependencies - -**Pinned dependencies** - -- Warnings reported -- Warn-error respected -- Ignores pinned dependencies -- Builds dev dependencies -- Runs custom rules - -**Normal dependencies** - -- Warnings, warn-error ignored -- Ignores dev directories -- Ignores pinned dependencies -- Ignores custom generator rules - -So with that knowledge in mind, let's dive into some more concrete examples to see our pinned dependencies in action. - -## Examples - -### Yarn workspaces - -Let's assume we have a codebase like this: - -``` -myproject/ - app/ - - src/App.res - - rescript.json - common/ - - src/Header.res - - rescript.json - myplugin/ - - src/MyPlugin.res - - rescript.json - package.json -``` - -Our `package.json` file within our codebase root would look like this: - -```json -{ - "name": "myproject", - "private": true, - "workspaces": { - "packages": ["app", "common", "myplugin"] - } -} -``` - -Our `app` folder would be our toplevel package, consuming our `common` and `myplugin` packages as `pinned-dependencies`. The configuration for `app/rescript.json` looks like this: - -```json -{ - "name": "app", - "version": "1.0.0", - "sources": { - "dir": "src", - "subdirs": true - }, - /* ... */ - "bs-dependencies": ["common", "myplugin"], - "pinned-dependencies": ["common", "myplugin"] - /* ... */ -} -``` - -Now, whenever we are running `rescript build` within our `app` package, the compiler would always rebuild any changes within its pinned dependencies as well. - -**Important:** ReScript will not rebuild any `pinned-dependencies` in watch mode! This is due to the complexity of file watching, so you'd need to set up your own file-watcher process that runs `rescript build` on specific file changes. From 5bb2f82f0ce7c060c148324a78c33eebffa14f99 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 2 Oct 2025 16:22:45 +0200 Subject: [PATCH 3/3] Correct rewatch guide --- .../manual/v12.0.0/build-monorepo-setup.mdx | 152 +++++++++++++++--- 1 file changed, 132 insertions(+), 20 deletions(-) diff --git a/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx b/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx index 11b8d51a6..f132770d2 100644 --- a/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx +++ b/pages/docs/manual/v12.0.0/build-monorepo-setup.mdx @@ -9,42 +9,48 @@ canonical: "/docs/manual/v12.0.0/build-monorepo-setup" **Since 12.0** -> A monorepo is a single repository containing multiple distinct projects, with well-defined relationships. +> A monorepo is a single repository containing multiple separate projects, with clear relationships between them. -ReScript 12.0 introduces native monorepo support via the new "Rewatch" build system. This guide shows you how to set it up. +ReScript 12.0 introduces improved support for native monorepos through the new "Rewatch" build system. This guide walks you through the setup process. -**Note:** This feature requires the new build system and is **not compatible** with `rescript legacy`. +**Note:** This feature requires the new build system and is **not compatible** with `rescript-legacy`. ## Project Structure A ReScript monorepo requires a `rescript.json` file at the repository root, plus a `rescript.json` file in each sub-project directory. +Basically, the monorepo contains a root package that manages all local dependencies. Building the root package will build all its dependencies. + +**Important:** You also need a node_modules monorepo setup with symlinks. In practice, if you want a ReScript monorepo, you will also need an npm/yarn/pnpm/bun monorepo. A typical structure looks like this: ``` my-monorepo/ ├── rescript.json +├── package.json +├── node_modules/ +│ ├── package-1/ # symlinked +│ ├── package-2/ # symlinked ├── packages/ │ ├── package-1/ │ │ ├── rescript.json +│ │ ├── package.json │ │ ├── src/ │ ├── package-2/ │ │ ├── rescript.json +│ │ ├── package.json │ │ ├── src/ │ ├── ... ``` ## Root `rescript.json` Configuration -The root `rescript.json` orchestrates the monorepo by listing its constituent packages. +The root `rescript.json` manages the monorepo by listing its packages. ```json { "name": "my-monorepo", - "dependencies": [ - "package-1", - "package-2" - ], + "dependencies": ["package-1", "package-2"], "package-specs": { "module": "esmodule", "in-source": true @@ -54,13 +60,33 @@ The root `rescript.json` orchestrates the monorepo by listing its constituent pa } ``` -The "dependencies" array specifies the names of your packages, which must correspond to the "name" fields in their respective sub-rescript.json files. +The `"dependencies"` array lists the names of your packages, which must match the `"name"` fields in their respective sub-rescript.json files. +When you build a package in ReScript, it will use the `"package-specs"` and `"suffix"` settings from the root package. +Therefore, it is recommended to place these settings in the root `rescript.json` file and avoid specifying them in local package `rescript.json` files. + +**Settings from different config files:** When Rewatch builds a package within a monorepo setup, it uses these settings from the root rescript.json: + +- `"jsx"` (jsx_args, jsx_module_args, jsx_mode_args, jsx_preserve_args) +- `"experimental"` (experimental_features_args) +- `"package-specs"` (used for implementation_args) +- `"suffix"` (used for package output) + +These settings come from the package's own rescript.json: + +- `"sources"` (determines which files to compile) +- `"dependencies"` (package dependencies) +- `"warnings"` (warning_args) +- `"compiler-flags"` (bsc_flags) + +When the root package is built, Rewatch will look for the dependencies inside the `my-monorepo/node_modules` folder. +It is expected that `package-1` and `package-2` are available there via a symlink system provided by your node_modules package manager. -Inheritance: By default, all settings defined in the root rescript.json are inherited by the individual packages. +Note that your root rescript.json is allowed to have a `"sources"` setting. +These files will be compiled as expected. ## Package `rescript.json` Configuration -Each nested rescript.json configures a specific package. +Each nested rescript.json sets up a specific package. `packages/package-1/rescript.json`: @@ -68,7 +94,8 @@ Each nested rescript.json configures a specific package. { "name": "package-1", "sources": ["src"], - "dependencies": [] + "dependencies": [], + "compiler-flags": ["-open Foobar"] } ``` @@ -79,24 +106,109 @@ Each nested rescript.json configures a specific package. "name": "package-2", "sources": ["src"], "dependencies": ["package-1"], - "warnings": { - "number":"-27" + "warnings": { + "number": "-27" } } ``` -In `package-2`, we demonstrate overriding a root setting by specifically disabling warning 27 (unused variable) for this package only. +In `package-1`, we show how to use special compiler flags. +In `package-2`, we show how to disable warning 27 (unused variable). +In both cases, the settings only apply to the package where they are specified. +Defining these in the root rescript.json will not affect the packages. +There is no inheritance system. -Note the dependencies array here, which allows one package to depend on another within the monorepo. +Also note the dependencies array in `package-2`, which allows that package to depend on `package-1` within the monorepo. ## Building the monorepo -From the root directory, build all packages with: +From the root directory, you can run all ReScript commands: + +```bash +# Build all packages +rescript build + +# Clean all packages +rescript clean + +# Format all packages +rescript format +``` + +### Building individual packages + +You can also run ReScript commands on individual packages instead of the entire monorepo. This is useful when you only want to work on one package. ```bash +# Build from the package directory +cd packages/package-3 rescript build +rescript clean +rescript format + +# Or run from the root directory +rescript build packages/package-3 +rescript clean packages/package-3 +rescript format packages/package-3 +``` + +When building a single package, ReScript will use the settings from the root rescript.json as explained in the [Root rescript.json Configuration](#root-rescriptjson-configuration) section above. + +### Building without a root rescript.json + +If your node_modules monorepo is set up with symlinks, you can build packages even without a root rescript.json: + ``` +my-monorepo/ +├──node_modules/ +│ ├── package-1/ # symlinked +│ ├── package-2/ # symlinked +├── package.json +├── packages/ +│ ├── package-1/ +│ │ ├── rescript.json +│ │ ├── package.json +│ │ ├── src/ +│ ├── package-2/ +│ │ ├── rescript.json +│ │ ├── package.json +│ │ ├── src/ +│ ├── ... +``` + +Building `package-2` (which depends on `package-1`) will search up the folder structure to find `package-1`. + +Example: + +```bash +rescript build ./packages/package-2 +``` + +Internally, Rewatch will look for: + +- 🔴 `my-monorepo/packages/package-2/node_modules/package-1` +- 🔴 `my-monorepo/packages/node_modules/package-1` +- ✅ `my-monorepo/node_modules/package-1` + +This only happens as a last resort if `package-1` is not listed as a (dev-)dependency in a parent `rescript.json`. + +## Troubleshooting + +If you're having issues with your monorepo setup, you can use the `-v` flag during build to see what Rewatch detected as the project context: + +```bash +rescript build -v +``` + +This will show you detailed information about how Rewatch is interpreting your project structure and which configuration files it's using. + +## Recommendation + +**The ReScript team strongly recommends using a root `rescript.json` file when setting up monorepos.** While it's technically possible to build packages without one (as shown in the section above), having a root configuration file provides several benefits: + +- **Consistent settings** across all packages (jsx, experimental features, package-specs, suffix) +- **Simplified dependency management** through the root dependencies array +- **Better developer experience** with unified build commands from the root +- **Easier maintenance** and configuration updates across the entire monorepo -Note on package.json: ReScript's build system manages the compilation of your ReScript code. -It does not directly interact with your `package.json` setup or `node_modules`. -You might need a separate monorepo tool (like Yarn Workspaces, pnpm, or npm Workspaces) to manage your JavaScript/Node.js dependencies across packages if applicable. \ No newline at end of file +The root `rescript.json` approach is the intended and supported way to work with ReScript monorepos.