17

I've a monorepo using nx with multiple node/nestjs apps. Some of the apps doesn't require all the packages used in the other apps. Because it's a monorepo, I need to install all packages for every apps during the deployment.

Is there a way generate a package.json on build that would contain only the packages needed for the app that I'm building?

I've tryed to use "generate-package-json-webpack-plugin" to generate the package.json, but it only detect half the dependencies.

I've also tried to build a single js file containing all the apps, but it doesn't seem to work and always require tslib.

N0Cloud
  • 201
  • 1
  • 2
  • 6

3 Answers3

27

After I look at the nx source code I found the answer.

Set generatePackageJson to true in workspace.json where <project-name>/targets/build/options.

This will generate you package.json with the necessary dependencies for your app.

Here example:

"node-api": {
      "root": "apps/node-api",
      "sourceRoot": "apps/node-api/src",
      "projectType": "application",
      "prefix": "node-api",
      "targets": {
        "build": {
          "executor": "@nrwl/node:build",
          "outputs": ["{options.outputPath}"],
          "options": {
            "showCircularDependencies": false,
            "outputPath": "dist/apps/node-api",
            "main": "apps/node-api/src/main.ts",
            "tsConfig": "apps/node-api/tsconfig.app.json",
            "assets": ["apps/node-api/src/assets"],
            "generatePackageJson": true <----------------------
          },
....
Shlomi Levi
  • 3,114
  • 1
  • 23
  • 35
1

Nx encourages a single-version policy and has a single package.json.

If the issue is that you are installing all the dependencies every time in CI before building then you might need to rely on the functionality provided by your CI system to cache these between runs - a lot of existing CI systems do provide these: * Gitlab: https://docs.gitlab.com/ee/ci/caching/ * CircleCI: https://circleci.com/docs/2.0/caching/ * Travis: https://docs.travis-ci.com/user/caching/

However this comes with its own set of issues (e.g. parallel jobs where one or more is changing the dependencies).

We can try to explore having a command in Nx: sort of a "affected:dep-install" that will detect which packages to install as part of the affected command. Please create an issue for it here: https://github.com/nrwl/nx/issues

electrichead
  • 1,124
  • 8
  • 20
  • 3
    thanks for your answer. The problem is not with CI, but more for deployment. If I have an app with 500MB+ of dependencies and I need to write a microservice that work with the main app. It feel just wrong to install all packages for the microservice when it almost require no package. After some research, there's an open issue here: https://github.com/nrwl/nx/issues/1518 – N0Cloud Aug 27 '19 at 19:30
  • hmm, this should not affect deployment at all. When you build you would only bundle those dependencies that you use. In this example you would end up with two bundles; One fore your client app and a separate one for your microservice. The microservice would only have the code needed for it (and not include the client side code) – electrichead Aug 30 '19 at 02:11
  • Although you need to install the dependencies in order to start building, your artifact wouldn't contain your entire node_modules - only the code that you're actually using (via tree shaking) – electrichead Aug 30 '19 at 02:11
  • 6
    When you run a server like next.js you need to install production depdendencies to run the app, and the nx repo only has one list of them in the root dir, so you get everything. Now when you do this in a docker container you now have a 1~2GB image that could be just 200mb for a small service.This hurts especially if you want to run this image on a serverless platform that deals with cold starts. I agree NX should provide a better way to have a `install production dependencies only for this app` command – MakuraYami Oct 17 '20 at 13:05
  • 6
    Exactly like @MakuraYami said. Electrichead you are confusing the web app with the server app. You can't bundle all the server code into one js file same as for web apps. – Maciej Sikorski Oct 28 '20 at 17:37
0

Following up on Shlomi's answer - as workspace.json is now deprecated, generatePackageJson option moved to @nx/webpack:webpack package so a modern (as of 2023) way to make it work is to either:

  1. Define a default in nx.json:
{
  "targetDefaults": {
    "build": {
      "executor": "@nx/webpack:webpack",
      "options": {
        "generatePackageJson": true
      },
      // ...
    },
    // ...
  },
  // ...
}
  1. Define a project-specific setting in project.json:
{
  "targets": {
    "build": {
      "executor": "@nx/webpack:webpack",
      "options": {
        "generatePackageJson": true
      },
      //...
    },
    // ...
  }
  // ...
}
  1. Define a project-specific setting in package.json:
{
  "name": "...",
  "scripts": {
    // ...
  },
  "nx": {
    "targets": {
      "build": {
        "executor": "@nx/webpack:webpack",
        "options": {
          "generatePackageJson": true
        },
      },
      // ...
    },
    // ...
  },
  // ...
}
mjarosie
  • 3,228
  • 2
  • 20
  • 31