81

I try to shorten my imports in typescript

from import {Hello} from "./components/Hello";

to import {Hello} from "Hello";

For that I found out you can use resolve.alias in webpack thus I configured that part as following

resolve: {
    root: path.resolve(__dirname),
    alias: {
        Hello: "src/components/Hello"
    },
    extensions: ["", ".ts", ".tsx", ".js"]
},

Webpack builds, and the output bundle.js works. However typescript's intellisense complain it cannot find the module

So my question is whether or not webpack's resolve.alias works with typescript?

I found following issue but there's no answer to it.

starcorn
  • 8,261
  • 23
  • 83
  • 124

9 Answers9

102

If you're using ts-loader, you might have to synchronize your webpack alias/resolve settings with your paths setting in your tsconfig.json.

{
    "compilerOptions": {
        "baseUrl": "./",
        "paths": {
            "Hello": ["src/components/Hello"]
        }
    }
}

If you're using awesome-typescript-loader, then webpack can figure this out automatically from the paths setting in your tsconfig.json, as per the status on this issue from the repo. That way, you don't need to duplicate the same information in your Webpack alias field.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Daniel Rosenwasser
  • 21,855
  • 13
  • 48
  • 61
  • 1
    Seems like I need to set the `paths` property also when I'm using `awesome-typescript-loader`. I'm using webpack1, and awesome-typescript-loader 1.1.1. But it works though :) – starcorn Nov 06 '16 at 15:19
  • 4
    This has gotten me for a second time now.. make sure you set the baseUrl if you're setting paths. You need both. – SgtPooki Apr 23 '17 at 07:05
  • new project with angular cli, adding app/components folder, moving the app.comonent under it in its own folder. tscinfig: adding baseUrl:"." and paths:{"~c": ["src/app/components"]} (c as components). adding index.d.ts with export "./app.component/app.component". npm install awesome-typescript-loader. vs code can resolve import {AppComponent} from "~c"; (mouse hover shows the correct path). ng build -> ERROR in C:/Temp/a4-cli-test/src/app/app.module.ts (4,30): Cannot find module '~c'. Did I miss something? – Drusantia Aug 12 '17 at 08:48
  • 1
    FWIW, I couldn't get this to work just when using the `TsConfigPathsPlugin ` [as documented on awesome-typescript-loader's README](https://github.com/s-panferov/awesome-typescript-loader#advanced-path-resolution-in-typescript-20), but synchronizing the config just like ts-loader seemed to work. – Shepmaster Oct 13 '17 at 03:05
  • This solved my problem: we were using a custom module syntax which defined aliases to files other than `index`. Renaming the files and fixing the aliases got the paths working. Thanks! – Alex Apr 10 '18 at 09:34
  • but what if I have a dynamic alias? – k102 May 03 '18 at 09:38
  • I'm experiencing the same issue but It seems like I have everything you suggested. Any advice https://stackoverflow.com/questions/51624134/aliasing-with-webpack-4-and-awesome-typescript-loader-not-working – darewreck Aug 01 '18 at 01:46
  • Also when you look at the bundle.js would you expect to see the alias in there or would you expect it to be converted to the mappings? – darewreck Aug 01 '18 at 01:47
  • To anyone trying to make this work with javascript files, you need to add the configuration to ` jsconfig.json` instead of `tsconfig.json` – Giovanni Benussi Feb 25 '20 at 18:21
93

You are missing one very important point in tsconfig.json: The matching pattern!

It should be configured like this:

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

The "*" is the important part to tell TS to match anything on the right side.

I found that out from this article: Type-safe es2015 module import path aliasing with Webpack, Typescript and Jest

NOTE

  • Make sure all your webpack.config.js are updated (e.g. if you use storybook).
  • If you use Visual Studio Code you may need to restart it, in order for the squiggly lines to disappear.
Anima-t3d
  • 3,431
  • 6
  • 38
  • 56
Caio Saldanha
  • 1,060
  • 7
  • 4
41

As others have mentioned, you need to provide an alias in your webpack.config.js:

    resolve: { 

        extensions: [".ts", ".js"],
        alias: {
            forms: path.resolve(__dirname, "src/forms/")
        } 
    },

This needs to be in synch with your tsconfig.json file (baseUrl and paths are required).

"compilerOptions":  {
    baseUrl: "./",
    ...
    paths: {
       "forms/*": ["src/forms/*"]
    }
}

Note: The wildcard pattern is necessary to match with your resolve alias configuration.

Then you can import any library using your alias:

import { FormsModule } from "forms/my-forms/my-forms.module";
Michele Riva
  • 552
  • 9
  • 24
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
  • Is there a way to configure webpack to also support it without tha slash `"~*": ["src/*"]` which is supported by TS (tsconfig.json) and VSCode? The result is `import x from '~components/x` which translates to `src/components/x`. – Qwerty Oct 03 '19 at 12:04
  • This is the only solution that works for me. Thanks. – zrna Jan 09 '20 at 09:27
  • This worked for me: Webpack 4.35.2 and Typescript 2.8 and AT-Loader 5.0 – andy Jun 02 '20 at 10:11
  • Worked for me, also check this out if you're getting related build errors for node_modules dependencies: https://github.com/netlify/netlify-lambda/issues/179#issuecomment-531468792 – helsont Jun 11 '21 at 21:39
12

You can also configure tsconfig-paths-webpack-plugin in order not to duplicate your aliases in several places. It will pick up aliases from tsconfig.json file and automatically add them to webpack.

ansavchenco
  • 535
  • 6
  • 14
10

If anyone still have this issue, don't forget to add your folder to the "include" option on tsconfig.json like this:

{
  "compilerOptions": {
    "sourceMap": true,
    "allowJs": true,
    "baseUrl": "./",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    "lib": [
      "es2016",
      "dom"
    ]
  },
  "outDir": "./built/",
  "include": [
    "./src/**/*",
    "./tests/**/*"
  ]
}
metal bar
  • 522
  • 3
  • 12
5

I had to make a small adjustment to Caio Saldanha's solution to make it work in my environment.

I am using Babel 7 with babel-plugin-module-resolver to resolve aliases. No ts-loader or awesome-typescript-loader as Babel 7 supports TypeScript out of the box using @babel/preset-typescript. I had to add an extra path configuration for each alias to load the module root (e.g. index.ts) automagically:

"baseUrl": ".",
"paths": {  // this must be synchronized with .babelrc.js's module-resolver alias config
    "component": ["src/component/index.ts"],
    "component/*": ["src/component/*"],
    ...
}

Having an index.ts in the /component folder with the following content:

export { default as Logo } from './Logo';

Without the extra .../index.ts line this import didn't work for me:

import { Logo } from 'component';  

Alias config in .babelrc.js:

plugins: [
[
    'module-resolver',
    {
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
        root: ['./src'],
        alias: {
        // this must be synchronized with tsconfig.json's path configuration
            component: './src/component',
        },
    },
],
AMilassin
  • 1,176
  • 16
  • 23
1

There are 2 cases

  1. When you write custom webpack It works with typescript but not directly. To explain, there are 2 types of compilation happening in backstage. First tsx -> js for which tsconfig.json plays the role, but when you actually compile the js code then webpack comes into picture. So for aliases, resolve should be placed at both places i.e in tsconfig and webpack to successfully run the application
  2. when you use default(after create react app): You just need to add "baseUrl": "./src" in tsconfig and see the code work.
Yash Agrawal
  • 464
  • 4
  • 11
0

It's not good practice to use alias for just 1 particular component and you should tell to webpack config that you have existing aliases setup in my ts-config by using tsconfig-paths-webpack-plugin, here is the sample config

// webpack.config.js
module.exports = {
  ...
  resolve: {
    plugins: [new TsconfigPathsPlugin({/* options: see below */})]
  }
  ...
}
//ts-config.json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "components/*": "components/*"
    ...
  },
  ...
}

and second solution, you might as well manual resolve the issue by specifying the aliases what you want in webpack.config, but if you don't want, you may follow the above config

// webpack.config.js
module.export = {
  resolve: {
    alias: {
      'components': path.resolve(__dirname, 'src/components')
    }
  }
}

remember the role of tsconfig or jsconfig is to provide an intellisense to your editor and give direction to your bundler

//ts-config.json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "components/*": "components/*"
    ...
  },
  ...
}

either what solution you chose, you should still use it as this

import {Home} from 'components';
...

and if you are out of your curiosity how webpack.config rely on your tsconfig.json, you may read ts-loader

Marvin
  • 647
  • 7
  • 15
-3

I think you can do this and have it work the way you describe:

resolve: {
    root: [
        path.resolve(__dirname),
        <path_to_components_directory> //e.g. path.resolve(__dirname, 'src', 'components')
    ], 
    extensions: ["", ".ts", ".tsx", ".js"]
},

Then you can do import {Hello} from "Hello";

I know I do this to resolve file paths in my src/js directory. I am not using typescript though, but I don't think it would affect the result.

Dimitris Karagiannis
  • 8,942
  • 8
  • 38
  • 63