Skip to content

Commit

Permalink
Expose all built-in options for getConstructor
Browse files Browse the repository at this point in the history
Quoting reactjs#264 (comment)

> Regarding `Encountered error "#<ExecJS::ProgramError: Invariant
> Violation: Element type is invalid: ...`:
>
> I think one of the core issues is that [module lookup uses
> `try...catch`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> While the errors are logged to the console shim, that typically doesn't
> help as a later error (such as the invariant violation) will lead to a
> fatal error (triggering a 500). If that could be refactored to be a bit
> more intentional based on environment (instead of just reacting based on
> exceptions, or at the very least, throwing if the caught exception isn't
> very specific)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
  • Loading branch information
hibachrach committed Jan 10, 2020
1 parent 43b97a5 commit 1a76ee9
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 62 deletions.
148 changes: 86 additions & 62 deletions react_ujs/dist/react_ujs.js
Expand Up @@ -7,7 +7,7 @@
exports["ReactRailsUJS"] = factory(require("react"), require("react-dom"), require("react-dom/server"));
else
root["ReactRailsUJS"] = factory(root["React"], root["ReactDOM"], root["ReactDOMServer"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__) {
})(this, function(__WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__, __WEBPACK_EXTERNAL_MODULE_6__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
Expand Down Expand Up @@ -73,7 +73,7 @@ return /******/ (function(modules) { // webpackBootstrap
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 6);
/******/ return __webpack_require__(__webpack_require__.s = 7);
/******/ })
/************************************************************************/
/******/ ([
Expand Down Expand Up @@ -106,13 +106,43 @@ module.exports = function(className) {

/***/ }),
/* 1 */
/***/ (function(module, exports) {

// Load React components by requiring them from "components/", for example:
//
// - "pages/index" -> `require("components/pages/index")`
// - "pages/show.Header" -> `require("components/pages/show").Header`
// - "pages/show.Body.Content" -> `require("components/pages/show").Body.Content`
//
module.exports = function(reqctx) {
return function(className) {
var parts = className.split(".")
var filename = parts.shift()
var keys = parts
// Load the module:
var component = reqctx("./" + filename)
// Then access each key:
keys.forEach(function(k) {
component = component[k]
})
// support `export default`
if (component.__esModule) {
component = component["default"]
}
return component
}
}


/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

var nativeEvents = __webpack_require__(7)
var pjaxEvents = __webpack_require__(8)
var turbolinksEvents = __webpack_require__(9)
var turbolinksClassicDeprecatedEvents = __webpack_require__(11)
var turbolinksClassicEvents = __webpack_require__(10)
var nativeEvents = __webpack_require__(8)
var pjaxEvents = __webpack_require__(9)
var turbolinksEvents = __webpack_require__(10)
var turbolinksClassicDeprecatedEvents = __webpack_require__(12)
var turbolinksClassicEvents = __webpack_require__(11)

// see what things are globally available
// and setup event handlers to those things
Expand Down Expand Up @@ -164,14 +194,14 @@ module.exports = function(ujs) {


/***/ }),
/* 2 */
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

// Make a function which:
// - First tries to require the name
// - Then falls back to global lookup
var fromGlobal = __webpack_require__(0)
var fromRequireContext = __webpack_require__(12)
var fromRequireContext = __webpack_require__(1)

module.exports = function(reqctx) {
var fromCtx = fromRequireContext(reqctx)
Expand All @@ -194,12 +224,6 @@ module.exports = function(reqctx) {
}


/***/ }),
/* 3 */
/***/ (function(module, exports) {

module.exports = __WEBPACK_EXTERNAL_MODULE_3__;

/***/ }),
/* 4 */
/***/ (function(module, exports) {
Expand All @@ -214,15 +238,22 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_5__;

/***/ }),
/* 6 */
/***/ (function(module, exports) {

module.exports = __WEBPACK_EXTERNAL_MODULE_6__;

/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {

var React = __webpack_require__(3)
var ReactDOM = __webpack_require__(4)
var ReactDOMServer = __webpack_require__(5)
var React = __webpack_require__(4)
var ReactDOM = __webpack_require__(5)
var ReactDOMServer = __webpack_require__(6)

var detectEvents = __webpack_require__(1)
var detectEvents = __webpack_require__(2)
var constructorFromGlobal = __webpack_require__(0)
var constructorFromRequireContextWithGlobalFallback = __webpack_require__(2)
var constructorFromRequireContext = __webpack_require__(1)
var constructorFromRequireContextWithGlobalFallback = __webpack_require__(3)

var ReactRailsUJS = {
// This attribute holds the name of component which should be mounted
Expand All @@ -236,9 +267,16 @@ var ReactRailsUJS = {
// This attribute holds which method to use between: ReactDOM.hydrate, ReactDOM.render
RENDER_ATTR: 'data-hydrate',

// A unique identifier to identify a node
CACHE_ID_ATTR: "data-react-cache-id",

TURBOLINKS_PERMANENT_ATTR: "data-turbolinks-permanent",

// If jQuery is detected, save a reference to it for event handlers
jQuery: (typeof window !== 'undefined') && (typeof window.jQuery !== 'undefined') && window.jQuery,

components: {},

// helper method for the mount and unmount methods to find the
// `data-react-class` DOM elements
findDOMNodes: function(searchSelector) {
Expand Down Expand Up @@ -276,6 +314,11 @@ var ReactRailsUJS = {
// the default is ReactRailsUJS.ComponentGlobal
getConstructor: constructorFromGlobal,

// Available for customizing `getConstructor`
constructorFromGlobal: constructorFromGlobal,
constructorFromRequireContext: constructorFromRequireContext,
constructorFromRequireContextWithGlobalFallback: constructorFromRequireContextWithGlobalFallback,

// Given a Webpack `require.context`,
// try finding components with `require`,
// then falling back to global lookup.
Expand Down Expand Up @@ -304,6 +347,8 @@ var ReactRailsUJS = {
var propsJson = node.getAttribute(ujs.PROPS_ATTR);
var props = propsJson && JSON.parse(propsJson);
var hydrate = node.getAttribute(ujs.RENDER_ATTR);
var cacheId = node.getAttribute(ujs.CACHE_ID_ATTR);
var turbolinksPermanent = node.hasAttribute(ujs.TURBOLINKS_PERMANENT_ATTR);

if (!constructor) {
var message = "Cannot find component: '" + className + "'"
Expand All @@ -312,13 +357,21 @@ var ReactRailsUJS = {
}
throw new Error(message + ". Make sure your component is available to render.")
} else {
let component = this.components[cacheId];
if(component === undefined) {
component = React.createElement(constructor, props);
if(turbolinksPermanent) {
this.components[cacheId] = component;
}
}

if (hydrate && typeof ReactDOM.hydrate === "function") {
ReactDOM.hydrate(React.createElement(constructor, props), node);
component = ReactDOM.hydrate(component, node);
} else {
ReactDOM.render(React.createElement(constructor, props), node);
component = ReactDOM.render(component, node);
}
}
}
}
},

// Within `searchSelector`, find nodes which have React components
Expand All @@ -339,6 +392,7 @@ var ReactRailsUJS = {
detectEvents: function() {
detectEvents(this)
},

}

// These stable references are so that handlers can be added and removed:
Expand Down Expand Up @@ -373,7 +427,7 @@ module.exports = ReactRailsUJS


/***/ }),
/* 7 */
/* 8 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -396,7 +450,7 @@ module.exports = {


/***/ }),
/* 8 */
/* 9 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -416,25 +470,25 @@ module.exports = {


/***/ }),
/* 9 */
/* 10 */
/***/ (function(module, exports) {

module.exports = {
// Turbolinks 5+ got rid of named events (?!)
setup: function(ujs) {
ujs.handleEvent('turbolinks:load', ujs.handleMount)
ujs.handleEvent('turbolinks:before-render', ujs.handleUnmount)
ujs.handleEvent('turbolinks:load', ujs.handleMount);
ujs.handleEvent('turbolinks:before-render', ujs.handleMount);
},

teardown: function(ujs) {
ujs.removeEvent('turbolinks:load', ujs.handleMount)
ujs.removeEvent('turbolinks:before-render', ujs.handleUnmount)
ujs.removeEvent('turbolinks:load', ujs.handleMount);
ujs.removeEvent('turbolinks:before-render', ujs.handleMount);
},
}


/***/ }),
/* 10 */
/* 11 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -452,7 +506,7 @@ module.exports = {


/***/ }),
/* 11 */
/* 12 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -472,36 +526,6 @@ module.exports = {
}


/***/ }),
/* 12 */
/***/ (function(module, exports) {

// Load React components by requiring them from "components/", for example:
//
// - "pages/index" -> `require("components/pages/index")`
// - "pages/show.Header" -> `require("components/pages/show").Header`
// - "pages/show.Body.Content" -> `require("components/pages/show").Body.Content`
//
module.exports = function(reqctx) {
return function(className) {
var parts = className.split(".")
var filename = parts.shift()
var keys = parts
// Load the module:
var component = reqctx("./" + filename)
// Then access each key:
keys.forEach(function(k) {
component = component[k]
})
// support `export default`
if (component.__esModule) {
component = component["default"]
}
return component
}
}


/***/ })
/******/ ]);
});
7 changes: 7 additions & 0 deletions react_ujs/index.js
Expand Up @@ -4,6 +4,7 @@ var ReactDOMServer = require("react-dom/server")

var detectEvents = require("./src/events/detect")
var constructorFromGlobal = require("./src/getConstructor/fromGlobal")
var constructorFromRequireContext = require("./src/getConstructor/fromRequireContext")
var constructorFromRequireContextWithGlobalFallback = require("./src/getConstructor/fromRequireContextWithGlobalFallback")

var ReactRailsUJS = {
Expand Down Expand Up @@ -65,6 +66,11 @@ var ReactRailsUJS = {
// the default is ReactRailsUJS.ComponentGlobal
getConstructor: constructorFromGlobal,

// Available for customizing `getConstructor`
constructorFromGlobal: constructorFromGlobal,
constructorFromRequireContext: constructorFromRequireContext,
constructorFromRequireContextWithGlobalFallback: constructorFromRequireContextWithGlobalFallback,

// Given a Webpack `require.context`,
// try finding components with `require`,
// then falling back to global lookup.
Expand Down Expand Up @@ -138,6 +144,7 @@ var ReactRailsUJS = {
detectEvents: function() {
detectEvents(this)
},

}

// These stable references are so that handlers can be added and removed:
Expand Down

0 comments on commit 1a76ee9

Please sign in to comment.