14

I am trying to use a very new third-party module in my project, which I installed using npm. The module was apparently developed on an OS with a case-insensitive file system, so it requires a file injectable.js whereas the actual file name is Injectable.js. This breaks the bundling process.

The developers of the module know of this issue. Meanwhile, I am trying to figure out how to use the module as it is. I am using Webpack for bundling my project.

The tree structure of the relevant part of my project is roughly this:

├──config
│     ├──webpack
│          ├──webpack.js
│
├──src
│   ├──client
│        ├──index.js
│
│
├──node_modules
│    ├──the module in question
│          ├── dist
│          │   ├── decorators
│          │   │   ├── providers
│          │   │         ├── Injectable.js
│          │   │
│          │   ├── index.js
|
├──gulpfile.js

The index.js file in the node_modules/the module in question/dist folder is requiring the file Injectable.js from the providers folder, but does so with the command require('./decorators/providers/injectable');

I would like to alias ./decorators/providers/injectable in that index.js with ./decorators/providers/Injectable.

Here is what I am doing in my webpack.js file:

resolve: {
        alias: {
            './decorators/providers/injectable': './decorators/providers/Injectable.js',
        },
}

But this still does not work; I am getting the error Module not found: Error: Cannot resolve 'file' or 'directory' ./decorators/providers/injectable

Could you please suggest how to replace one file name in a node module with another while bundling with Webpack?

UPDATE:

Here's webpack's config file:

var path = require('path');
var rucksack = require('rucksack-css')({
    fallbacks: true,
    autoprefixer: true
});
var precss = require('precss');
var csswring = require('csswring');
var webpack = require('webpack');

module.exports = {
    context: path.join(__dirname, '../../'),
    debug: false,
    entry: [
        './src/client/'
    ],
    output: {
        path: path.join(__dirname, '../../public/assets/js'),
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel?stage=1'
            },
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader!postcss-loader'
            },
            {test: /\.png$/, loader: 'file-loader'},
            {test: /\.gif$/, loader: 'file-loader'},
            {test: /\.jpe?g$/, loader: 'file-loader'},
            {test: /\.eot$/, loader: 'file-loader'},
            {test: /\.woff2?$/, loader: 'file-loader'},
            {test: /\.ttf$/, loader: 'file-loader'},
            {test: /\.svg$/, loader: 'file-loader'}
        ]
    },
    postcss: function () {
        return [rucksack, precss, csswring];
    },
    plugins: [
        new webpack.NormalModuleReplacementPlugin(
            /ng-forward\/dist\/decorators\/providers\/injectable\.js/,
            require.resolve('ng-forward/dist/decorators/providers/Injectable')
        )
    ],
    resolve: {
        extensions: ['', '.js']
    }
};
azangru
  • 2,644
  • 5
  • 34
  • 55

1 Answers1

24

Use webpack.NormalModuleReplacementPlugin:

plugins: [
  new webpack.NormalModuleReplacementPlugin(
    /ng-forward\/dist\/decorators\/providers\/injectable\.js/,
    require.resolve('ng-forward/dist/decorators/providers/Injectable')
  ),
],
Danil Gudz
  • 2,233
  • 16
  • 16
Alexandre Kirszenberg
  • 35,938
  • 10
  • 88
  • 72
  • Went ahead and tried that, but am still getting the error `ERROR in ./~/ng-forward/dist/index.js Module not found: Error: Cannot resolve 'file' or 'directory' ./decorators/providers/injectable in /node_modules/ng-forward/dist @ ./~/ng-forward/dist/index.js 125:37-81 – azangru Nov 02 '15 at 18:24
  • When you replace `require.resolve('...')` with `function() { console.log('called') }`, is "called" printed anywhere in your webpack output? – Alexandre Kirszenberg Nov 02 '15 at 21:24
  • I actually tried to do that to see what is passed as an argument to this function. But it did not get called. – azangru Nov 02 '15 at 21:30
  • It does get called for me. Make sure your RegExp is correct. You could also pass a RegExp that matches all (`/.*/`) as well as a `function(request)`, and inspect `request.resource` manually to find the actual path of `injectable.js`. You could then edit the RegExp to correctly match it. – Alexandre Kirszenberg Nov 02 '15 at 21:36
  • It's super weird, but even a regular expression that should match anything (`/.*/`) does not cause the function passed as a second argument to printo anything in the console. The relevant part of my webpack config is: `plugins: [ new webpack.NormalModuleReplacementPlugin( /.*/, function(request) {console.log('CALLED!', request)} ) ], `. Can't imagine what is it that I am doing wrong. – azangru Nov 02 '15 at 22:00
  • Could you add your entire `webpack.config.js` file to your question? Perhaps the `plugins` field gets overwritten later? – Alexandre Kirszenberg Nov 02 '15 at 22:13
  • Yep, I was overwriting the plugins in the general config in the production config :-) Now that I corrected that I am getting the error `TypeError: arguments[i].apply is not a function`. I added my general webpack config file to my question. – azangru Nov 02 '15 at 22:27
  • Ok, found and removed the cause of the TypeError, but now I'm back to square one: `ERROR in ./~/ng-forward/dist/index.js Module not found: Error: Cannot resolve 'file' or 'directory' ./decorators/providers/injectable in /home/andrey/development/vagrant/ehr-admin/node_modules/ng-forward/dist`. Will experiment with regular expressions. – azangru Nov 02 '15 at 22:35
  • Finally! The regex that finally did it was: `new webpack.NormalModuleReplacementPlugin( /decorators\/providers\/injectable/, require.resolve('ng-forward/dist/decorators/providers/Injectable') )`. The bundle got assembled successfully. Thank you so much! – azangru Nov 02 '15 at 22:43
  • 1
    This have worked to me, thanks! BUT.... why the `resolve.alias` approach do not work? (I have spent a lot of time with it before search and found your solution). At first glance it look much more obvious than the plugin method. – Gustavo Vargas Oct 01 '16 at 00:59