ilearnio / module-alias

Register aliases of directories and custom module paths in Node
MIT License
1.76k stars 69 forks source link

Using in both 'dev' and 'build' modes #103

Closed jazzfog closed 4 years ago

jazzfog commented 4 years ago

I've just installed module-alias and it works great with my TypeScript app using path aliases after I build the app.

tsconfig.json:

    "baseUrl": "./src",
    "paths": {
      "@src/*": ["./*"],
      "@utils/*": ["utils/*"]
    }

package.json

  "_moduleAliases": {
    "@src": "dist",
    "@utils": "dist/utils"
  },

However now dev mode the app is not working, it seems like module-alias completely takes over the path alias resolutions and even in dev mode the app tries to pull .js files from dist (instead of using .ts from src).

For development I use ts-node-dev:

ts-node-dev --respawn --no-notify -r tsconfig-paths/register ./src/index.ts

Am I doing something wrong?

Kehrlann commented 4 years ago

Hey @jazzfog 👋

This reminds me of a previous issue . Basically the gist of it was:

  1. Do not use module-alias
  2. Use typescript's config compilerOptions.paths instead
  3. And use the tsconfig-pathwhen running in prod mode

Here is a fully working example: https://github.com/Kehrlann/module-alias-74

I'm closing this as duplicate of #74 , but feel free to reopen if you think your case is different.

Cheers !

jazzfog commented 4 years ago

Thanks @Kehrlann, I will give it a shot. Thought I see that it will require customization to the command I use to start the app, if it is the case and I can't just run node dist/index.js then I could just probably customize my yarn start command starting my dev server and just add some ENV variable, then check it's existence in my code and omit module-alias/register then it should work in dev as well. It is even kinda better because it does not restrict you in the way you start the final build, if it makes sense.

jazzfog commented 4 years ago

Thank you @Kehrlann, it worked! One question though The lib's developers suggest to install it as a dev dependency npm install --save-dev tsconfig-paths while the recommended way of using it is to start your prod app specifying the lib as a requirement in the command line. node -r tsconfig-paths/register main.js. How so?

Kehrlann commented 4 years ago

Glad to hear it worked. Here's my understanding of that other module:

--dev

First, I don't understand why they suggest only installing it in --dev 🤔 I think it's because you would be doing the transforming of the paths as part of your compilation step (e.g. with babel or webpack), so that the compiled code would not have the aliases inside.

tsconfig.json

Here's my understand of how tsconfig.json and tsconfig-paths work. Here's the TypeScript doc:

The TypeScript compiler has a set of additional flags to inform the compiler of transformations that are expected to happen to the sources to generate the final output.

It is important to note that the compiler will not perform any of these transformations; it just uses these pieces of information to guide the process of resolving a module import to its definition file.

So basically the compilerOptions.paths in tsconfig.json just allows tsc to compile ; but does perform any transform.

tsconfig-paths

tsconfig-paths registers some extra imports just like module-alias would, except instead of getting aliases from package.json it gets them from tsconfig.json so it's nice and consistent. However, when you create an alias for your own files AND your run your project in dev mode with ts-node, the source files and compiled files have a different baseUrl (e.g. src vs dist), so tsconfig-paths cannot decide magically which one to take, hence prod-paths.js in my example.

If you don't want to update your start command with -r ./prod-paths.js, you can just put the code that's in that file inside your index.js. Basically -r is just doing a require before your main code runs.

jazzfog commented 4 years ago

Thanks again for the response! @Kehrlann !

Yeah, I think I understood how it works it's just --dev part that was unclear for me. I am still not sure what you mean by this

I think it's because you would be doing the transforming of the paths as part of your compilation step (e.g. with babel or webpack), so that the compiled code would not have the aliases inside.

How can I compile it so it transforms aliases to the real paths?

Kehrlann commented 4 years ago

A project source layout sometimes does not match that of the output. Usually a set of build steps result in generating the final output. These include compiling .ts files into .js, and copying dependencies from different source locations to a single output location. The net result is that modules at runtime may have different names than the source files containing their definitions. Or module paths in the final output may not match their corresponding source file paths at compile time.

The idea I get from the doc is that this transformation is not done by the TypeScript compiler, but by another step of the build process. So you need some other compile step, e.g. with Babel + a plugin, or Webpack, or a simple postbuild script that fixes your imports... Here's a sample article with some examples (that may or may not work, I haven't tested them). https://medium.com/analytics-vidhya/better-imports-with-typescript-aliases-babel-and-tspath-5c3addc7bc9e

jazzfog commented 4 years ago

Makes sense. Thank you!