2

I have set up an example project to demonstrate the issue:

https://github.com/garethrbrown/node-share-code

In this example there are two projects, example-api (a mini express project) and example-shared (a class library), both using Node JS / TypeScript. I want example-api to be able to use classes from example-shared to avoid code duplication. Having followed this example, I have referenced the example-shared project from package.json in example-api.

"dependencies": {
    "example-shared": "file:..\\example-shared",
    "express": "^4.17.1"
}

Having done this, and following running npm install, intellisense in VSCode sees ApiClass from the example-shared project and assists with the import.

enter image description here

I can then run by build command tsc --build via NPM, which succeeds.

I can also see that the sym link has been created in the example-api node_modules directory.

enter image description here

However, when I try to run the example-api project using the npm start script from under example-api, I get an error along the lines of:

  Error: Cannot find module 'example-shared/apiClass'
  Require stack:

  ...

  code: 'MODULE_NOT_FOUND',
  requireStack: [
    ...
  ]

I have tried running commands from different locations such as described here, but with no luck so far.

I'm using current stable versions of Node (14+) and NPM (7+).

I don't want to share via NPM or git repositories as I feel it will slow down development.

What am I doing wrong?

gbro3n
  • 6,729
  • 9
  • 59
  • 100

2 Answers2

1

Seems like this is a discussed problem, see this post Typescript: How to resolve absolute modules paths for node.js?

I did not investigate further, but in the example-shared folder you can remove "outDir" from your example-shared/tsconfig.json and then run npm run build. Unfortunately, this will emit the javascript files next to typescript files instead of placing them in a separate directory.

Finally, in the example-api run npm i, npm run build and npm start.

Now, Express will run because Node is using the javascript file instead of typescript file.

mtbno
  • 561
  • 7
  • 12
  • Thanks you. Your changes worked in that I was able to run the example-api project referencing the example-shared class and that does help my understanding. I'm surprised that there isn't a way out of the box to achieve the project structure I'm attempting. – gbro3n Mar 03 '21 at 19:19
  • 1
    It would be great if typescript supported this, I might look into this problem again when I have more time. So far you can try to compile your source code with webpack and ts-loader instead of using `tsc`, and maybe some webpack plugin can replace the module paths so that they point to a `dist` folder. Best of luck! – mtbno Mar 03 '21 at 21:01
  • Your advice would be appreciated if you do. I have looked into bit.dev, which looks comprehensive but quite heavy for sharing few classes between modules. In the meantime I'm going to opt for KISS and duplicate code, which isn't so terrible from a microservices point of view. – gbro3n Mar 04 '21 at 11:46
0

As per @mtbno's answer, the standard behavior without "outDir" is all js and map files will just be created next to each of your TypeScript files, which is super gross.

Without using some extra npm package or webpack or any of that, you can solve this by adding that "outDir" in your tsconfig, and then making a couple of tweaks to your package.json.

For argument's sake, say your root TypeScript file is called app.ts and your outDir folder is lib.

Relevant sections in your package.json can look like this:

  "scripts": {
    "build": "tsc --build",
    "clean": "tsc --build --clean",
    "start": "npm run build && node ./lib/app"
  },

and

"main": "./lib/app",

And here's an example tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "lib": ["es6"],
    "sourceMap": true,
    "outDir": "./lib",
  },
  "exclude": [
    "node_modules"
  ]
}

After those 2 files are updated, then running npm run start should build out your lib folder with the compiled JavaScript, and your server should start up successfully. Note that if you previously did a build and you have "old" .js and .map files next to your TypeScript files, you may have to delete those manually because npm run clean won't do it for you.

R-D
  • 566
  • 6
  • 13