bs-ant-design icon indicating copy to clipboard operation
bs-ant-design copied to clipboard

ES6 default imports are broken in ParcelJS

Open johnhaley81 opened this issue 5 years ago • 5 comments

👋

Thanks for the bindings.

I tried to use them in a project that was bundled with ParcelJS and it wasn't able to use the bindings as they are defined. The default export is not pulled in correctly. For example, changing a binding from:

[@bs.module] external reactClass: ReasonReact.reactClass = "antd/lib/button";

to:

[@bs.module "antd/lib/button"] external reactClass: ReasonReact.reactClass = "default";

Fixed the issue.

johnhaley81 avatar Nov 05 '18 22:11 johnhaley81

I think this is Parcel not working correctly. antd/lib/button is a commonjs module by all means

thangngoc89 avatar Nov 05 '18 23:11 thangngoc89

It looks like it is using ES6 import/export syntax

And according to https://github.com/parcel-bundler/parcel/issues/1584#issuecomment-403265873 that import shouldn't work as it is not to spec.

johnhaley81 avatar Nov 06 '18 00:11 johnhaley81

@johnhaley81 you need to check the generated source. antd/lib/button is a commonjs module. I can't remember why I chose commonjs format of antd instead of es6 (it ships both format)

thangngoc89 avatar Nov 06 '18 05:11 thangngoc89

So I did some more research on what was happening and came across some madness.

How Import is breaking

I'm using "module": "es6" in my bsconfig.json which is outputting ES6 code.

This gives me an Antd_Button.js with:

// Generated by BUCKLESCRIPT VERSION 4.0.6, PLEASE EDIT WITH CARE

import * as Js_option from "bs-platform/lib/es6/js_option.js";
import * as Js_mapperRt from "bs-platform/lib/es6/js_mapperRt.js";
import * as ReasonReact from "reason-react/src/ReasonReact.js";
import * as Js_primitive from "bs-platform/lib/es6/js_primitive.js";
import * as Button from "antd/lib/button";

When we import antd/lib/button with the wildcard * the ES6 import spec says that you must get back an object. ParcelJS will force the module to be compliant to this if it is not an ES6 module. It checks this by looking at __esModule like so:

function _interopRequireWildcard(obj) { 
  if (obj && obj.__esModule) { 
    return obj; 
  } else { 
    var newObj = {}; 
    if (obj != null) { 
      for (var key in obj) { 
        if (Object.prototype.hasOwnProperty.call(obj, key)) { 
          var desc = Object.defineProperty && Object.getOwnPropertyDescriptor 
            ? Object.getOwnPropertyDescriptor(obj, key) 
            : {}; 
          if (desc.get || desc.set) { 
            Object.defineProperty(newObj, key, desc); 
          } else { 
            newObj[key] = obj[key]; 
          } 
        } 
      } 
    } 
    newObj.default = obj; 
    return newObj; 
  } 
}

Now, this is breaking because antd/lib/button already went through the conversion and is a commonjs file as you correctly asserted earlier:

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _button = require('./button');

var _button2 = _interopRequireDefault(_button);

var _buttonGroup = require('./button-group');

var _buttonGroup2 = _interopRequireDefault(_buttonGroup);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

_button2['default'].Group = _buttonGroup2['default'];
exports['default'] = _button2['default'];
module.exports = exports['default'];

Note the last line where module.exports = exports['default'] So ParcelJS is correctly seeing a commonjs file and is converting that back into an ES6 module since the code generated by bsb is expecting an ES6 module. Thus, when Button is referenced inside of Antd_Button.js it is actually the object of the ES6 module.

Conclusion

Currently, additional steps are required if the user is using bsb to compile to es6.

Workaround

Currently you can fix this by bringing in babel-plugin-import@^1.6.3, babel-preset-env@^1.6.1, babel-preset-react!^6.24.1 and set your .babelrc to use them. This will have ParcelJS force all of your code into commonjs. This seems a little convoluted however and it would be easier to just not use "module": "es6" at all unless you had to.

Possible fix?

Would it be possible to switch the bindings to all use antd/es6/*? Would that break bs modules that use commonjs?

johnhaley81 avatar Nov 06 '18 18:11 johnhaley81

@johnhaley81 Does jsx3 help this situation at all? https://github.com/Enalmada/bs-ant-design/pull/2

Enalmada avatar May 06 '19 03:05 Enalmada