DEV Community

Cover image for Creating a scalable Monorepo for Vue - Nx
Dawid Nitka
Dawid Nitka

Posted on • Edited on

Creating a scalable Monorepo for Vue - Nx

As your codebase grows, so does the complexity of managing multiple apps and libraries. At this point Nx can help with its graph, but more importantly it can orchestrate all builds and tests in monorepo and keep you sane while managing dozens of packages.

In essence Nx is capable of running tasks in parallel based on what has changed from the previous commit. It also respects dependencies, ensuring that libraries needed by others are built first.

 

Key Features

  • Project Graph & Dependency Awareness
    Nx automatically analyzes your workspace and builds a project graph, understanding how your apps and libraries depend on each other. This
    allows you to build or test only what has changed and furthermore what is directly influenced by it, based on the changes between the current and the previous commit.

  • Code Generation
    Nx provides some nice generators for scaffolding new apps, libraries,
    etc. I found them to be decent for Vue, but if you like it your way you can of course just ignore them.

  • Advanced Caching
    Nx caches build and test results, so repeated commands are lightning
    fast. It can even share cache results across CI runs and between developers (Caution: sharing is a nice but paid feature - still very useful for enterprise clients).

  • Powerful CI/CD
    Nx can run tasks in parallel, only for affected projects, and provides detailed output for CI pipelines.

 

How to Configure Nx in Your Monorepo

 

Install Nx

If you’re starting from scratch, you can create a new Nx workspace with:

pnpx create-nx-workspace
Enter fullscreen mode Exit fullscreen mode

In an existing monorepo, install Nx as a dev dependency and run init:

pnpm add -D nx

nx init
Enter fullscreen mode Exit fullscreen mode

 

Nx Workspace Structure

Nx expects some sub-directories with package.json or it's internal project.json file by default as a marker of a package. Sample structure can look like this:

/
├── apps/
│   └── app_1/
├── libs/
│   └── commons/
│   └── ui/
├── nx.json
├── workspace.json (or project.json or package.json files)
├── tsconfig.base.json
├── pnpm-workspace.yaml
└── package.json
Enter fullscreen mode Exit fullscreen mode
  • apps/: Applications (SPA, SSR, etc.)
  • libs/: Reusable libraries (UI, utilities, etc.)
  • nx.json: Nx-specific configuration (project graph, tasks, etc.)
  • workspace.json: Project definitions (can be split into per-project project.json or package.json),
  • pnpm-workspace.yaml: Defines workspace packages for pnpm

 

Adding Nx Plugins

Nx supports plugins for frameworks and tools. For example, to add Vue support:

pnpm add -D @nx/vue
Enter fullscreen mode Exit fullscreen mode

Or for Storybook:

pnpm add -D @nx/storybook
Enter fullscreen mode Exit fullscreen mode

With the mentioned plugins you can run and utilize Nx commands for these frameworks, but also use them for scaffolding new projects.

To start with using commands as well as Nx packages I recommend the vscode plugin Nx Console. It’s a great tool for exploring available options and features.

 

Basic Nx Commands

  • Run a target:
  pnpm nx build:staging @monorepo/app_1
  pnpm nx lint @monorepo/commons
Enter fullscreen mode Exit fullscreen mode
  • Run for affected (changed from the last commit) projects only:
  pnpm nx affected -t build:staging
Enter fullscreen mode Exit fullscreen mode
  • Start the project graph:
  pnpm nx graph
Enter fullscreen mode Exit fullscreen mode
  • List of installed and available plugins:
  pnpm nx list
Enter fullscreen mode Exit fullscreen mode

 

graph

It helps you visualize the dependencies between your packages. If you want to categorize your packages correctly in this browser based tool, I recommend either generating workspace.json or a bunch of project.json files, or as in my case (the simplest one) just adding this to your package.json files:

{
    "name": "@monorepo/ui",
    "version": "1.0.0",
    // ...
    "nx": {
        "projectType": "library" // or "application"
    }
}
Enter fullscreen mode Exit fullscreen mode

Image description

 

affected

Running locally the affected command will work with default settings only if creating branch and making some changes as it compares your branch to the main. But you can always explicitly compare the current state with a state from a couple of commits ago for test purposes.

# run lint for packages which changed 
# between the current state and the state from 5 commits ago
pnpm nx affected -t lint --base=HEAD~5 --head=HEAD  
Enter fullscreen mode Exit fullscreen mode

Nx lint run result

This is the result of running lint for all packages in my monorepo template.

Not very spectacular, I know, but imagine how much build time you can save with a big monorepo while running this command on your server and executing commands in parallel only for the changed parts!

 

This is the last article in this series. If you want to learn more about creation of monorepo with Vue, check out other tutorials. If you prefer starting with a solid foundation - try this template, where I’ve put all of this into practice.

Top comments (0)