Mike R Mike R - 9 days ago 6
AngularJS Question

How can I get webpack to find angular modules?

I'm trying to setup a bare-bones application with Angular 1 + Typescript 2 and Webpack. The app works fine until I try to use an external module, ex:

angular-ui-router
.

It always complains that it can't find the dependency:

ERROR in ./src/app.ts Module not found: Error: Cannot resolve module 'angular-ui-router' in ./src/app.ts 3:26-54


Demo showing problem: https://github.com/jxc876/angular-ts

I suspect I'm not importing the routing dependency correctly, tried:


  • import uiRouter from 'angular-ui-router';

  • import * as uiRouter from 'angular-ui-router'



Tried with
angular-route
and also
ui-router
but neither works. Tried
ts-loader
and
awesome-typescript-loader
.

App



import * as angular from 'angular';
import uiRouter from 'angular-ui-router';

let myApp = angular.module('myApp', [uiRouter]);

myApp.config(function($stateProvider) {
let homeState = {
name: 'home',
url: '/home',
template: '<div>It works !!!</div>'
}

$stateProvider.state(homeState);
});


Config



package.json

{
"name": "ts-demo",
"scripts": {
"start": "webpack-dev-server --content-base ./src"
},
...
"devDependencies": {
"@types/angular": "^1.5.16",
"@types/angular-ui-router": "^1.1.34",
"awesome-typescript-loader": "^3.0.0-beta.3",
"typescript": "^2.0.9",
"webpack": "^1.13.3",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"angular": "^1.5.8",
"angular-ui-router": "^0.3.1",
"enhanced-resolve": "^2.3.0"
}
}


webpack.config.js

module.exports = {
entry: './src/app',
output: {
filename: './dist/bundle.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
devtool: 'source-map',
module: {
loaders: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader'
}
]
}
};


tsconfig.json

{
"compilerOptions": {
"outDir": "./dist/",
"allowJs": true,
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"strictNullChecks": true,
"listFiles": true
},
"include": [
"./src/**/*"
],
"exclude": [
"node_modules"
]
}

Answer

Finally figured this out.

First issue is that the typescript compiler removes import statements that are not used.

The compiler detects whether each module is used in the emitted JavaScript. If a module identifier is only ever used in type annotations and never as an expression then no require call is emitted for that module. This culling of unused references is a good performance optimization, and also allows for optional loading of those modules.

source: https://github.com/Microsoft/TypeScript/issues/4717

I assigned the imported value to a dummy array and it seems to fix this. Logging the value out to the console also works. (See my final note on why I couldn't simply pass it into the dependency array).


Second, my typescript file was missing an empty string in the resolve array:

resolve { extensions: ['', '.ts', '.js'] }

Without this it couldn't pull in the file for ui router.

A few things I noticed while working on this: webpack --display-error-details is super useful. For some reason it was looking for double .js.js extensions inside node_modules/angular-ui-router/release:

resolve file
  /Users/mich2264/projects/angular-ts/node_modules/angular-ui-router/release/angular-ui-router.js.ts doesn't exist
  /Users/mich2264/projects/angular-ts/node_modules/angular-ui-router/release/angular-ui-router.js.js doesn't exist

--traceResolution is equally useful for typescript.


Finally, I'm not sure why but when I import the default value from angular-ui-router and I log it or set a breakpoint it shows up correctly as ui.router, but if I attempt to pass it into the dependency array it becomes undefined.

@types/angular-ui-router defines the following export inside their type file : export default "ui.router"; Which seems to cause issues when importing.