Search code examples
angulartypescriptnx-workspace

error TS2304: Cannot find name 'localStorage' on Angular app build in NX


I'm not able to run the 'build' command on an Angular app inside a NX workspace anymore. An error occurs while NX is building a dependent library that accesses 'localStorage' on the dom:

Executing task: npx nx run my-app:build --configuration=production 
  
   ×  1/20 dependent project tasks failed (see below)
   √  19/20 dependent project tasks succeeded [19 read from cache]

libs\my-lib\src\example-file.ts:43:5 error TS2304: Cannot find name 'localStorage'.

When I build the library that causes the issue alone (Without the Angular App), i don't get any error:

Executing task: npx nx run my-lib:build 

   √  8/8 dependent project tasks succeeded [8 read from cache]

 NX   Successfully ran target build for project my-lib and 8 tasks it depends on (1s)

The issue occurs both with 'production' and 'development' builds.

The issue only occurs with the 'build' command, everything works well with the 'serve' command.

I tried adding "lib": ["es2022", "dom"] on tsconfig.json and tsconfig.app.json of the app to allow access to the DOM. It doesn't solve the issue.

If I add "lib": ["es2022"] (without DOM) on tsconfig.lib.json of the library and build the library alone, the error occurs.

I tried adding "ssr": false and "prerender": false to project.json file of the angular app, as I have seen that some people get the issue while trying to access localStorage on Server Side Rendering.

Any help would be greatly appreciated.

Angular version: 18.2.10

NX version: 20.0.7

Typescript version: 5.5.4

project.json of the angular app:

{
  "name": "my-app",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "projectType": "application",
  "prefix": "app",
  "sourceRoot": "apps/my-app/src",
  "tags": [],
  "targets": {
    "build": {
      "executor": "@angular-devkit/build-angular:application",
      "outputs": ["{options.outputPath}"],
      "options": {
        "verbose": true,
        "outputPath": "dist/apps/my-app",
        "index": "apps/my-app/src/index.html",
        "browser": "apps/my-app/src/main.ts",
        "polyfills": [], 
        "tsConfig": "apps/my-app/tsconfig.app.json",
        "inlineStyleLanguage": "scss",
        "assets": [
          "apps/my-app/src/favicon.ico",
          "apps/my-app/src/assets"
        ],
        "styles": [
          "apps/my-app/src/styles.scss",
          {
            "input": "apps/my-app/src/assets/styles/themes/dark-cyan-theme.scss",
            "bundleName": "dark-cyan-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/dark-deep-purple-theme.scss",
            "bundleName": "dark-deep-purple-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/dark-grey-theme.scss",
            "bundleName": "dark-grey-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/dark-light-green-theme.scss",
            "bundleName": "dark-light-green-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/dark-pink-theme.scss",
            "bundleName": "dark-pink-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/dark-yellow-theme.scss",
            "bundleName": "dark-yellow-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/light-amber-theme.scss",
            "bundleName": "light-amber-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/light-blue-gray-theme.scss",
            "bundleName": "light-blue-gray-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/light-blue-theme.scss",
            "bundleName": "light-blue-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/light-indigo-theme.scss",
            "bundleName": "light-indigo-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/light-pink-theme.scss",
            "bundleName": "light-pink-theme",
            "inject": false
          },
          {
            "input": "apps/my-app/src/assets/styles/themes/light-teal-theme.scss",
            "bundleName": "light-teal-theme",
            "inject": false
          }
        ],
        "scripts": []
      },
      "configurations": {
        "production": {
          "budgets": [
            {
              "type": "initial",
              "maximumWarning": "500kb",
              "maximumError": "2mb"
            },
            {
              "type": "anyComponentStyle",
              "maximumWarning": "2kb",
              "maximumError": "4kb"
            }
          ],
          "outputHashing": "all",
          "ssr": false,
          "prerender": false 
        },
        "development": {
          "optimization": false,
          "extractLicenses": false,
          "sourceMap": true,
          "ssr": false,
          "prerender": false 
        }
      },
      "defaultConfiguration": "production"
    },
    "serve": {
      "executor": "@angular-devkit/build-angular:dev-server",
      "configurations": {
        "production": {
          "buildTarget": "my-app:build:production"
        },
        "development": {
          "buildTarget": "my-app:build:development"
        }
      },
      "defaultConfiguration": "development"
    },
    "extract-i18n": {
      "executor": "@angular-devkit/build-angular:extract-i18n",
      "options": {
        "buildTarget": "my-app:build"
      }
    },
    "lint": {
      "executor": "@nx/eslint:lint"
    },
    "test": {
      "executor": "@nx/jest:jest",
      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
      "options": {
        "jestConfig": "apps/my-app/jest.config.ts"
      }
    }
  }
}

Solution

  • I got a working solution, I replaced :

      "targets": {
        "build": {
          "executor": "@angular-devkit/build-angular:application",
          ...
        },
        "serve": {
          "executor": "@angular-devkit/build-angular:dev-server",
          ...
        },
      },
    

    with:

      "targets": {
        "build": {
          "executor": "@nx/angular:application",
          ...
        },
        "serve": {
          "executor": "@nx/angular:dev-server",
          ...
        },
      },
    

    in the project.json of the angular app