Search code examples
webpackwebpack-2umd

Module is not a loader must have normal or pitch function


I am using a lib that is distributed as umd modules and the code from one of the file i am importing looks like this

lib.js

(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['exports', '../utils/require-isdefined-plugin!lodash'], factory);
    } else if (typeof exports !== "undefined") {
        factory(exports, require('lodash'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod.exports, global.lodash);
        global.registry = mod.exports;
    }
})(this, function (exports, _lodash) {
    'use strict';
    // Library code
})

and now when i use this lib.js in my code and run webpack, it throws this error

Error: Module 'H:\Projects\abc\umd\app\utils\require-isdefined-plugin.js' is not a loader (must have normal or pitch function)

I think that webpack is treating "../utils/require-isdefined-plugin" as a loader and complaining.

My question is how can i let webpack know that this is not a loader and execute this file normally or

is there any other way to make this work?


Solution

  • The easiest and frankly best solution would be to use a different build. Most libraries nowadays have a UMD build as well as an npm package.

    If that is not an option you can use imports-loader to disable the AMD define as shown in Shimming - imports-loader, so webpack doesn't touch it and will use the commonjs version. You would add a rule for the library:

    {
      test: require.resolve('./path/to/lib'),
      loader: 'imports-loader?define=>false'
    }
    

    require.resolve works the same as the regular require but gives you the full path of the resolved module instead of its content, so you can still do require.resolve('lib') if that's how you imported it.

    To be safe you should also exclude the library from your regular .js rule, because having two rules for the same file usually doesn't end well. Your rules might look like this:

    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: [/node_modules/, require.resolve('./path/to/lib')]
      },
      {
        test: require.resolve('./path/to/lib'),
        loader: 'imports-loader?define=>false'
      }
    ]