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

IMPORTANT: DO NOT USE! Use import mapping instead #113

Open
Nytelife26 opened this issue Feb 21, 2021 · 54 comments
Open

IMPORTANT: DO NOT USE! Use import mapping instead #113

Nytelife26 opened this issue Feb 21, 2021 · 54 comments

Comments

@Nytelife26
Copy link

A similar feature to this library is already available in node as a standard: import mapping.

Not only does it allow for directory mapping, but it also allows dependency aliasing, and works for both require and import (ESM) WITHOUT breaking resolution behaviour in production or other libraries like using this library does.

You have been warned.

I know this sounds hateful, however, that is not my intention. My intention is instead to spread awareness about this mostly undocumented feature (it is not shown in any package manifest documentation besides node's, and it is relatively tucked away) so people can write better software without needing to use hacky libraries like this one and without adding unnecessary dependencies.

@Kehrlann
Copy link
Collaborator

Kehrlann commented Feb 21, 2021

@Nytelife26 , thanks for raising awareness. This was introduced "recently", so on older versions of node, you might still want module-alias - therefore we probably won't just "deprecate" the package.

Would you mind opening a PR to update the README of this package, explaining that import mapping exists and should be used instead?

@Nytelife26
Copy link
Author

Nytelife26 commented Feb 21, 2021 via email

@nick-bull
Copy link

Further reading here and with a great example of directory mapping here. Hopefully this latter example clears up any confusion about the difference between "imports" and "exports" usage too

@Nytelife26
Copy link
Author

@nick-bull Thanks for the extra examples :) greatly appreciated

@nick-bull
Copy link

nick-bull commented Feb 22, 2021

An interest afterthought to replacing this module is that import mapping does not resolve directory imports, e.g. "#services/*": "./src/services/*.js" would not resolve import ... from '#services/someCoolService' to ./src/services/someCoolService/index.js.

You can get around this with "#services/*": "./src/services/*/index.js" but then that obviously doesn't work with non-index.js mappings.

The value is not really a regex, so something like "./src/services/*(/index)?.js" would not work. Directory-style imports with:

"#services/*": "./src/services/*.js"
import ... from '#services/someCoolService'

throws Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import ... is not supported resolving ES modules imported from ...

Anybody know a way around this?

@Nytelife26
Copy link
Author

Nytelife26 commented Feb 22, 2021

@nick-bull ..uh

"#services/*": "./src/services/*.js"

Of course it doesn't? That'd resolve to ./src/services/someCoolService.js
Use this instead:

"#services/*": "./src/services/*"

@nick-bull
Copy link

@nick-bull ..uh

"#services/*": "./src/services/*.js"

Of course it doesn't? That'd resolve to ./src/services/someCoolService.js
Use this instead:

"#services/*": "./src/services/*"

I have already suggested that in my comment; I've edited my response so it's a little clearer, as it was a bit densely packed, as it does not work, it throws an error

@Nytelife26
Copy link
Author

@nick-bull No, you did not already suggest what I said specifically. You suggested something similar, which was "#services/*": "./src/services/*.js" as aforementioned. Although, actually, that still works - you'll notice if you import #services/someCoolService/test, that does in fact resolve to ./services/someCoolService/test.js, for both require and import. And then if you do the other thing I suggested, "#services/*": "./src/services/*", you have to import #services/someCoolService/test.js to achieve the same result, but it will definitely work.

I hope that helps.

@nick-bull
Copy link

nick-bull commented Feb 23, 2021

@nick-bull No, you did not already suggest what I said specifically. You suggested something similar, which was "#services/*": "./src/services/*.js" as aforementioned. Although, actually, that still works - you'll notice if you import #services/someCoolService/test, that does in fact resolve to ./services/someCoolService/test.js, for both require and import. And then if you do the other thing I suggested, "#services/*": "./src/services/*", you have to import #services/someCoolService/test.js to achieve the same result, but it will definitely work.

I hope that helps.

You're right, I totally thought I'd written that example too and forgot to include it. I'm still not sure that answers my question though - is there a way to write a mapping that will allow both of the following:

import ... from '#coolService' // coolService/index.js
import ... from '#coolService/someFile.js' // coolService/someFile.js

Edit, scrap the above. It was because I had "type": "module" in package.json in my test project, causing it to throw the Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import ... is not supported resolving ES modules imported from .. I'd mentioned before. You'll either need transpilation or node --experimental-specifier-resolution=node .... Thanks Nytelife!

@Nytelife26
Copy link
Author

No worries @nick-bull. My answer if not for your discovery of needing to set the type to modules would've been to just import #coolService/index.js if it wouldn't work the conventional way anyways, but I'm glad you found your problem.

If you have any further questions or concerns let me know.

@thebrownfox
Copy link

This package didn't work for me no matter how I hard I tried to configure it. Maybe because I use ES6+ including imports (no single require() in my project) Builtin functionality works.

"imports": {
    "##/*": "./*"
},

jsconfig

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "##/*": ["./*"]
        }
    },
    "exclude": ["node_modules"]
}

usage

import { Model } from "##/api/models.js";

@Nytelife26
Copy link
Author

Nytelife26 commented Feb 27, 2021

@thefoxie thank you for the contribution :) however, this is not a place to report the package failing. I am glad the built-in functionality works, however, if you have any problems you should still create a separate issue so the ilearnio team can ensure the package works as intended for those who need it.

@Papooch
Copy link

Papooch commented Mar 8, 2021

After reading the documentation, I still don't understand how to use it... Could you please explain to me how can I convert this:

"_moduleAliases": {
    "@root": ".",
    "@submodules": "submodules",
    "@db": "src/db",
    "@middleware": "src/middleware"
  }

to use native import mapping instead? Preferably without changing any other code. Thanks.

@Nytelife26
Copy link
Author

@Papooch you will have to convert to using #alias instead of @alias, but that's it.

"imports": {
    "#root/*": "./*",
    "#submodules/*": "./submodules/*",
    "#db/*": "./src/db/*",
    "#middleware/*": "./src/middleware/*"
}

I hope that helps.

@Papooch
Copy link

Papooch commented Mar 9, 2021

Well that's what I tried also, but I am getting and error.

in C:\repos\project\src\db\connect.js, I am using

const { initModels } = require('#submodules/db-models/master');

But it throws an error, which I don't understand:

Error: Cannot find module 'C:\repos\project\submodules\db-models\master'
    at Object.<anonymous> (C:\repos\project\src\db\connect.js)

But the folder C:\repos\project\submodules\db-models\master DOES exist and has an index.js file in it which exports the initModels function.

Does folder mapping work differently to file mapping using this technique?

@nick-bull
Copy link

@Papooch You didn't happen to get burned in the same way as I did? Test by using

const { initModels } = require('#submodules/db-models/master/index.js');

@Papooch
Copy link

Papooch commented Mar 9, 2021

@nick-bull Well, that does seem to work, but I have to explicitly state the file, including the file extension. require('#submodules/db-models/master/index') does not work. I would have to change imports in the whole project and lose the flexibility along the way.

I would very much prefer to use a native solution instead of a library, but not in a way that makes my experience worse.

@nick-bull
Copy link

@Papooch I suspect you're being burned for the same reason as the prior mentioned comment, this feature isn't going to affect extension resolution. Try node --es-module-specifier-resolution=node, or install esm and use node -r esm. Report back and let us know if that works!

@initplatform
Copy link

I've gotten this to work as described above.

In my package.json

    "imports": {
        "#app/*": "./dist/app/*",
        "#lib/*": "./dist/lib/*",
        "#src/*": "./dist/*"
    },

then using node --es-module-specifier-resolution=node after compilation.

Where I am having issues, is when I try and use jest. Previously when using module-alias I could do the following in jest.config.ts

    moduleNameMapper: {
        '^#app/(.*)$': '<rootDir>/src/app/$1',
        '^#lib/(.*)$': '<rootDir>/src/lib/$1',
        '^#src/(.*)$': '<rootDir>/src/$1'
    },

but when I try and run tests, now, I am getting:

    Configuration error:

    Could not locate module #app/index.js mapped as:
    /Users/blah/src/app/$1.

    Please check your configuration for these entries:
    {
      "moduleNameMapper": {
        "/^#app\/(.*)$/": "/Users/blah/src/app/$1"
      },
      "resolver": undefined
    }

    > 1 | import { FastifyApp } from '#app/index.js';

It looks like it is looking for #app/index.js instead of #app/index.ts

If I do a quick hardcode hack, the test runs (I hardcode index.ts):

    moduleNameMapper: {
        '^#app/(.*)$': '<rootDir>/src/app/index.ts',
        '^#lib/(.*)$': '<rootDir>/src/lib/$1',
        '^#src/(.*)$': '<rootDir>/src/$1'
    },

...any ideas?

@Nytelife26
Copy link
Author

@Papooch if you wish to use extensions in the map to avoid having to specify .js you can. Although, as people have mentioned, it is better to set the module resolution to use node's.

@initplatform how are the imports specified in the actual files?

@initplatform
Copy link

Ha!
I was banging my head against the monitor for a good hour earlier before I wrote that post.
5 minutes after trying to respond to your question I found it. Thanks!

For whatever reason, when I was debugging the transition over to import mapping I had done this:

import { FastifyApp } from '#app/index.js';

instead of this:

import { FastifyApp } from '#app/index';

Can't even remember what I was testing... but I forgot to remove the .js after whatever I was doing.
Building and running worked fine, but jest exposed the error.

Sometimes it's the tiny things right :)

I am excited to see this import mapping land in node. At first I was averse to the # instead of using the @, but I kinda like it now. I am assuming it's to differentiate between npm namespaces and actual mappings...

Thanks to all involved that created module-alias and for your response @Nytelife26

@nick-bull
Copy link

@initplatform I'm not sure you'll need the index either, as I'm pretty sure directory imports are part of --es-module-specifier-resolution=node

@Nytelife26
Copy link
Author

No worries @initplatform. I give special credit to @nick-bull for the module resolution override because prior to that I was unaware it even existed honestly. I'm glad you found your solution, though!

@initplatform
Copy link

@initplatform I'm not sure you'll need the index either, as I'm pretty sure directory imports are part of --es-module-specifier-resolution=node

I believe that's an annoyance with typescript.

For whatever reason, if only using the typescript path alias, I need to specify index or typescript won't compile. I don't need to use index for nested routes though.

Screen Shot 2021-03-15 at 9 52 45 AM

Screen Shot 2021-03-15 at 9 55 44 AM

@nick-bull
Copy link

One other reason to keep maintaining this package is that import mapping only works for "type": "module", which isn't ideal for e.g., React Native

@Nytelife26
Copy link
Author

One other reason to keep maintaining this package is that import mapping only works for "type": "module", which isn't ideal for e.g., React Native

Is that so? Standard React and JSX relies on ESM, I cannot see why React Native wouldn't permit it.

@Griffork
Copy link

Griffork commented May 4, 2021

I've discovered that I might need to switch to es6 modules, and that module-alias seems to be not working. I stumbled across this thread and converted my project over to using the "imports" property in package.json, but I'm getting an error I can't solve:

Package.json:

"imports": {
    "#Common/*": "../Common/*.js",
    "#Typescript/*":  "../Typescript/*.js"
  }

Error:

Invalid "imports" target "../Common/*.js" defined for '#Common/*' in the package config [PathToRepo]\Server\package.json imported from [PathToRepo]\Server\server.js

Does this mean that the inbuilt "imports" property doesn't work outside the directory that the package.json is located within? Is there a work around for this? If not is there a way to make module-alias work with ES6 modules?

@Nytelife26
Copy link
Author

Nytelife26 commented May 5, 2021 via email

@FossPrime
Copy link

FossPrime commented May 7, 2021

I can't figureout how to get node 16 native ESM support to work with Mocha 8 and module-alias... So this is my only option

Error on node 16, mocha 8, type: "module"

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@src/common' imported from /src/mocking/reset.js
    at packageResolve (internal/modules/esm/resolve.js:655:9)
    at moduleResolve (internal/modules/esm/resolve.js:696:18)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
    at Loader.resolve (internal/modules/esm/loader.js:86:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:230:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:56:40)
    at link (internal/modules/esm/module_job.js:55:36)

mocha test wrapper

import moduleAlias from 'module-alias'
moduleAlias()

import test from '../app.test.js'
export default test

package.json

"_moduleAliases": {
    "@src": "./src"
},

reset.js

import { simple as logger } from '@src/common/Logger.js'

@Nytelife26
Copy link
Author

@Griffork That seems to be a relatively critical misunderstanding of how monorepositories work. They're packages within a package structure.

Common is not part of either package. So, instead, you should make the other packages depend on common, assuming common is its own package.

As to why that needs to be a "very arbitrary condition", how do you expect a package to work if it imports code that is neither bundled with the package nor depended on in the manifest?? If anyone installs that, it will break, guaranteed. Shared code and external libraries are common - that's why you can make them dependencies.

You should look into workspaces for your relevant node package manager and research further into monorepositories.

@prabhatCH
Copy link

A similar feature to this library is already available in node as a standard: import mapping.

Not only does it allow for directory mapping, but it also allows dependency aliasing, and works for both require and import (ESM) WITHOUT breaking resolution behaviour in production or other libraries like using this library does.

You have been warned.

I know this sounds hateful, however, that is not my intention. My intention is instead to spread awareness about this mostly undocumented feature (it is not shown in any package manifest documentation besides node's, and it is relatively tucked away) so people can write better software without needing to use hacky libraries like this one and without adding unnecessary dependencies.

However, this works fine for me. VS Code Intellisense will not resolve the imports. Is there any convenient workaround for that?

@Nytelife26
Copy link
Author

Nytelife26 commented May 26, 2021 via email

@cnm-n
Copy link

cnm-n commented Nov 27, 2021

@Nytelife26 Trying to switch to a node subpath imports, but for me it only works with the full path.

My imports:

  "imports": {
    "#utils/*": "./app/utils/*"
  }

Utils folder has two files: index.js and test.js, both has foo and bar functions.

My entry:

const {foo} = require('#utils');
const {bar} = require('#utils/test');
foo();
bar();

Both calls only work if I add the full path: #utils/index.js or #utils/test.js. Otherwise i have:

Package import specifier "#utils" is not defined in package C:\...\package.json imported from C:\...\test.js
and
Cannot find module 'C:\...\app\utils\test'

I have no "type": "module" enabled, and I tried "type": "commonjs" with no success. Also experimental-specifier-resolution does not help.

Any idea what I'm doing wrong?

@spence-s
Copy link

spence-s commented Jan 10, 2022

To see a working example of using subpath imports with index.js files in a commonjs environment - see the forwardemail.net repo

package.json

  "imports": {
    "#config/*": "./config/*.js",
    "#config": "./config/index.js",
    "#helpers/*": "./helpers/*.js",
    "#models/*": "./app/models/*.js",
    "#models": "./app/models/index.js",
    "#controllers/*": "./app/controllers/*.js",
    "#controllers": "./app/controllers/index.js",
    "#controllers/web": "./app/controllers/web/index.js",
    "#controllers/api": "./app/controllers/api/index.js"
  },

Many people are confused because using these import maps uses the same resolution logic as ESModules, which do not automatically resolve index.js files in the same way commonjs does. ESM requires the full path and extension to the file it is importing, and by extension so do the import maps here.

Using import maps like shown above will help you have a similar feel to commonjs. If you go deeper in the linked repo - you can see that this works.

Also note that the * in the imports does not have the same functionality as a glob star, which can be a bit confusing and may need some trial and error to set up your project correctly.

@viT-1
Copy link

viT-1 commented Jan 11, 2022

Best solution to solve aliases/paths in js projects for node scripts is using tsconfig-paths. For example.
Jest & Eslint have abilities to use tsconfig.json paths too.

@viT-1
Copy link

viT-1 commented Jan 11, 2022

Many people are confused because using these import maps uses the same resolution logic as ESModules, which do not automatically resolve index.js files in the same way commonjs does. ESM requires the full path and extension to the file it is importing, and by extension so do the import maps here.

@spence-s Yeah, I use vanilla nodejs, without bundlers, and I'm forced to use replace-in-file solution with regexp for solving extension & index addition & tsconfig-paths/register for node aliases. With ts-projects & ttsc we have more functionality with custom transformers which can do this work for us.

Using import maps like shown above will help you have a similar feel to commonjs. If you go deeper in the linked repo - you can see that this works.

How about glob paths? Something like that src/**/*

@viT-1
Copy link

viT-1 commented Jan 11, 2022

Another solution is tsc-alias which generates relative paths.
You can see my configuration for it.

@its-dibo
Copy link

A similar feature to this library is already available in node as a standard: import mapping.

Not only does it allow for directory mapping, but it also allows dependency aliasing, and works for both require and import (ESM) WITHOUT breaking resolution behaviour in production or other libraries like using this library does.

You have been warned.

I know this sounds hateful, however, that is not my intention. My intention is instead to spread awareness about this mostly undocumented feature (it is not shown in any package manifest documentation besides node's, and it is relatively tucked away) so people can write better software without needing to use hacky libraries like this one and without adding unnecessary dependencies.

unfortunately, the native imports mapping forces you to rewrite all of your path aliases to be start with '#' which breaks your codebase

@its-dibo
Copy link

Best solution to solve aliases/paths in js projects for node scripts is using tsconfig-paths. For example. Jest & Eslint have abilities to use tsconfig.json paths too.

this doesn't work if you set type: module in your package.json

@its-dibo
Copy link

its-dibo commented Feb 22, 2022

this will force you make some changes to your codebase that introduce breaking change

  1. you will need to change your alias to start with '#'
  2. es6 imports can't refer to a path outside your module i.e a parent director for monorepos

@jamesmortensen
Copy link
Contributor

For those who say changing '@' to '#' will break their codebase, is it possible for you to do a find/replace in your codebase to fix the imports? We've done something like that before when needing to do other sweeping changes across the codebase, and it's worked out quite well as long as there was a pattern we could match on initially.

@its-dibo
Copy link

For those who say changing '@' to '#' will break their codebase, is it possible for you to do a find/replace in your codebase to fix the imports? We've done something like that before when needing to do other sweeping changes across the codebase, and it's worked out quite well as long as there was a pattern we could match on initially.

the problem is not how to replace '@' by '#', the problem is in the project structure itself.

for example if you want to import a local package that is not published to npm and updated frequently without packing it everytime
you can add it's name to tsconfig path so @scope/package-name refers the location of the local package
and allows you to import it in your project like this

import something from `@scope/package-name

which will be replaced with the actual path.

changing '@' to '#' will not help

@eurostar-fennec-cooper
Copy link

eurostar-fennec-cooper commented Oct 5, 2022

One interesting thing I've come across recently when trying to run both tsc->node for the build/start script and ts-node for the dev script is that neither module-alias nor node.js' new import mapping support aliasing paths relative to the working directory.

For example, my src folder contains Typescript files. Package.json contains a _moduleAliases alias from "@" to "dist", which is the folder typescript will build to. This works perfectly fine, the start script is essentially node dist/index.

The issue occurs when running something like ts-node, the dev script is: ts-node src/index. However because module-alias is configured to alias to dist, at runtime ts-node cannot find modules as it's looking in the dist folder, but is operating out of the src folder.

In the end it was solved by using both module-alias and tsconfig-paths, the former using alias/paths config from package.json when running from dist/build folder. And the latter using alias/paths config from tsconfig.json when running from the src folder.

All of this module/path aliasing stuff makes things so much tidier, but all implementations seem to rely on aliases to a static path. Imagine if for some reason I needed two separate copies of my code in different src or dist/build folders, which current path aliasing solutions it's impossible; imports in "src2" would reference files in the src folder.

Edit: I've just spotted "tsc-alias" mentioned here, looking into it, it may be able to help with this issue.

@jlenon7
Copy link

jlenon7 commented Oct 19, 2022

@spence-s when you use the Node.js ESM import aliases in your code to import modules, does VSCode understand the type of the class or function that you are importing? In my case I can only get the type of the class or function if I use the real path to import modules:

// Does not work. VSCode does not show intellisense for Hello class.
import { Hello } from '#src/hello'

// Works
import { Hello } from './src/Hello.js'

@Spacey4K
Copy link

Spacey4K commented Oct 29, 2022

Would it be possible to resolve the path from subpath Imports?
Similar functionality as #33

For example if i have this import for assets:

"imports": {
    "#config": "./src/config.json",
}

How would i resolve the path to a variable?
Something as:

const path = getAliasPath("#config");
console.log(path); // "./src/config.json" or absolute path

Edit:

require.resolve('#config'); // absolute path to config.json

@spence-s
Copy link

@jlenon7 Yeah I don't think the path intellisense extensions support subpath imports, however, TS (and vscode ts linting) does. So while it won't help you autocomplete, it will help validate their existence and types.

@TheDirigible
Copy link

@Griffork That seems to be a relatively critical misunderstanding of how monorepositories work. They're packages within a package structure.

Common is not part of either package. So, instead, you should make the other packages depend on common, assuming common is its own package.

And what if Common is not it's own package? We should not be forced into anyone's idea of what a project should look like. Our project is NOT a distributed package, has complex needs, and one of those is to include files from libs outside the project. These libs are not in a package, and they need to be shared many places.

One solution is to put a symlink to outside the project, in the project root. However this is not ideal. If anyone knows another way to create an alias outside the project, please post it.

@jamesmortensen
Copy link
Contributor

@TheDirigible why not make Common into its own package so it can be added as a dependency? You of course can setup a project however you like. No one is trying to force anything, but I think the idea here is that NPM has features and functionality to include files and libs from outside the project, so that installing it is a one command operation. If it's possible to make those changes in the project to set it up to work with the existing tooling, then configuration and managing it could potentially be a lot easier.

@Nytelife26
Copy link
Author

Nytelife26 commented Nov 25, 2022

@eng-dibo

Local dependencies that aren't published to NPM are registered like this.

"dependencies": {
    "@some/package": "file:./path/to/package",
}

I'm not sure what makes you think you have to update your code for this, nor why you're using import aliases for local packages when the file dependency specifier has existed for quite some time now.

@Nytelife26
Copy link
Author

And what if Common is not it's own package?

Common was very clearly a package of some description in their example, seemingly as a shared library.

Aside from making everything you want to use an actual dependency, there is no solution that makes sense.
In fact, I'm not even sure why your structure exists. If you were to make the library a local package, you can import things from it in as many places as you want without needing to symlink or create aliases. Life makes more sense that way.

@deakjahn
Copy link

deakjahn commented Dec 24, 2022

@Nytelife26 I'm struggling with the same, and this is the first time I do this, so I might be mistaken, but I spent the better part of two days with this. It looks like the local dependency you mention has the significant drawback that the building process will not build the dependent project even if needed, It looks like the only way to make TSC build it automatically is to use project references. This is exactly cut out for directly this purpose (compartmentalize your own project, without the need of external dependencies, into subprojects that can reference each other and the build system will take care of the rest), and has been available since TS 3.0.

However, I have a problem with that approach you suggested. While IDE build and intellisensing works all right, running does not. As I can see now, tsconfig.json/paths is needed for the building (and it clearly accepts ../-ing out to a sibling folder), package.json/imports would be the counterpart for running (and it doesn't work with ../). We need both, obviously, because the transpiled files are in a location different from the source, however, both should work for project references to make any sense.

The only workaround I can see now is to cheat:

"imports": {
  "#other/module": "./other_link/out/whatever.ts"
},

where other_link is a symbolic link.

@deakjahn
Copy link

deakjahn commented Dec 25, 2022

I kept going on and I think I have the solution, without symlinks. It's rather fragile, in the sense that it needs a very carefully balanced folder structure to work.

I'll keep the client-server-common paradigm for the discussion, both the client and the server depending on the common project. Let's start with the topmost, "solution" folder.

Apart from other settings, it needs a tsconfig.json with -- to make sure TSC builds both dependent projects:

"references": [
  {
    "path": "./client"
  },
  {
    "path": "./server"
  },
 ]

And a package.json with -- to make sure the running code will be able to load the common module:

"imports": {
  "#common/foobar": "./out/common/src/foobar.js"
},

Both the client and the server packages need a tsconfig with -- to make sure that they get output to a common out folder, to help TS (IDE) to find the common module and to depend on it for the build process:

"compilerOptions": {
  "baseUrl": ".",
  "rootDir": "../",
  "outDir": "../out",
  "paths": {
    "#common/*": [
      "../common/src/*.ts"
    ]
  },
},
"references": [
  {
    "path": "../common"
  }
],

The common project needs a tsconfig with -- also to output to the same folder, and to act as an appropriate TSC --build dependent project:

"compilerOptions": {
  "baseUrl": ".",
  "rootDir": "../",
  "outDir": "../out",
  "composite": true,
  "declaration": true,
  "declarationMap": true,
},
"references": []

I found that if the outDir or rootDir folders have any other structure, the whole scheme falls apart.

External dependencies are left for the specific case, each subproject needs its own dependencies and the topmost package.json will also need the relevant packages in its node_modules.

@strblr
Copy link

strblr commented Sep 10, 2023

Life on easy mode for typescript users: use tsx as a runtime instead of node. Everything just works, no need for additional config besides the aliases defined in tsconfig.json, no need to emit any js file either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests