1

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?

Alana Storm
  • 164,128
  • 91
  • 395
  • 599
  • `import` compiles to `require`, there is no conflict; you can use both happily. Your issue is most likely expecting or using a non-existent global variable. – elclanrs May 15 '17 at 17:54
  • It also depends on how `helloWorld1` is being exposed. It has nothing to do w/ mixing and matching. – Dave Newton May 15 '17 at 17:57
  • @elclanrs Thank you for your attention -- but I've got a pretty simple example program above that doesn't seem to be working? – Alana Storm May 15 '17 at 18:06
  • @DaveNewton Thank you for your attention -- I have the source for helloWorld1 above -- does anything look wrong with the way its exposed? – Alana Storm May 15 '17 at 18:07

2 Answers2

3

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.

Michael Jungo
  • 31,583
  • 3
  • 91
  • 84
  • 2
    To be clear, ES6 created the distinction between "Module" and "Script" and a file being a "Module" makes it automatically strict, as you said. Webpack's decision to automatically treat files using `import` or `export` as a Module and things without that as Script is very much not part of the spec. In the future it may very well change. Node for instance will not do this. It will treat `.mjs` files as modules and `.js` files as scripts. Webpack and other tools may very well adopt that in the long run. Too early to say. – loganfsmyth May 16 '17 at 05:17
1

Webpack should not have any trouble mixing the different module syntaxes.

The problem is you implicitly declared helloWorld1 in an ES2015 module. These modules are in strict mode by default, which means you can not declare a variable like that in an ES2015 module.

Change your line to the line below, and I'm pretty confident your program will run.

let helloWorld1 = require('./hello-world');
Community
  • 1
  • 1
JJWesterkamp
  • 7,559
  • 1
  • 22
  • 28