user2771609
user2771609

Reputation: 1903

How do I get Webpack and Typescript to use an external node_module folder?

The Setup

I have the bluebird module along with @types/bluebird installed in a node_modules folder.

I also have some .ts files that will be bundled using Webpack and be used in a browser.

For various reasons the node_modules folder is outside the path hierarchy of my .ts files.

The Problem

I would like to import the bluebird module in my .ts files such that:

  1. I get the typings.
  2. Webpack will resolve the module and include it in the output bundle.

If the node_modules was in the right place in the path hierarchy I could simply do this:

import * as Promise from 'bluebird'

The Typescript compiler (through the ts-loader) resolves to the type definitions in node_modules/@types/bluebird and type checks the code and Webpack resolves to the actual module in node_modules/bluebird and emits it in the bundle.

With an external node_modules folder however, I cannot get this to work.

Approaches I Tried

So far I am able to get it so that Typescript is happy but not Webpack.

1. Setting baseURL and paths in tsconfig.ts

The most obvious solution to me seemed to be to set the baseURL and setup a paths into the node_modules in tsconfig.json like so (shared contains the node_modules folder):

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

However I am not able to do:

import * as Promise from 'shared/node_modules/bluebird'

I need:

import * as Promise from 'shared/node_modules/@types/bluebird/index'

But this import does not work for Webpack. It either can't find it, or if I configure it to find it, ts-loader will not like to compile it (because it is a declaration file), or if I configure it to ignore it, it will crash at runtime because it is not there.

2. Relative Import

I tried specifying a relative path in to the node_modules folder but ended up with roughly the same problem.

Upvotes: 4

Views: 3200

Answers (1)

user2771609
user2771609

Reputation: 1903

I employed a somewhat hacky solution to this problem.

The crux of the problem I was having was that I needed a single import statement to be resolved in different ways by Typescript and Webpack. Typescript needs to resolve it to the type definitions, and Webpack needs to resolve it to the module.

To acheive this I used paths in tsconfig.json to point the import to the type definitions, and resolve.alias in the webpack.config.js to point the same import to the acutal module.

tsconfig.json:

{
    "compilerOptions": {
        "baseUrl":"..",    // you need this to set paths below.
        "paths":{
             "shared/bluebird":["shared/node_modules/@types/bluebird/index"]
        }
        ...
    }
}

webpack.config.js

resolve: {
    alias: {
        "shared/bluebird": path.resolve(__dirname, '../shared/node_modules/bluebird')
    }
    ...
}

This allows me to do:

import * as Promise from 'shared/bluebird'

and Typescript and Webpack are both happy.

Upvotes: 3

Related Questions