From b9c824dcbbbf45665d098946b6a47d37d2eac204 Mon Sep 17 00:00:00 2001 From: Cymen Vig Date: Thu, 2 Sep 2021 22:39:14 -0400 Subject: [PATCH 01/10] add useContexts which takes an array of require.context --- react_ujs/index.js | 7 ++++ .../fromRequireContextsWithGlobalFallback.js | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 react_ujs/src/getConstructor/fromRequireContextsWithGlobalFallback.js diff --git a/react_ujs/index.js b/react_ujs/index.js index 4c4c991fb..c0ba1c1a7 100644 --- a/react_ujs/index.js +++ b/react_ujs/index.js @@ -79,6 +79,13 @@ var ReactRailsUJS = { this.getConstructor = constructorFromRequireContextWithGlobalFallback(requireContext) }, + // Given an array of Webpack `require.context`, + // try finding components with `require`, + // then falling back to global lookup. + useContexts: function(requireContexts) { + this.getConstructor = constructorFromRequireContextsWithGlobalFallback(requireContexts) + }, + // Render `componentName` with `props` to a string, // using the specified `renderFunction` from `react-dom/server`. serverRender: function(renderFunction, componentName, props) { diff --git a/react_ujs/src/getConstructor/fromRequireContextsWithGlobalFallback.js b/react_ujs/src/getConstructor/fromRequireContextsWithGlobalFallback.js new file mode 100644 index 000000000..ab4b936c6 --- /dev/null +++ b/react_ujs/src/getConstructor/fromRequireContextsWithGlobalFallback.js @@ -0,0 +1,39 @@ +// Make a function which: +// - First tries to require the name +// - Then falls back to global lookup +var fromGlobal = require("./fromGlobal") +var fromRequireContext = require("./fromRequireContext") + +module.exports = function(reqctxs) { + var fromCtxs = reqctxs.map((reqctx) => fromRequireContext(reqctx)) + return function(className) { + var component; + try { + var index = 0, fromCtx, firstErr; + do { + fromCtx = fromCtxs[index]; + + try { + // `require` will raise an error if this className isn't found: + component = fromCtx(className) + } catch (fromCtxErr) { + if (!firstErr) { + firstErr = fromCtxErr; + } + } + + index += 1; + } while (index < fromCtxs.length); + if (!component) throw firstErr; + } catch (firstErr) { + // fallback to global: + try { + component = fromGlobal(className) + } catch (secondErr) { + console.error(firstErr) + console.error(secondErr) + } + } + return component + } +} From 2c7ca31c7082da25fe0b18f82ab82725f6b27072 Mon Sep 17 00:00:00 2001 From: Cymen Vig Date: Fri, 3 Sep 2021 17:41:31 -0400 Subject: [PATCH 02/10] add note to README about useContexts --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 77c3f7b87..051b0f0af 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,8 @@ ReactRailsUJS.useContext(myCustomContext) If `require` fails to find your component, [`ReactRailsUJS`](#ujs) falls back to the global namespace, described in [Use with Asset Pipeline](#use-with-asset-pipeline). +In some cases, having multiple `require.context` may be desired. If so, an array of `require.context` can be passed to `ReactRailsUJS.useContexts`. With an array of contexts, an attempt will be made to `require` the component from each context before falling back to the global namespace as described above. + ### File naming React-Rails supports plenty of file extensions such as: .js, .jsx.js, .js.jsx, .es6.js, .coffee, etcetera! From 99ded57f459ffb79a0ce8838e71d1512c782e4bc Mon Sep 17 00:00:00 2001 From: Riccardo Margiotta Date: Mon, 28 Nov 2022 12:04:59 +0000 Subject: [PATCH 03/10] Update README to include information about useContexts. --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 051b0f0af..dffcf7ac8 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,21 @@ ReactRailsUJS.useContext(myCustomContext) If `require` fails to find your component, [`ReactRailsUJS`](#ujs) falls back to the global namespace, described in [Use with Asset Pipeline](#use-with-asset-pipeline). -In some cases, having multiple `require.context` may be desired. If so, an array of `require.context` can be passed to `ReactRailsUJS.useContexts`. With an array of contexts, an attempt will be made to `require` the component from each context before falling back to the global namespace as described above. +In some cases, having multiple `require.context` may be desired - for example, if you have additional entry points to create JavaScript files for different routes, you would add multiple `require.context` to your `server_rendering.js` to allow for [Server-Side Rendering](#server-side-rendering) across your application. If so, an array of `require.context` can be passed to `ReactRailsUJS.useContexts`. With an array of contexts, an attempt will be made to `require` the component from each context before falling back to the global namespace as described above. +```js +// server_rendering.js +var componentsRequireContext = require.context('components', true); +var searchRequireContext = require.context('search', true); +var checkoutRequireContext = require.context('checkout', true); + +var ReactRailsUJS = require('react_ujs'); +ReactRailsUJS.useContexts([ + componentsRequireContext, + searchRequireContext, + checkoutRequireContext +]); +``` ### File naming React-Rails supports plenty of file extensions such as: .js, .jsx.js, .js.jsx, .es6.js, .coffee, etcetera! From 6c5449fbe5796682b4d15f53cc02f20875cfb527 Mon Sep 17 00:00:00 2001 From: Riccardo Margiotta Date: Mon, 28 Nov 2022 12:09:41 +0000 Subject: [PATCH 04/10] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 192eef6e9..a6ffe2d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ #### New Features - Camelizes keys with primitive values, in addition to hashes #946 - Expose alternative implementations for `ReactUJS.getConstructor` #1050 +- Add support for multiple `require.context` with addition of `useContexts` #1221 - Update dependencies - react to 17.0.2 #1218 - webpack to 5.74.0 From f12b2167bf872862f19304e6d9e0c5423278e5a4 Mon Sep 17 00:00:00 2001 From: Riccardo Margiotta Date: Mon, 28 Nov 2022 18:36:19 +0000 Subject: [PATCH 05/10] Update usage example. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dffcf7ac8..73e8f5314 100644 --- a/README.md +++ b/README.md @@ -176,13 +176,13 @@ In some cases, having multiple `require.context` may be desired - for example, i ```js // server_rendering.js -var componentsRequireContext = require.context('components', true); +var applicationRequireContext = require.context('application', true); var searchRequireContext = require.context('search', true); var checkoutRequireContext = require.context('checkout', true); var ReactRailsUJS = require('react_ujs'); ReactRailsUJS.useContexts([ - componentsRequireContext, + applicationRequireContext, searchRequireContext, checkoutRequireContext ]); From 402310de53748a5f9c9f9f47320c5b3cdcc42e78 Mon Sep 17 00:00:00 2001 From: Riccardo Margiotta Date: Mon, 28 Nov 2022 18:50:12 +0000 Subject: [PATCH 06/10] Update usage example to better explain route-splitting and SSR. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73e8f5314..6c758d146 100644 --- a/README.md +++ b/README.md @@ -172,17 +172,17 @@ ReactRailsUJS.useContext(myCustomContext) If `require` fails to find your component, [`ReactRailsUJS`](#ujs) falls back to the global namespace, described in [Use with Asset Pipeline](#use-with-asset-pipeline). -In some cases, having multiple `require.context` may be desired - for example, if you have additional entry points to create JavaScript files for different routes, you would add multiple `require.context` to your `server_rendering.js` to allow for [Server-Side Rendering](#server-side-rendering) across your application. If so, an array of `require.context` can be passed to `ReactRailsUJS.useContexts`. With an array of contexts, an attempt will be made to `require` the component from each context before falling back to the global namespace as described above. +In some cases, having multiple `require.context` entries may be desired. In a larger application, you might find it helpful to split your JavaScript by routes/controllers to avoid serving unused components and improve your site performance by keeping bundles smaller. For example, you might have separate bundles for homepage, search, and checkout routes. In that scenario, you can add an array of `require.context` component directory paths via `useContexts` to `server_rendering.js`, to allow for [Server-Side Rendering](#server-side-rendering) across your application ```js // server_rendering.js -var applicationRequireContext = require.context('application', true); +var homepageRequireContext = require.context('homepage', true); var searchRequireContext = require.context('search', true); var checkoutRequireContext = require.context('checkout', true); var ReactRailsUJS = require('react_ujs'); ReactRailsUJS.useContexts([ - applicationRequireContext, + homepageRequireContext, searchRequireContext, checkoutRequireContext ]); From c5cd6c6c627f73ecb6fe38a2a0d989ed428e310d Mon Sep 17 00:00:00 2001 From: Cymen Vig Date: Mon, 28 Nov 2022 11:31:32 -0800 Subject: [PATCH 07/10] Update README.md Add additional use case for multiple require contexts to documentation. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c758d146..0ac875b71 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,11 @@ ReactRailsUJS.useContext(myCustomContext) If `require` fails to find your component, [`ReactRailsUJS`](#ujs) falls back to the global namespace, described in [Use with Asset Pipeline](#use-with-asset-pipeline). -In some cases, having multiple `require.context` entries may be desired. In a larger application, you might find it helpful to split your JavaScript by routes/controllers to avoid serving unused components and improve your site performance by keeping bundles smaller. For example, you might have separate bundles for homepage, search, and checkout routes. In that scenario, you can add an array of `require.context` component directory paths via `useContexts` to `server_rendering.js`, to allow for [Server-Side Rendering](#server-side-rendering) across your application +In some cases, having multiple `require.context` entries may be desired. Examples of this include: +- In a larger application, you might find it helpful to split your JavaScript by routes/controllers to avoid serving unused components and improve your site performance by keeping bundles smaller. For example, you might have separate bundles for homepage, search, and checkout routes. In that scenario, you can add an array of `require.context` component directory paths via `useContexts` to `server_rendering.js`, to allow for [Server-Side Rendering](#server-side-rendering) across your application +- Refactoring a typical Rails application into a Rails API with an (eventually) separate Single Page Application (SPA). For this use case, one can add a separate pack in addition to the typical `application` one. React components can be shared between the packs but the new pack can use a minimal Rails view layout, different default styling, etc. + ```js // server_rendering.js var homepageRequireContext = require.context('homepage', true); From c893444e4824116e6685bbab1df2605a2dfa4fc5 Mon Sep 17 00:00:00 2001 From: Cymen Vig Date: Mon, 28 Nov 2022 11:41:47 -0800 Subject: [PATCH 08/10] Update CHANGELOG.md Co-authored-by: Riccardo Margiotta --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6ffe2d38..954ae9ffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ #### New Features - Camelizes keys with primitive values, in addition to hashes #946 - Expose alternative implementations for `ReactUJS.getConstructor` #1050 -- Add support for multiple `require.context` with addition of `useContexts` #1221 +- Add support for multiple `require.context` with addition of `useContexts` #1144 - Update dependencies - react to 17.0.2 #1218 - webpack to 5.74.0 From f92b5f1d5ccf429312de10d1b8455e0a78b3d113 Mon Sep 17 00:00:00 2001 From: Cymen Vig Date: Mon, 28 Nov 2022 11:43:35 -0800 Subject: [PATCH 09/10] Update README.md Co-authored-by: Riccardo Margiotta --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ac875b71..537db271a 100644 --- a/README.md +++ b/README.md @@ -174,8 +174,8 @@ If `require` fails to find your component, [`ReactRailsUJS`](#ujs) falls back to In some cases, having multiple `require.context` entries may be desired. Examples of this include: -- In a larger application, you might find it helpful to split your JavaScript by routes/controllers to avoid serving unused components and improve your site performance by keeping bundles smaller. For example, you might have separate bundles for homepage, search, and checkout routes. In that scenario, you can add an array of `require.context` component directory paths via `useContexts` to `server_rendering.js`, to allow for [Server-Side Rendering](#server-side-rendering) across your application - Refactoring a typical Rails application into a Rails API with an (eventually) separate Single Page Application (SPA). For this use case, one can add a separate pack in addition to the typical `application` one. React components can be shared between the packs but the new pack can use a minimal Rails view layout, different default styling, etc. +- In a larger application, you might find it helpful to split your JavaScript by routes/controllers to avoid serving unused components and improve your site performance by keeping bundles smaller. For example, you might have separate bundles for homepage, search, and checkout routes. In that scenario, you can add an array of `require.context` component directory paths via `useContexts` to `server_rendering.js`, to allow for [Server-Side Rendering](#server-side-rendering) across your application: ```js // server_rendering.js From 108ed6e64b0a5f85bdcaa24bec695b18c489ce50 Mon Sep 17 00:00:00 2001 From: Cymen Vig Date: Sat, 21 Jan 2023 22:53:24 -0500 Subject: [PATCH 10/10] add missing import (overlooked in prior merge) --- react_ujs/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/react_ujs/index.js b/react_ujs/index.js index c0ba1c1a7..6b8effc85 100644 --- a/react_ujs/index.js +++ b/react_ujs/index.js @@ -6,6 +6,7 @@ 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 constructorFromRequireContextsWithGlobalFallback = require("./src/getConstructor/fromRequireContextsWithGlobalFallback") const { supportsHydration, reactHydrate, createReactRootLike } = require("./src/renderHelpers") var ReactRailsUJS = {