Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • project_dir/app
  • project_dir/node_modules

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.

like image 243
marius Avatar asked Oct 20 '16 14:10

marius


3 Answers

Cannot find module

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

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

like image 199
Legends Avatar answered Nov 04 '22 12:11

Legends


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.

like image 28
marius Avatar answered Nov 04 '22 11:11

marius


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!

like image 2
E. Salazar Avatar answered Nov 04 '22 11:11

E. Salazar