Within in a monorepo, is it possible to configure a package to 'use the uncompiled code if you can'?

Viewed 340

I'm playing around with Yarn 2, and I want to do something like this.

I have a monorepo of the structure:

/
  packages/ 
    shared-ts/
       package.json
       src/
       lib*/ 
    app-ts/
       package.json
       src/
       lib*/ 
    app-js/ 
       package.json
       src/
       lib*/ 

where lib* denotes that the folder is gitignored, but is where the compiled code will live.

In this example, I have a dependency library shared-ts that is used by two apps, app-ts and app-js.

The conventional approach

The conventional approach to configuring a monorepo like this, is that in shared-ts I would have a package.json like:

"main": "lib/index.js"
"scripts" : {
    "build": "tsc" 
}

Where the build script will build index.js and index.d.ts into the lib folder.

When both app-ts and app-js then resolve the package, they look in the lib folder and find the index.js and in app-ts's case - the index.d.ts.

This works fine, except that the developers need to remember to run the build script if they have made changes to shared-ts in order for the changes to propagate across.

Where this could potentially become problematic is where there are many layers of dependencies.

Attempted work around 1 - point main to src/index.ts.

I can change shared-ts package.json to

"main": "src/index.ts"
"scripts" : {
    "build": "tsc" 
}

This generally won't work, a plain node process won't be able to parse the syntax in the .ts file (eg. the import keyword).

Potential workaround - publishConfig

So something I'm considering, but haven't tried yet is, using the publishConfig fields in the package.json

This field contains various settings that are only taken into consideration when a package is generated from your local sources (either through yarn pack or one of the publish commands like yarn npm publish).

"main": "src/index.ts", 
"publishConfig": {
    "main": "lib/index.js"
}

The idea being that:

  • When you publish a package to npm, lib/index.js will be used as main. code is ready for consumption, no compilation required.
  • If being used directly in the monorepo src/index.ts will be used as main. This kind of works as if you were running app-ts with ts-node for example.

However, where this starts breaking down is:

  • Running app-js in a development environment (where you don't have any additional syntax parsing set up).

Practical current best solution

My current best solution is to 'just give up on this 'no compile' aspiration' - if a developer makes changes to some code, they need to re-run build for the changes to propagate across.

3 Answers

How about using this?: import someValue from 'some-package/src/index';

I can do this in my monorepo like the image below

enter image description here

I believe using nx will be good choice here. While it won't help you run the uncompiled code, it has pretty good features. In particular, you can automatically run the affected:apps on certain changes. For example, if you have a start command, it will run the start command for all the affected apps.

I wanted the same thing but had to compromise on the "Automatic compilation on changes" option in my JetBrains IDE.

enter image description here

It allows me to debug with ts-node as well as run the code using the native node binary.

Related