🍒 Cherry-Picked Nx v19.6 Updates

Jonathan GelinJonathan Gelin
6 min read


🌊 Nx Core

Skipping Dependent Tasks

When testing or for any other reason, you may want to skip running the entire tree of task dependencies. You can now achieve this with the --exclude-task-dependencies flag in your Nx command:

nx run app:build --exclude-task-dependencies

New Nx Sync Command

⚠️ This is an experimental feature, currently undocumented and subject to change.

The nx sync command is a new feature that runs a list of generators to ensure your workspace is always up-to-date:

nx sync

You can configure this command globally in your nx.json:

{
  sync: {
    /**
     * List of workspace-wide sync generators to be run (not attached to targets).
     */
    globalGenerators?: string[];

    /**
     * Options for the sync generators.
     */
    generatorOptions?: {
      [generatorName: string]: Record<string, unknown>;
    };

    /**
     * Whether to automatically apply sync generator changes when running tasks.
     * If not set, the user will be prompted.
     * If set to `true`, the user will not be prompted and the changes will be applied.
     * If set to `false`, the user will not be prompted and the changes will not be applied.
     */
    applyChanges?: boolean;
  }
}

Alternatively, you can configure it per target by adding the syncGenerators option to the target’s configuration. For example:

"libs/my-lib": {
  "targets": {
    "typecheck": {
      "command": "tsc --build --emitDeclarationOnly --pretty --verbose",
      "outputs": [],
      "syncGenerators": [
        "@nx/js:typescript-sync",
      ],
    },
  },
},

In this setup, the @nx/js:typescript-sync generator will be called before running the TypeScript command to keep tsconfig project references in sync with the project graph.

You can also run nx sync:check to validate that the workspace is up-to-date without applying changes. This is especially useful as a CI validation step.

New Nx Import Command

Nx has introduced a new command to simplify integrating external repositories into your monorepo:

nx import

Transferring files between repos can be tricky, especially when preserving Git history. The nx import command automates the process by:

  1. Cloning the external repository.

  2. Moving the code to the desired directory in a temporary branch.

  3. Merging the code into the current workspace branch.

  4. Recommending Nx plugins for tool integration from the imported code.

For a demo of how nx import works, check out this PR demo:


🧩 Module Federation

New setRemoteDefinition API

Instead of using setRemoteDefinitions, which replaces the entire state, you can now use setRemoteDefinition(remoteName: string, remoteUrl: string) to add or update a specific remote without overwriting the existing remote map.

Local DX Improvements

I will redirect you to the new great documentation: Nx Module Federation Technical Overview:

The NxRuntimeLibraryControlPlugin

🖨 ️Copied from the Nx documentation by Colum Ferry

Previously, when using shared workspace libraries as part of your Module Federation application, there was a chance that the workspace library would be provided by one of the static remotes. This would cause issues where changes to those shared libraries would not be reflected in the locally served application.

To combat this issue, we developed the NxRuntimeLibraryControlPlugin. This is a Runtime Plugin that will ensure that workspace libraries are only shared via any active dev remote. This means that any changes to the shared library will be picked up by webpack-dev-server and, as such, reflected in the locally served application.

This plugin is enabled by default, however, you can turn it off in your module-federation.config file:

export const config: ModuleFederationConfig = {
  ...,
  disableNxRuntimeLibraryControlPlugin: true
}

📦 Nx Release

Version Plans

Nx Release is introducing a new approach to versioning packages. Until now, Nx Release supported either a static approach — prompting for each project — or an automatic approach based on conventional commits from Git history.

However, if you’re not using conventional commits or prefer to have more control over the release notes and how versions are bumped, you can now use the new Version Plan approach. With this method, version bumps are defined by files located in the .nx/version-plans folder.

Let’s walk through an example using the e2e version-plans.test.ts. Imagine you have two groups of releases: one group with a fixed version (fixed-group) and another with independent versions (independent-group). You can configure nx.json to activate your version plans as follows:

{
  "release": {
    "groups": {
      "fixed-group": {
        "projects": ["pkg1", "pkg2"],
        "releaseTagPattern": "v{version}"
      },
      "independent-group": {
        "projects": ["pkg3", "pkg4", "pkg5"],
        "projectsRelationship": "independent",
        "releaseTagPattern": "{projectName}@{version}"
      },
    },
    "version": {
      "generatorOptions": {
        "specifierSource": "version-plans"
      },
    },
    "changelog": {
      "projectChangelogs": true,
    },
    "versionPlans": true,
  };
}

Next, you can create a Version Plan file to specify how to bump the versions for each package and group.

You can either generate it automatically by running:

nx release plan minor -g fixed-group -m "feat: Update the fixed packages with a minor release."

Or, you can create one manually by adding a file like ./nx/bump-independent.md:

---
pkg3: patch
pkg4: preminor
pkg5: prerelease
---
feat: Update the independent packages with a patch, preminor, and prerelease.

Once these plans are defined and pushed, the nx release command will follow them:

pkg1 📄 Resolved the specifier as "minor" using version plans.
...
pkg2 ✍️  New version 0.1.0 written to pkg2/package.json
...
pkg3 📄 Resolved the specifier as "patch" using version plans.
pkg4 📄 Resolved the specifier as "preminor" using version plans.
pkg5 📄 Resolved the specifier as "prerelease" using version plans.

The changelog will not only be generated from the Git commits but will also include details from your Version Plan.

To ensure every modification impacting a releasable project aligns with a version plan, you can run the following on your CI:

nx release plan:check

For more information, see the blog post Nx 19.5 is here! Stackblitz, Bun, Incremental Builds for Vite, Gradle Test Atomizer

Log Unchanged Project Only

The version generator logs activity for every project, which can create noise in large monorepos where only a subset of projects is being released.

To address this, a new logUnchangedProjects option has been introduced. This allows you to configure the generator to suppress logs for unchanged projects. The default behavior remains unchanged, and this option is opt-in.


🌐 Nx Cloud

Explain with AI

Following the introduction of AI into Nx’s documentation (via AI Chat) and Nx Cloud (via Tusky), a new Explain With AI feature is now available. This tool helps developers quickly understand complex errors and provides suggestions for improvements, streamlining the debugging process.


💫 Upgrades

Support of Angular v18.2.0

Support Storybook 8

Upgrade to Jest v29.7.0


📣 Monorepo World Conference

The Monorepo World conference is coming up soon on October 7, 2024 at the Computer History museum in Mountain View, California.


Looking for some help? 🤝Connect with me on Twitter LinkedIn Github


0
Subscribe to my newsletter

Read articles from Jonathan Gelin directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jonathan Gelin
Jonathan Gelin

Who am I? Whether it's as a Software Engineer, Tech Lead, or Architect, if it involves software development, I'm in! My journey began in the realm of Java development, but I fully transitioned into the universe of JavaScript/TypeScript and its exciting toolset. I support companies through their software development cycle challenges by utilizing Nx monorepos, micro frontends, robust testing strategies, and a touch of Extreme Programming philosophy. Every day for me is like waiting for the next episode of my favorite series—filled with learning, sharing, and growing together. Indeed, I'm as passionate about coaching and sharing knowledge as I am about coding. I am the father of two incredible boys, and I am endlessly grateful to my wife for supporting my passion every day.