Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@nx/esbuild tsconfig.app.json paths not included in output #22238

Closed
1 of 4 tasks
yohannpoli opened this issue Mar 8, 2024 · 6 comments
Closed
1 of 4 tasks

@nx/esbuild tsconfig.app.json paths not included in output #22238

yohannpoli opened this issue Mar 8, 2024 · 6 comments
Assignees
Labels
outdated scope: node Issues related to Node, Express, NestJS support for Nx type: bug

Comments

@yohannpoli
Copy link

yohannpoli commented Mar 8, 2024

Current Behavior

Path aliases are not correctly resolved when building application with options bundle "false" and format "cjs" which result in

Error: Cannot find module '@api/foo'
Require stack:
- /Users/yosh/Works/myorg/dist/apps/api/apps/api/src/index.js
- /Users/yosh/Works/myorg/dist/apps/api/main.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1134:15)
    at Function.Module._resolveFilename (/Users/yosh/Works/myorg/tmp/api/main-with-require-overrides.js:41:36)
    at Function.Module._load (node:internal/modules/cjs/loader:975:27)
    at Function.Module._load (/Users/yosh/Works/myorg/node_modules/@nx/js/src/executors/node/node-with-require-overrides.js:18:31)
    at Module.require (node:internal/modules/cjs/loader:1225:19)
    at require (node:internal/modules/helpers:177:18)
    at Object.<anonymous> (/Users/yosh/Works/myorg/apps/api/src/index.ts:6:46)
    at Module._compile (node:internal/modules/cjs/loader:1356:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1414:10)
    at Module.load (node:internal/modules/cjs/loader:1197:32)

This is because the output of the builded main.js does not include module from tsconfig.app.json

...
const manifest = [
  {
    module: '@myorg/lib1',
    exactMatch: 'libs/lib1/src/index.js',
    pattern: 'libs/lib1/src/index.ts',
  },
  {
    module: '@myorg/lib2',
    exactMatch: 'libs/lib2/src/index.js',
    pattern: 'libs/lib2/src/index.ts',
  },
];
...

Expected Behavior

I would expect not having an error when serving with custom application paths aliases

GitHub Repo

No response

Steps to Reproduce

  1. Create root tsconfig.base.json
{
  ...
  "compilerOptions": {
    ...
    "paths": {
      "@myorg/lib1": ["libs/lib1/src/index.ts"],
      "@myorg/lib2": ["libs/lib2/src/index.ts"]
    }
  },
  ...
}
  1. Create an application and overrides paths config
{
  "extends": "../../tsconfig.base.json",
  ...
  "compilerOptions": {
    ...
    "paths": {
      "@myorg/lib1": ["libs/lib1/src/index.ts"],
      "@myorg/lib2": ["libs/lib2/src/index.ts"],
      "@api/foo": ["apps/api/src/foo/index.ts"],
    }
  },
  ...
}
  1. Set build command in project.json of previously created application
  ...
  "build": {
    "executor": "@nx/esbuild:esbuild",
    "outputs": ["{options.outputPath}"],
    "defaultConfiguration": "development",
    "options": {
      "platform": "node",
      "outputPath": "dist/apps/api",
      "outputFileName": "main.js",
      "format": ["cjs"],
      "main": "apps/api/src/index.ts",
      "tsConfig": "apps/api/tsconfig.app.json",
      "assets": ["apps/api/src/assets"],
      "generatePackageJson": true,
      "esbuildOptions": {
        "sourcemap": true,
        "outExtension": {
          ".js": ".js"
        }
      }
    },
    "configurations": {
      "development": {
        "bundle": false,
        "metafile": true,
        "minify": false
      },
      "production": {
        "bundle": true,
        "minify": true,
        "esbuildOptions": {
          "sourcemap": false,
          "outExtension": {
            ".js": ".js"
          }
        }
      }
    }
  },
  ...
  1. Serve the application

Nx Report

Node   : 18.19.1
OS     : darwin-x64
npm    : 10.2.4

nx                 : 18.0.7
@nx/js             : 18.0.7
@nx/jest           : 18.0.7
@nx/linter         : 18.0.7
@nx/eslint         : 18.0.7
@nx/workspace      : 18.0.7
@nx/devkit         : 18.0.7
@nx/esbuild        : 18.0.7
@nx/eslint-plugin  : 18.0.7
@nx/node           : 18.0.7
@nrwl/tao          : 18.0.7
typescript         : 5.3.3

Failure Logs

No response

Package Manager Version

10.2.4

Operating System

  • macOS
  • Linux
  • Windows
  • Other (Please specify)

Additional Information

No response

@yohannpoli
Copy link
Author

yohannpoli commented Mar 12, 2024

After some investigations, it seems that the getTsConfigCompilerPaths function from packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.ts file only read Root tsconfig, maybe it's the source of the problem.

function getTsConfigCompilerPaths(context: ExecutorContext): {
  [key: string]: string[];
} {
  const tsconfigPaths = require('tsconfig-paths');
  const tsConfigResult = tsconfigPaths.loadConfig(getRootTsConfigPath(context));
  if (tsConfigResult.resultType !== 'success') {
    throw new Error('Cannot load tsconfig file');
  }
  return tsConfigResult.paths;
}

And the getRootTsConfigPath does not include the tsConfig options from project.json esbuild options

function getRootTsConfigPath(context: ExecutorContext): string | null {
  for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) {
    const tsConfigPath = path.join(context.root, tsConfigName);
    if (existsSync(tsConfigPath)) {
      return tsConfigPath;
    }
  }

  throw new Error(
    'Could not find a root tsconfig.json or tsconfig.base.json file.'
  );
}

@FrozenPandaz FrozenPandaz added the scope: node Issues related to Node, Express, NestJS support for Nx label Mar 15, 2024
@Gtosta96
Copy link

any news?

@hamishrose1
Copy link

hamishrose1 commented May 9, 2024

After some investigations, it seems that the getTsConfigCompilerPaths function from packages/esbuild/src/executors/esbuild/lib/build-esbuild-options.ts file only read Root tsconfig, maybe it's the source of the problem.

function getTsConfigCompilerPaths(context: ExecutorContext): {
  [key: string]: string[];
} {
  const tsconfigPaths = require('tsconfig-paths');
  const tsConfigResult = tsconfigPaths.loadConfig(getRootTsConfigPath(context));
  if (tsConfigResult.resultType !== 'success') {
    throw new Error('Cannot load tsconfig file');
  }
  return tsConfigResult.paths;
}

And the getRootTsConfigPath does not include the tsConfig options from project.json esbuild options

function getRootTsConfigPath(context: ExecutorContext): string | null {
  for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) {
    const tsConfigPath = path.join(context.root, tsConfigName);
    if (existsSync(tsConfigPath)) {
      return tsConfigPath;
    }
  }

  throw new Error(
    'Could not find a root tsconfig.json or tsconfig.base.json file.'
  );
}

I think this is the cause of my issue as well
It seems like the most basic build target ignores the tsconfig.json in the project

 "targets": {
    "build": {
      "executor": "@nx/esbuild:esbuild",
      "outputs": [
        "{options.outputPath}"
      ],
      "options": {
        "tsConfig": "{projectRoot}/tsconfig.json", 
        "outputPath": "{projectRoot}/dist/",
        "main": "dist/src/functions/*.js",
        "format": [
          "cjs"
        ],
        "generatePackageJson": true,
        "platform": "node"
      }
}

}

Error: Invalid config file due to following: No inputs were found in config file 'tsconfig.json'. Specified 'include' paths were
'["**/*"]' and 'exclude' paths were '[]'.

skipType check to bypass:

NX Build failed with 1 error:
error: Must use "outdir" when there are multiple input files
Error: Build failed with 1 error:

The most basic tsconfig.json

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "outdir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false
  },
  "include": ["**/*.ts"]
}

@jaysoo
Copy link
Member

jaysoo commented May 15, 2024

This is working as intended, as Nx treats the root tsconfig's compilerOptions.paths as the source of truth. Individual projects should not override compilerOptions.paths as TS will not merge them, and instead the ones from the app will override the root paths completely.

There is a proposal to allow merging options, but it is still just a proposal: microsoft/TypeScript#57486.

Any changes in this setup will require a larger design discussion. Feel free to open a discussion topic on it, as I don't see one that exists already.


Alternatively, you could use npm/yarn/pnpm workspaces to link your packages, which avoids compilerOptions.paths. Note that it doesn't currently have first-class support when generating libraries and apps, so you are going to have to generate things by hand, or write your own generators.

@jaysoo
Copy link
Member

jaysoo commented May 15, 2024

@hamishrose1 That sounds like a different issue. Make sure that your include/exclude is defined on the tsConfig file that the @nx/esbuild:esbuild executor is pointing to. By default this would be tsconfig.app.json, which has it's own include/exclude that overrides tsconfig.json.

If you continue to run into issue, please open a new issue with a repro linked so we can investigate. Thanks!

@jaysoo jaysoo closed this as completed May 15, 2024
Copy link

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated scope: node Issues related to Node, Express, NestJS support for Nx type: bug
Projects
None yet
Development

No branches or pull requests

5 participants