DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Nx 15.3 - Standalone Projects, Vite, Task Graph and more!
Juri Strumpflohner for Nx

Posted on • Updated on • Originally published at blog.nrwl.io

Nx 15.3 - Standalone Projects, Vite, Task Graph and more!

What a massive release! Here are all the news πŸ‘‡

Table of Contents

Prefer a video version?

Funding - Nx raises $8.6M

In case you missed it, we raised $8.6 million a couple of weeks ago. Here's the official blog post from our CEO Jeff: https://blog.nrwl.io/from-bootstrapped-to-venture-backed-nx-raises-8-6m-2ae2228eff76

It is exciting for us as we can now have more employees focused on pushing Nx and Nx Cloud forward, which will significantly boost development speed!
For most of our workforce, working on Nx and Nx Cloud was only part of their "20% project". Yet we released terrific features over the last years and have seen tremendous growth with Nx (which brings us to the next section)

3 million downloads per week

2022 has been a particularly crazy but successful year for us. And Nx's growth confirms that we're on the right track:

  • January: Nx crosses 1 million downloads per week
  • June: Nx crosses 2 million downloads per week
  • November: Nx crosses 3 million downloads per week

On to 4 million!

3 Million Downloads per week

New Task Graph Visualization

One of our most loved features also just got more powerful: the Nx graph!

Nx already visualizes your project graph, mapping the dependencies different projects have on one another through imports and exports in your code. But your tasks also have a graph. Your task can either depend on another target on the same project, let's say you have a prebuild
and a build target. Whenever you run build, you want to run prebuild first. Similarly, if your project depends on other projects, you might want to make sure to build them first as well. This is called a task pipeline and can be defined in nx.json as follows:

// nx.json
{
    ...
    "targetDefaults": {
      "build": {
        "dependsOn": ["prebuild", "^build"]
      }
    }
}
Enter fullscreen mode Exit fullscreen mode

This example is pretty straightforward, but such pipelines can become much more involved.

Therefore, let me introduce you the task graph. You might already be used to seeing the project graph after running the nx graph command. But there's now a dropdown in the corner that enables you to switch to the task graph. Select a target from the "Target Name dropdown" to filter the list of projects to only projects which have that target. Click on a project to show that target's task graph.

You can add another project as well, showing what the task graph looks like for a command that runs tasks for multiple projects like nx run-many or nx affected. Click on the Group by project checkbox to group related tasks by their project, and click on a task to see what executor it uses.

the new Nx Task Graph visualization

Standalone Projects

Nx is widely known as THE developer tool people look at when it comes to implementing monorepos in the frontend space. However, a lot of the unique features that Nx ships (in particular when it comes to implementing Integrated Monorepos) can be beneficial even outside of the typical monorepo scenario. In particular, Nx plugin features such as code generation, pre-configured build tooling setup, and battle-tested integration with best practices tools (e.g. Cypress, Jest, ESLint, Vite, ...).

But one stands out most prominently: the ability to easily modularize your codebase.

Apps and libs modularization

A lot of our users adopt Nx for precisely this reason. They have a large app and want to break it into smaller pieces while still having the comfort of deploying it as a single one.

In 15.3 we are therefore making standalone projects a first-class feature. Suppose you now create a new workspace with npx create-nx-workspace alongside the usual monorepo options. In that case, you will now see two more options for scaffolding a standalone React or Angular application (we will add more in the future).

new standalone options when creating a Nx project

In a standalone project setup, you don't have the typical apps and libs structure you might be accustomed to if you have been using Nx in the past. Instead, the app lives directly at the root of your workspace. The structure looks similar to the following:

e2e/
Β  src/
Β  cypress.config.ts
Β  project.json
Β  ...
src/
Β  app/
Β  main.tsx
Β  ...
public/
index.html
project.json
tsconfig.spec.json
tsconfig.app.json
tsconfig.json
vite.config.ts
nx.jsonΒ  Β  Β  Β  Β  Β  Β  Β  Β  Β  Β  Β 
package.json
Enter fullscreen mode Exit fullscreen mode

The critical part here is that you can still have multiple nodes. Even in this example, we have the app itself at the root of the workspace and a nested e2e project for that application (using Cypress).

To modularize your application, you can add libraries as you would do in a more traditional integrated Nx monorepo setup, but you can now have those alongside your application. Either create them directly at the root-level or group them in one or more root-level folders. In the example below, I have a features as well as utils folder, both of which can host multiple libraries.

e2e/
  ...
src/
Β  app/
Β  main.tsx
Β  ...
features/
  feature1/
  feature2/
utils/
  ...
index.html
...
nx.jsonΒ  Β  Β  Β  Β  Β  Β  Β  Β  Β  Β  Β 
package.json
Enter fullscreen mode Exit fullscreen mode

It is really up to you how you want to structure them.

Think of it as a supercharged development tool, providing powerful generators, features like module boundary rules and obviously the ability to run tests, linting, building on individual libraries. Not to forget about Nx's powerful caching ability. And if you're ready for a "real" monorepo because you want to add multiple applications, there will be paths for you to "upgrade" to that structure.

Integrated Vite and Vitest support is here!

Finally! We talked about it; now it is here! Official Vite and Vitest support for Nx-based integrated monorepos and standalone app projects! That adds the Vite community into the Nx family, and we've been chatting with core members there recently, and we love it!

So before we dive into this: if you are using a package-based monorepo with Nx, you could already use Vite or whatever other technology you want. Nx does just the task scheduling there, running your package.json scripts efficiently. Whatever those scripts do "internally" is up to you.

But if you power an integrated setup, you'd want more support via a dedicated Nx plugin. And there has already been a Nx community plugin created by the folks from https://nxext.dev/. Given the high demand for Vite support, we (the Nx core team) started to look into creating and maintaining our own. We reached out to the out Dominik Piper and Jordan Hall from the NxExt team and they were on board from the beginning! We got lots of helpful input, while designing the new Vite plugin. Huge shoutout to them!!

@nrwl/vite (just like @nrwl/webpack) is a package that can be integrated as part of other packages. Right now, we're prioritizing our React setup. If you generate a new Nx workspace and choose the new "Standalone React app" version, you will get a React application powered by Vite and Vitest.

Similarly, you can add a new Vite-powered React app to an existing Nx workspace using the vite bundler option:

npx nx generate @nrwl/react:application --bundler=vite
Enter fullscreen mode Exit fullscreen mode

This new setup gives you an easy jumpstart as it does all the configuration for you:

  • React with Vite
  • Tests with Vitest
  • Making sure it nicely works with TypeScript (both in src and spec files)

Open the application's project.json to inspect the setup:

{
  "name": "viteapp",
  ...
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nrwl/vite:build",
      ...
    },
    "serve": {
      "executor": "@nrwl/vite:dev-server",
      "defaultConfiguration": "development",
      ...
    },
    "test": {
      "executor": "@nrwl/vite:test",
      "outputs": ["{projectRoot}/coverage"],
      "options": {
        "passWithNoTests": true
      }
    },
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

Furthermore, there's a vite.config.ts at the project root level, which you can further customize to your needs. It is already pre-configured to seamlessly work in a monorepo scenario and has the Vitest setup. Just run npx nx serve or npx nx build or npx nx test to serve, build or test your standalone React app.

If you are currently using the NxExt based Vite plugin, or even a Webpack based Nx React setup, you can easily transition to the new Vite plugin by just running the following generator:

npx nx g @nrwl/vite:configuration
Enter fullscreen mode Exit fullscreen mode

This will adjust the NxExt Vite plugin configuration to match the one provided by our core team. Check out our docs for more info: https://nx.dev/packages/vite/generators/configuration

You can also find all the details about the new Vite package on our docs: https://nx.dev/packages/vite

Adopting Nx has never been easier

Many developers don't necessarily start with a greenfield project, but rather have an existing reality where they want to use Nx. We've been improving this process of adopting Nx over this year to the point where it has never been easier than now!

Regardless of whether you have

  • an existing package-based monorepo setup using NPM/Yarn or PNPM workspaces
  • an existing Lerna workspace (for this you probably want to consult the Lerna docs for some awesome feature updates)
  • a Create-React-App (CRA) application
  • a Angular CLI standalone application
  • or really any other form of project

You can just run

npx nx@latest init
Enter fullscreen mode Exit fullscreen mode

Running this command will install the nx package, and then analyze your existing project structure and correctly identify whether it is a monorepo workspace or some standalone project, whether it's a CRA app or whether you're coming from the Angular CLI. Based on that, you'll get a couple of questions asked and then your workspace gets configured to run it with Nx.

Check out our docs for all the details on

Oh..you're wondering why you would want to add Nx to an existing non-monorepo project? Then keep reading πŸ‘‡

Adding Nx to an Existing Standalone Project

Adding Nx to a single application? Why would that be useful? Well, most apps have multilple scripts in their package.json, which includes building, testing, linting your app and potentially much more. Nx can cache these! Obviously it is just app-level caching (since you didn't modularize it with libraries), but imagine your CI setup running these:

npx nx build
npx nx test
npx nx lint
npx nx e2e
Enter fullscreen mode Exit fullscreen mode

If your change just modified a couple of "spec files", then there's no point on running build or e2e again, but just test and potentially lint. Nx can restore the results of the other operations from the cache.

To add Nx to an existing standalone project, all you need to run is

npx nx@latest init
Enter fullscreen mode Exit fullscreen mode

This process will ask you a few questions about which operations are cacheable. We optimized it so that you don't necessarily have to use nx to run your build, linting or serving your app. You can keep using npm run build or npm start. This is because Nx wraps your scripts in the package.json. Notice how build and lint are wrapped because they are cacheable operations.

{
  ...
  "scripts": {
    "build": "nx exec -- vite build",
    "lint": "nx exec -- eslint \"src/**/*.ts*\"",
    ...
    "dev": "vite",
    "start": "vite --open",
  },
  "devDependencies": {
    ...
    "nx": "15.3.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Read more on our docs: https://nx.dev/recipes/adopting-nx/adding-to-existing-project

Root-level Scripts

Most of the tasks in a workspace run against a specific project, like building or testing it. That's why they live in the corresponding package.json or project.json. But sometimes you have workspace wide commands which you want to run through the "Nx pipeline" to get the benefits of caching.

Assume you have already a script called docs in your root-level package.json.

// package.json
{
  "name": "myorg",
  "scripts": {
    "docs": "node ./generateDocsSite.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

To allow it to be cached and to be run with Nx, all you need to do is add the follow nx property to your package.json:

// package.json
{
  "name": "myorg",
  "scripts": {
    "docs": "node ./generateDocsSite.js"
  }
  "nx": {}
}
Enter fullscreen mode Exit fullscreen mode

You can then run it with

npx nx docs
Enter fullscreen mode Exit fullscreen mode

As the next steps you might obviously want to add docs to the cacheable operations and fine-tune it's cache inputs.

Read more about it on our docs: https://nx.dev/recipes/other/root-level-scripts

Simplified Nx run-commands

Nx can automatically detect your scripts in package.json. But if you have an integrated setup using Nx plugins, they usually come with a project.json . There you have targets like build, test, lint etc.. and they mostly look as follows:

// project.json
{
  "name": "demoapp",
  ...
  "targets": {
    "build": {
      "executor": "@nrwl/vite:build",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "outputPath": "dist/demoapp"
      },
      ...
    },
    "serve": {
      "executor": "@nrwl/vite:dev-server",
      ...
    },
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

The task itself is handled by an Nx executor that comes with the plugin, in this case @nrwl/vite:build to build a Vite project.

To add a custom command, like invoking a node script, Nx has the so-called "run-commands". So far you had to wrap those commands as follows:

// project.json
{
  "name": "demoapp",
  ...
  "targets": {
    "prebuild": {
      "executor": "nx:run-commands",
      "options": {
        "command": "echo 'hi'"
       }
    },
    "build": {
      ...
    },
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

For simple commands this was a huge overhead, so we simplified it to just this:

// project.json
{
  "name": "demoapp",
  ...
  "targets": {
    "prebuild": {
      "command": "echo 'hi'"
    },
    "build": {
      ...
    },
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

Simple, isn't it! Obviously the expanded form is still there and also useful for when you need more options, run multiple commands or features such as argument forwarding.

You can read all about it on our docs: https://nx.dev/recipes/executors/run-commands-executor

Coming up

Wow, what a launch! But more features are on the way in the coming weeks that didn't make it for this release. Super excited about these, which most prominently include

  • Workspace watching
  • Lock-file pruning
  • Nx Cloud integration into Nx Console

Follow us on our socials and on Youtube to make sure to see it when we announce them!

How to Update Nx

Updating Nx is done with the following command and will update your Nx workspace dependencies and code to the latest version:

npx nx migrate latest
Enter fullscreen mode Exit fullscreen mode

After updating your dependencies, run any necessary migrations.

npx nx migrate --run-migrations
Enter fullscreen mode Exit fullscreen mode

Learn more

Also, if you liked this, click the ❀️ and make sure to follow Juri and Nx on Twitter for more!

#nx

Top comments (1)

Collapse
 
ngplex profile image
NG Plex • Edited on

Great news!! Are you planning to add Vitest to Nx Angular projects?

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

β­οΈπŸŽ€ JavaScript Visualized: Promises & Async/Await

async await