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

3

6

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.

Unconquerable answered 9/9, 2021 at 0:20 Comment(3)
Congrats! You nailed it! I wonder if you could run "app-js" with ts-node, too. – Slaphappy
Very well-formulated question. I've been wondering the same. I think it may be up to whatever build system you're using (Vite, in my case), but I've added a bounty to see if anyone knows a good solution. – Theurgy
turborepo.org/blog/… I've followed this approach for frontend monorepo. Now all the packages included in the consuming applications just as a source code and it is responsibility of consuming application to bundle and build all the source files. For apps without bundling (backend) I would go with typescript project references approach and some lerna/nx task runner aware of project dependencies. – Hillis
H
0

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

Heliacal answered 31/1, 2022 at 14:22 Comment(2)
Sure, but then your compiled application is also going to be trying to import from src/index and ... that might actually be ok, it should compile away. Let me have a think. – Unconquerable
This will work, but I don't think it handles the "only use the TS version if you can" part of the question. The nice part about using the compiled version, as shown in the original question, is that you're only one change to package.json away from using the published package. With this, you tie yourself to always using the local version. But perhaps that's okay, having that type of portability might not be worth the extra effort. – Theurgy
C
0

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.

Carothers answered 6/2, 2022 at 14:9 Comment(0)
B
0

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.

Brindled answered 14/8, 2022 at 17:8 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.