0

I am trying to combine two require amd modules into one combined.js javascript file using Webpack.

module1.js

//module1.js - objectTest1
(function (root, factory) {
    'use strict';

    //Universal Module Definition
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.returnExports = factory();
    }
}(this, function () {
    'use strict';

     return function objectTest1() {
          var test = '1';
          return test;
     };
}));

module2.js

//module2.js - objectTest2
(function (root, factory) {
    'use strict';

    //Universal Module Definition
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.returnExports = factory();
    }
}(this, function () {
    'use strict';

     return function objectTest2() {
          var test = '2';
          return test;
    };
}));

Recommended good practice

In requireJS wiki and other sources, as a good practice, they explicitly recommend not to set a name for each module, but instead leave it anonymous without an id: https://github.com/requirejs/requirejs/wiki/Updating-existing-libraries#anon

"Normally you should not register a named module, but instead register as an anonymous module..."

WebPack - Combining the modules in one js file

[webpack.config.js]

module.exports= {
    entry: [
        "./modules/module1.js",
        "./modules/module2.js"
    ],
    output: {
        filename:"combined.js",
        libraryTarget: "umd",
        umdNamedDefine: true
    }
};

[Ejecute WebPack combine]

webpack.js
webpack 2.5.1
Time: 64ms
Asset     Size  Chunks             Chunk Names
combined.js  5.11 kB       0  [emitted]  main
   [0] ./modules/module1.js 551 bytes {0} [built]
   [1] ./modules/module2.js 551 bytes {0} [built]
   [2] multi ./modules/module1.js ./modules/module2.js 40 bytes {0} [built]

WebPack - Output - combined.js

https://pastebin.com/Dy9ZcgAc

Trying to load combined.js file and modules with RequireJS

[index.html]

require(["combined", "combined/modules/module1", "combined/modules/module2"], 
        function (combined, objectTest1, objectTest2) {
           //combined = objectTest1
           //
           //objectTest1 = objectTest1 - OK!
           //
           //objectTest2 = objectTest1 - **WRONG**
           //
        }
);

Problem

When loading the combined.js file, I am always getting the first anonymous module defined in the combined file. And I do not know how to get the second module, its never set in requireJS variable: window.requirejs.s.contexts._.defined

Additional Info

If I build the modules with a 'id name' in the define('name',..) of each module, it works perfectly, and I can load them perfectly, but as explained above, its not a good practice to name your modules.

Questions

  1. How can I combine those ANONYMOUS modules in one combined.js file, load that file with requireJS and then get each module?
  2. Could there be something wrong in the code?
  3. I have looked into the requireJS variable: window.requirejs.s.contexts._.defined to look for all the modules, but the second module is never added there. So I suppose it could be a problem of the UMD pattern I am using or a feature not supported by Webpack.

I am getting totally desesperate trying to solve it and already looked through many resources but could not find a clear answer. Thanks a lot

xtrm
  • 966
  • 9
  • 22

1 Answers1

0

I think I have found the reason why it does not work.

Once the webpack combined.js file is called with RequireJS, it will execute the line to return its own main entry point:

/******/    // Load entry module and return exports
/******/    return __webpack_require__(__webpack_require__.s = 2);

We have an array with position[0]=module1; position[1]=module2, and position[2]=webpack_entry_point. If we look at what those lines, its going to execute the webpack_entry_point code that we can see at the end of the file:

/***/ }),
/* 2 */
    /***/ (function(module, exports, __webpack_require__) {
    __webpack_require__(0);
    module.exports = __webpack_require__(1);
/***/ })

The last line: "module.exports = __webpack_require__(1);" is the important one, since its saying what module object is going to be returned. If we set it to "module.exports = __webpack_require__(0);" then objectTest1 will be returned, and we set it to "module.exports = __webpack_require__(1);" then objectTest2 will be returned, since module.exports cannot return 2 different things and would gets overwritten.

The solution to maintain compatibility with anonymous modules, would be to pass an identify string to webpack in the constructor to be able to handle which module to return, like the example above which is not supported at the moment:

require(["combined", "combined/modules/module1", "combined/modules/module2"], 
        function (combined, objectTest1, objectTest2) {
           //combined = objectTest1
           //
           //objectTest1 = objectTest1 - OK!
           //
           //objectTest2 = objectTest1 - **WRONG**
           //
        }
);

Going to try to add support to it and update this post once I get it working.

xtrm
  • 966
  • 9
  • 22