Search code examples
javascriptwebpackecmascript-6commonjs

How does Webpack Handle mix-and-match Module Syntax


If I'm using webpack, I can create a program using CommonJS module syntax

#File: src-client/entry-point.js
helloWorld1 = require('./hello-world');    
alert(helloWorld1.getMessage());

#File: src-client/hello-world.js
var toExport = {};
toExport.getMessage = function(){
    return 'Hello Webpack';
}
module.exports = toExport;

I can also create a program using ES6/ES2015 module syntax.

#File: src-client/entry-point.js 
import * as helloWorld2 from './hello-world2';    
alert(helloWorld2.getMessage());

#File: src-client/hello-world2.js
var getMessage = function(){
    return 'Hello ES2015';
};
export {getMessage};

Both of the above programs compile and run (in browser) without issue. However, if I try to mix and match the syntax

#File: src-client/entry-point.js
helloWorld1 = require('./hello-world');
import * as helloWorld2 from './hello-world2';
alert(helloWorld1.getMessage());
alert(helloWorld2.getMessage());

Webpack itself will happily compile the program

$ ./node_modules/webpack/bin/webpack.js src-client/entry-point.js pub/bundle.js 
Hash: 1ce72fd037a8461e0509
Version: webpack 2.5.1
Time: 72ms
    Asset     Size  Chunks             Chunk Names
bundle.js  3.45 kB       0  [emitted]  main
   [0] ./src-client/hello-world.js 110 bytes {0} [built]
   [1] ./src-client/hello-world2.js 80 bytes {0} [built]
   [2] ./src-client/entry-point.js 155 bytes {0} [built]

but when I run the program in my browser, I get the following error

Uncaught ReferenceError: helloWorld1 is not defined
    at Object.<anonymous> (bundle.js:101)
    at __webpack_require__ (bundle.js:20)
    at toExport (bundle.js:66)
    at bundle.js:69

I didn't expect this to work (I'm not a monster), but it does raise the question of what, exactly, is going on.

When webpack encounters conflicting module syntax like this -- what happens? Does the presence of an import keyword put webpack into "parse ES2015" mode? Is there a way to force webpack to treat certain files as ES2015 and others as CommonJS? i.e. is there a way for webpack to seamlessly handle a project with modules using multiple standards? Or is the general feeling that you shouldn't do this?


Solution

  • The presence of import automatically puts the module in strict mode, as defined in the Spec. In strict mode you're not allowed to use a variable that hasn't been defined, whereas in regular mode the variable will implicitly become a global variable. You try to assign the result of require to helloWorld1 which was not previously defined. You need to declare that variable:

    const helloWorld1 = require('./hello-world');
    

    Instead of const you may also use let or var.