Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack 2.0 with native ES6 modules: Uncaught TypeError: Cannot read property 'a' of undefined

Tags:

I just turned off modules in babel with the ["es2015", { "modules": false }] preset in order to leverage tree-shaking, and now my application, which worked perfectly before, is no longer loading. The console shows Uncaught TypeError: Cannot read property 'a' of undefined, and a white page is displayed.

Webpack 2.2.0-rc.1

like image 421
Espen H Avatar asked Dec 22 '16 19:12

Espen H


1 Answers

If you are using a babel plugin like "add-module-exports", you need to remove it, as webpack with native ES6 modules will not work with it enabled

If you are interested in why this happens, read on.

Findings:

Given an exported component like this

class TradeComponent extends React.Component {
// ...
}

export default TradeComponent;

Which is imported like this

import TradeComponent from 'components/Trade';

The exported component is compiled to this

/***/ "./components/Trade/index.js":
/* exports provided: default */
/* exports used: default */
/*!***********************************!*\
  !*** ./components/Trade/index.js ***!
  \***********************************/
/***/ function(module, exports, __webpack_require__) {

// ... Imports and component

var _default = TradeComponent; // _default = TradeComponent()
/* harmony default export */ exports["a"] = _default; // exports = Object {}
module.exports = exports['default']; // module = Object {i: "./components/Trade/index.js", l: false, exports: undefined, hot: Object, parents: Array[1]…}
// ^ Notice the module.exports = undefined above
;

var temp2 = // ... React hot loader things and end of component

Which results in a __webpack_require__ like this

// The require function
/******/    function __webpack_require__(moduleId) {

/******/        // Check if module is in cache
/******/        if(installedModules[moduleId])
/******/            return installedModules[moduleId].exports;

/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {},
/******/            hot: hotCreateModule(moduleId),
/******/            parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),
/******/            children: []
/******/        };

/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));

/******/        // Flag the module as loaded
/******/        module.l = true; // module = Object {i: "./components/Trade/index.js", l: true, exports: undefined, hot: Object, parents: Array[1]…}

/******/        // Return the exports of the module
/******/        return module.exports; // undefined
/******/    }

Which makes the component break like this

/***/ "./components/Trade/QuickTrade/BuyForm.js":
/* exports provided: default */
/* exports used: default */
/*!************************************************!*\
  !*** ./components/Trade/QuickTrade/BuyForm.js ***!
  \************************************************/
/***/ function(module, exports, __webpack_require__) {

"use strict";
// ... More imports
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9_components_Suggest__ = __webpack_require__(/*! components/Suggest */ "./components/Suggest/Suggest.js");
// __WEBPACK_IMPORTED_MODULE_9_components_Suggest__ = Object {}
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10_components_Trade__ = __webpack_require__(/*! components/Trade */ "./components/Trade/index.js");
// __WEBPACK_IMPORTED_MODULE_10_components_Trade__ = undefined

// ... The rest of the component

}(__WEBPACK_IMPORTED_MODULE_10_components_Trade__["a" /* default */]); 
// ^ This is where it breaks because components_Trade__ is undefined

If we add a named export, the issue is resolved, even without changing the import

export class TradeComponent extends React.Component {
// ...
}

export default TradeComponent;

Because it now looks like this

/***/ "./components/Trade/index.js":
/* exports provided: default */
/* exports used: default */
/*!***********************************!*\
  !*** ./components/Trade/index.js ***!
  \***********************************/
/***/ function(module, exports, __webpack_require__) {

// ... Imports and component

var _default = TradeComponent; // _default = TradeComponent()
/* harmony default export */ exports["a"] = _default; // exports = Object {}
// Notice the missing module.exports = exports["default"]; // undefined
;

var temp2 = // ... React hot loader things and end of component

Which results in a __webpack_require__ like this

// The require function
/******/    function __webpack_require__(moduleId) {

/******/        // Check if module is in cache
/******/        if(installedModules[moduleId])
/******/            return installedModules[moduleId].exports;

/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {},
/******/            hot: hotCreateModule(moduleId),
/******/            parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),
/******/            children: []
/******/        };

/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));

/******/        // Flag the module as loaded
/******/        module.l = true; // module = Object {i: "./components/Trade/index.js", l: true, exports: Object, hot: Object, parents: Array[1]…}

/******/        // Return the exports of the module
/******/        return module.exports; // module = Object {exports: Object{a:TradeComponent()}}
/******/    }
like image 196
Espen H Avatar answered Sep 22 '22 16:09

Espen H