Skip to content

Expose all built-in options for getConstructor #1050

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#### New Features

- Expose alternative implementations for `ReactUJS.getConstructor` #1050

#### Deprecation

#### Bug Fixes
Expand Down
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,27 @@ delete window.Turbolinks;

### `getConstructor`

Components are loaded with `ReactRailsUJS.getConstructor(className)`. This function has two built-in implementations:
Components are loaded with `ReactRailsUJS.getConstructor(className)`. This function has two default implementations, depending on if you're using the asset pipeline or Webpacker:

- On the asset pipeline, it looks up `className` in the global namespace.
- On Webpacker, it `require`s files and accesses named exports, as described in [Get started with Webpacker](#get-started-with-webpacker).
- On the asset pipeline, it looks up `className` in the global namespace (`ReactUJS.constructorFromGlobal`).
- On Webpacker, it `require`s files and accesses named exports, as described in [Get started with Webpacker](#get-started-with-webpacker), falling back to the global namespace (`ReactUJS.constructorFromRequireContextWithGlobalFallback`).

You can override this function to customize the mapping of name-to-constructor. [Server-side rendering](#server-side-rendering) also uses this function.

For example, the fallback behavior of
`ReactUJS.constructorFromRequireContextWithGlobalFallback` can sometimes make
server-side rendering errors hard to debug as it will swallow the original error
(more info
[here](https://github.com/reactjs/react-rails/issues/264#issuecomment-552326663)).
`ReactUJS.constructorFromRequireContext` is provided for this reason. You can
use it like so:

```js
// Replaces calls to `ReactUJS.useContext`
ReactUJS.getConstructor = ReactUJS.constructorFromRequireContext(require.context('components', true));
```


## Server-Side Rendering

You can render React components inside your Rails server with `prerender: true`:
Expand Down
123 changes: 65 additions & 58 deletions lib/assets/javascripts/react_ujs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
exports["ReactRailsUJS"] = factory(require("react-dom"), require("react"), require("react-dom/server"));
else
root["ReactRailsUJS"] = factory(root["ReactDOM"], root["React"], root["ReactDOMServer"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_5__, __WEBPACK_EXTERNAL_MODULE_6__) {
})(this, function(__WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_6__, __WEBPACK_EXTERNAL_MODULE_7__) {
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 = 7);
/******/ return __webpack_require__(__webpack_require__.s = 8);
/******/ })
/************************************************************************/
/******/ ([
Expand Down Expand Up @@ -108,17 +108,47 @@ module.exports = function(className) {
/* 1 */
/***/ (function(module, exports) {

module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
// 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) {

module.exports = __WEBPACK_EXTERNAL_MODULE_2__;

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

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)
var nativeEvents = __webpack_require__(9)
var pjaxEvents = __webpack_require__(10)
var turbolinksEvents = __webpack_require__(11)
var turbolinksClassicDeprecatedEvents = __webpack_require__(13)
var turbolinksClassicEvents = __webpack_require__(12)

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


/***/ }),
/* 3 */
/* 4 */
/***/ (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__(13)
var fromRequireContext = __webpack_require__(1)

module.exports = function(reqctx) {
var fromCtx = fromRequireContext(reqctx)
Expand All @@ -201,15 +231,15 @@ module.exports = function(reqctx) {


/***/ }),
/* 4 */
/* 5 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (immutable) */ __webpack_exports__["supportsHydration"] = supportsHydration;
/* harmony export (immutable) */ __webpack_exports__["reactHydrate"] = reactHydrate;
/* harmony export (immutable) */ __webpack_exports__["createReactRootLike"] = createReactRootLike;
const ReactDOM = __webpack_require__(1)
const ReactDOM = __webpack_require__(2)

function supportsHydration() {
return typeof ReactDOM.hydrate === "function" || typeof ReactDOM.hydrateRoot === "function"
Expand Down Expand Up @@ -238,29 +268,30 @@ function legacyReactRootLike(node) {


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

module.exports = __WEBPACK_EXTERNAL_MODULE_5__;
module.exports = __WEBPACK_EXTERNAL_MODULE_6__;

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

module.exports = __WEBPACK_EXTERNAL_MODULE_6__;
module.exports = __WEBPACK_EXTERNAL_MODULE_7__;

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

var React = __webpack_require__(5)
var ReactDOM = __webpack_require__(1)
var ReactDOMServer = __webpack_require__(6)
var React = __webpack_require__(6)
var ReactDOM = __webpack_require__(2)
var ReactDOMServer = __webpack_require__(7)

var detectEvents = __webpack_require__(2)
var detectEvents = __webpack_require__(3)
var constructorFromGlobal = __webpack_require__(0)
var constructorFromRequireContextWithGlobalFallback = __webpack_require__(3)
const { supportsHydration, reactHydrate, createReactRootLike } = __webpack_require__(4)
var constructorFromRequireContext = __webpack_require__(1)
var constructorFromRequireContextWithGlobalFallback = __webpack_require__(4)
const { supportsHydration, reactHydrate, createReactRootLike } = __webpack_require__(5)

var ReactRailsUJS = {
// This attribute holds the name of component which should be mounted
Expand Down Expand Up @@ -321,6 +352,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 @@ -395,6 +431,7 @@ var ReactRailsUJS = {
detectEvents: function() {
detectEvents(this)
},

}

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


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

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


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

module.exports = {
Expand All @@ -472,7 +509,7 @@ module.exports = {


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

module.exports = {
Expand All @@ -488,7 +525,7 @@ module.exports = {


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

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


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

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


/***/ }),
/* 13 */
/***/ (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
}
}


/***/ })
/******/ ]);
});
Loading