Episode 7:Understanding Hoisting in Yarn Workspaces

What Is Hoisting?

Hoisting in Yarn Workspaces refers to the process of lifting dependencies from individual package directories to a shared node_modules folder at the root of the repository.

This mechanism optimizes:

  1. Dependency Management:

    • Avoids duplicate installations for shared dependencies.
  2. File System Structure:

    • Simplifies the node_modules layout for better performance and disk usage.
  3. Package Linking:

    • Ensures packages are symlinked efficiently.

How Hoisting Works

  1. Workspace Package Symlinks:

    • Symlinks for workspace packages (e.g., moduleA and moduleB) are hoisted to the root node_modules folder.

    • This allows a single symlink per package, resolving dependencies globally.

  2. Shared Dependencies:

    • Dependencies installed for one module but required by others are hoisted to the root node_modules.

    • Example: Installing lodash for both moduleA and moduleB results in one shared copy at the root.


Practical Example: Hoisting in Action

1. Checking Node Modules

In a typical Yarn Workspace setup:

  • moduleA/node_modules/No folder present.

  • moduleB/node_modules/No folder present.

  • root/node_modules/ → Contains symlinks for moduleA, moduleB, and shared dependencies.


2. Installing Shared Dependencies

Step 1: Install lodash in moduleA

Run:

yarn workspace moduleA add lodash

Check the root node_modules:

  • lodash/ → Installed here, shared globally.

Step 2: Install lodash in moduleB

Run:

yarn workspace moduleB add lodash

Since lodash is already hoisted to the root, no additional copy is created. Both moduleA and moduleB access the same instance.


3. Handling Version Conflicts

If two modules require different versions of the same dependency:

  1. Root Version:

    • The version required by one module (e.g., lodash@4.17.21) is installed at the root.
  2. Per-Module Version:

    • The conflicting version (e.g., lodash@3.10.1) is installed in the node_modules folder of the module that needs it.

Example:

  • root/node_modules/lodash/4.17.21

  • packages/moduleB/node_modules/lodash/3.10.1

Each module will resolve the correct version via Node’s module resolution algorithm.


No-Hoist Dependencies

When to Use nohoist

Some packages are not compatible with hoisting, such as:

  • React Native

  • Electron

  • Packages with binaries or non-JavaScript files that depend on specific locations.

Defining nohoist

You can specify packages that shouldn’t be hoisted in the root package.json under the workspaces property:

{
  "workspaces": {
    "packages": ["packages/*"],
    "nohoist": [
      "**/react-native",
      "**/react-native/**"
    ]
  }
}

Effect of nohoist

  • react-native and its dependencies will be installed locally within each package’s node_modules.

  • These dependencies will not appear in the root node_modules.


Benefits of Hoisting

  1. Efficiency:

    • Reduces disk usage by avoiding duplicate installations.
  2. Performance:

    • Improves dependency resolution speed due to centralized management.
  3. Flexibility:

    • Handles version conflicts seamlessly when needed.
  4. Compatibility:

    • Allows opting out for specific packages via nohoist.

Summary

  • Hoisting centralizes shared dependencies at the root of a Yarn Workspace project, optimizing performance and disk usage.

  • Yarn resolves conflicts by installing specific versions in individual package directories when needed.

  • Use the nohoist option for packages that cannot or should not be hoisted.

Yarn Workspaces with hoisting provide a clean, efficient, and scalable solution for managing monorepos. 🎉