nrwl / nx

Smart Monorepos · Fast CI
https://nx.dev
MIT License
22.76k stars 2.27k forks source link

@nx/esbuild:esbuild `declarations: true` does not include tsconfig path mappings for buildable libraries #26376

Open danielsharvey opened 1 month ago

danielsharvey commented 1 month ago

Current Behavior

Recently, the capability to add declarations generation to an esbuild build - see https://github.com/nrwl/nx/pull/21084 (thanks!).

However, when generating declarations/typings using the @nx/esbuild:esbuild executor the build does not correctly reference buildable libraries in the generated tsconfig.json.

The @nx/js:tsc and other bundlers like @nx/vite and @nx/rollup do this correctly - I include a patch which adds this to the @nx/esbuild:esbuild executor below.

It is also noted that the @nx/esbuild:esbuild plugin does not exclude buildable libraries when bundling though this can be achieved via configuration using the external build option for the executor.

Specifically, for this esbuild build target:

    "build": {
      "executor": "@nx/esbuild:esbuild",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "platform": "node",
        "outputPath": "dist/apps/esbuild-dependencies-repro",
        "format": ["cjs"],
        "bundle": true,
        "external": [
          "@esbuild-dependencies-repro/mylib"
        ],
        "declaration": true,
        "declarationRootDir": "apps/esbuild-dependencies-repro/src",
        "main": "apps/esbuild-dependencies-repro/src/main.ts",
        "tsConfig": "apps/esbuild-dependencies-repro/tsconfig.app.json",
        "assets": ["apps/esbuild-dependencies-repro/src/assets"],
        "generatePackageJson": true,
        "esbuildOptions": {
          "sourcemap": true,
          "outExtension": {
            ".js": ".js"
          }
        }
      },
      ...
    }

With reference to the above:

  1. Note declaration and declarationRootDir defined to have tsc output declarations/typings during the build.
  2. Note that bundling is enabled.
  3. Note the external configuration is used to exclude the buildable library(s) used by the app.

When this build is run it produces an error similar to:

> nx run esbuild-dependencies-repro:build:production

apps/esbuild-dependencies-repro/src/main.ts:1:23 - error TS6059: File 'mylib/src/index.ts' is not under 'rootDir' '/Users/daniel/projects/tmp/esbuild-dependencies-repro/apps/esbuild-dependencies-repro/src'. 'rootDir' is expected to contain all source files.

> 1 | import { mylib } from "@esbuild-dependencies-repro/mylib";
    |                       ^
  2 | 
  3 | console.log('Hello World' + mylib());
  4 | 

mylib/src/index.ts:1:15 - error TS6059: File '/Users/daniel/projects/tmp/esbuild-dependencies-repro/mylib/src/lib/mylib.ts' is not under 'rootDir' '/Users/daniel/projects/tmp/esbuild-dependencies-repro/apps/esbuild-dependencies-repro/src'. 'rootDir' is expected to contain all source files.

> 1 | export * from './lib/mylib';
    |               ^
  2 | 

Found 2 errors.

Expected Behavior

Declarations should build appropriately, with Nx utilising the dependency graph to correctly map buildable libraries as it does in other parts of the system.

e.g. the @nx/js:tsc and other bundlers like @nx/vite and @nx/rollup do this correctly.

GitHub Repo

https://github.com/danielsharvey/esbuild-dependencies-repro.git

Steps to Reproduce

# Clone the project
git clone https://github.com/danielsharvey/esbuild-dependencies-repro.git

# install the packages
cd esbuild-dependencies-repro
npm i

# Run build and observe reproduction of error
npx nx run esbuild-dependencies-repro:build

I implemented the foreshadowing of a fix, which you can apply and test as follows:

npx patch-package
npx nx run esbuild-dependencies-repro:build

The patches as follows:

Daniels-MBP:esbuild-dependencies-repro daniel$ npx patch-package
patch-package 8.0.0
Applying patches...
@nx/esbuild@19.1.2 ✔
@nx/js@19.1.2 ✔

Nx Report

NX   Report complete - copy this into the issue template

Node   : 18.20.1
OS     : darwin-arm64
npm    : 10.5.0

nx (global)        : 19.1.0
nx                 : 19.1.2
@nx/js             : 19.1.2
@nx/jest           : 19.1.2
@nx/linter         : 19.1.2
@nx/eslint         : 19.1.2
@nx/workspace      : 19.1.2
@nx/devkit         : 19.1.2
@nx/esbuild        : 19.1.2
@nx/eslint-plugin  : 19.1.2
@nx/node           : 19.1.2
@nrwl/tao          : 19.1.2
typescript         : 5.4.5
---------------------------------------
Registered Plugins:
@nx/eslint/plugin
@nx/jest/plugin

Failure Logs

Daniels-MBP:esbuild-dependencies-repro daniel$ npx nx run esbuild-dependencies-repro:build

   ✔  1/1 dependent project tasks succeeded [0 read from cache]

   Hint: you can run the command with --verbose to see the full dependent project outputs

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

> nx run esbuild-dependencies-repro:build:production

apps/esbuild-dependencies-repro/src/main.ts:1:23 - error TS6059: File 'mylib/src/index.ts' is not under 'rootDir' '/Users/daniel/projects/tmp/esbuild-dependencies-repro/apps/esbuild-dependencies-repro/src'. 'rootDir' is expected to contain all source files.

> 1 | import { mylib } from "@esbuild-dependencies-repro/mylib";
    |                       ^
  2 | 
  3 | console.log('Hello World' + mylib());
  4 | 

mylib/src/index.ts:1:15 - error TS6059: File '/Users/daniel/projects/tmp/esbuild-dependencies-repro/mylib/src/lib/mylib.ts' is not under 'rootDir' '/Users/daniel/projects/tmp/esbuild-dependencies-repro/apps/esbuild-dependencies-repro/src'. 'rootDir' is expected to contain all source files.

> 1 | export * from './lib/mylib';
    |               ^
  2 | 

Found 2 errors.

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 NX   Ran target build for project esbuild-dependencies-repro and 1 task(s) they depend on (1s)

   ✖  1/2 failed
   ✔  1/2 succeeded [0 read from cache]

Package Manager Version

No response

Operating System

Additional Information

I've included a patch-package patch which suggests a solution.

It patches the executor runTypeCheck() method to use the calculateProjectBuildableDependencies() to extract the mappings; see

The @nx/vite plugin: https://github.com/nrwl/nx/blob/260562e484c09b81a82c980272e8f8f50889718c/packages/vite/src/utils/executor-utils.ts#L39-L57

The @nx/rollup plugin: https://github.com/nrwl/nx/blob/260562e484c09b81a82c980272e8f8f50889718c/packages/rollup/src/executors/rollup/rollup.impl.ts#L91-L101

I suspect this should be applied to the esbuild executor to automatically generate esbuild external configuration (optionally).

I am happy to work on a PR though am interested in guidance on the approach and other considerations from the Nx team before proceeding.

danielsharvey commented 1 month ago

I am just flagging the buildLibsFromSource discussion - https://github.com/nrwl/nx/discussions/23370 ("Add build "buildLibsFromSource" option to the esbuild executor") as a related issue.