marius
marius

Reputation: 1613

Cannot find module with Webpack, Typescript, custom module directory

What I'm trying to do

I am wrote a dummy module my-component which essentially exports a single class Something. I placed it in app/modules/. Now I am tying to access it using the import Syntax from app/app.js:

import { Something } from 'my-component';

Expectation: With my current Webpack configuration (below) I would expect this to work.

Actual: This throws the error:

ERROR in [default] /<project_dir>/app/app.ts:1:26
Cannot find module 'my-component/Something'.

What I tried to fix it

I know the module in itself is defined correctly, because

  1. I can import it using a relative path: import { Something } from './my-component'
  2. I can import it as-is, if I move the module to node_modules/my-component.

The only combination that fails is importing it without a relative path from my modules/ directory. So I think the issue might be my Webpack configuration.

Setup Details

As you can see below, I have two directories listed as resolve.root:

It seems to manage to resolve from node_modules, just not from app.

Project layout

                               Webpack
project_dir/
 ├── app/                      context, resolve.root
 │    ├── app.ts
 │    └── my-component/
 │         ├── index.ts
 │         └── Something.ts
 ├── webpack.config.js
 ├── node_modules/             resolve.root
 │    ├── ...
 │    ├── ...
 │    └── ...
 └── dist/
      └── ...

app/app.ts

import { Something } from 'my-component/Something';

app/my-component/index.ts

export { Something } from './Something'

app/my-component/Something.ts

class Something {
}

export { Something };

webpack.config.js

var path = require('path'),
  ROOT = path.resolve(__dirname, '.');

module.exports = {
  context: path.resolve(ROOT, 'app'),
  entry: 'app.ts',
  output: {
    path: path.resolve(ROOT, 'dist'),
    filename: '[name]-[hash].js'
  },
  module: {
    loaders: [
      { test: /\.ts$/, loader: 'awesome-typescript' }
    ]
  },
  resolve: {
    root: [
      path.resolve(__dirname, 'app'),
      path.resolve(__dirname, 'node_modules')
    ],
    extensions: [
      '', '.ts', '.js'
    ]
  }
};

EDIT Fixed the project layout.

Upvotes: 7

Views: 18704

Answers (3)

Legends
Legends

Reputation: 22662

Cannot find module

If you experience this issue with dynamic module loading using ESNEXT,

you have to add "moduleResolution": "node" to your tsconfig.json.

Upvotes: 15

marius
marius

Reputation: 1613

I found an easier solution than the previously accepted one:

In your typescript configuration, set the baseUrl in the compilerOptions:

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "./app",
    ...
  },
  ...
}

Explanation:

Webpack and Typescript use node module resolution by default, which is fine. When setting up custom module folders though, you need to configure them in both the Webpack and the Typescript config. Changes to the Webpack module resolution config are not propagated to the Typescript compiler.

Upvotes: 6

E. Salazar
E. Salazar

Reputation: 93

Ok. I created a replica of your project structure. It seems that the case is that the import statement does not behave the same as the require, AND, webpack resolve.root config works as expected with it.

For the modules, change your import statements to require like this:

app.ts

// Define require function for TypeScript to know that it
// will exist at runtime
declare function require(name:string);
// Require your module
var Something = require('my-component/Something');
// var myComponent = require('my-component');

my-component/Something.ts

// Export something (used a function to test)
export function Something() {
    console.log("Hello");
}

my-component/index.ts

// Definition of require function as mentioned before
declare function require(name:string);
// Passing other modules
var exportedModules = {
    Something: require("my-component/Something")
};
export default exportedModules;

Like this, it will work without problems and resolve with the module names as you defined in Webpack. Unfortunately, I couldn't achieve it with the import.

I pushed the solution to a repository. Check it out if you need!

Upvotes: 2

Related Questions