typescriptvisual-studioproject-reference

How to leverage dependencies in referenced TypeScript projects?


I'm trying to understand how to break apart my pretty large TypeScript section of a SPA (React with Asp Net 6 as backend).

Let's consider this basic structure:

WebAppSolution
  SharedProject
    lib
      (TS sources)
    node_modules
    tsconfig.json
    package.json

  WebAppProject
    (C# sources)
    Scripts
      (TS sources)
    node_modules
    tsconfig.json
    package.json
    webpack.config.js

I mean that WebAppSolution includes WebAppProject and they live in a dedicated repo. SharedProject will have its own repo and it is referred by the solution. Moreover, SharedProject is meant as a general-purpose project reusable by other applications. In short, SharedProject should act as a NPM package for WebAppProject, but without the hassle of publishing it at every single modification (actually I'll have several shared projects to refer).

So far, I've been able to make it work something.

In SharedProject I have just this basic service to expose. Of course, the project has lodash as npm installed dependency:

import * as _ from "lodash";

export function sum(a: number, b: number): [number, boolean] {
    const result = a + b;
    return [
        result,
        _.isFinite(result)
    ]
}

On the other side, in WebAppProject I have a script which consumes the service:

import * as myLib from "../../SharedProject/lib";

const a = 10;
const b = 25;
const result = myLib.sum(a, b);

console.log(`Ciao: ${result[0]}; ${result[1]}; ${ia}`);

Everything works perfectly.

The problem happens when I try to leverage lodash from the SharedProject instead of installing in the WebAppProject as well. I cannot figure how to solve it (whereas it is possible).

import * as myLib from "../../SharedProject/lib";
import * as _ from "lodash";  //error TS2307: Build:Cannot find module 'lodash'...

const a = 10;
const b = 25;
const result = myLib.sum(a, b);

const ia = _.isArray([]);

console.log(`Ciao: ${result[0]}; ${result[1]}; ${ia}`);

I tried also by expliciting the lodash path, but I would avoid to specify this info in every single module. At config level would be perfectly acceptable, instead.

import * as myLib from "../../SharedProject/lib";
import * as _ from "../../SharedProject/node_modules/lodash";

const a = 10;
const b = 25;
const result = myLib.sum(a, b);

const ia = _.isArray([]);

console.log(`Ciao: ${result[0]}; ${result[1]}; ${ia}`);

This works, however there's no symbols available for lodash.

If I install lodash as dependency also in the WebAppProject, it works, but then the resulting bundle actually embeds the library twice and that's not acceptable. Note that I say "bundle", because the resulting script is bundled via webpack at the WebAppProject level, then served to the browser.

Finally, is there a way to leverage the already installed npm's, together with the symbols? Is this approach worthwhile or are there suggestion to manage in a different way?


Solution

  • Okay, I figured it out.

    In the WebAppProject's package.json the dependencies should be added and should point to the related SharedProject folder:

      "devDependencies": {
        "clean-css": "^5.2.4",
        ...
        "webpack-cli": "^4.5.0",
        "webpack-merge-and-include-globally": "^2.3.3",
        "@types/lodash": "file:../SharedProject /node_modules/@types/lodash"
      },
      "dependencies": {
        "@babel/runtime": "^7.18.9",
        "lodash": "file:../SharedProject /node_modules/lodash"
      }
    

    Also important to run npm install for this package.

    More info here: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#local-paths