question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

react_component console errors with multiple packs on a page

See original GitHub issue

Steps to reproduce

Trying to use react_component where a page has 2 pack tags loaded.

example .html.erb file

<div id='inside-comp'>
  <%= javascript_pack_tag 'application' %>
  <%= javascript_pack_tag 'outside' %>
  <%= react_component("InsideComp", { greeting: "Hello" }, {prerender: false}) %>
</div>

Resulting error

1. fromRequireContextWithGlobalFallback.js:19 Error: Cannot find module './InsideComp'.
    at webpackContextResolve (.*$:14)
    at webpackContext (.*$:9)
    at fromRequireContext.js:13
    at Object.getConstructor (fromRequireContextWithGlobalFallback.js:13)
    at Object.mountComponents (index.js:85)
    at HTMLDocument.ReactRailsUJS.handleMount (index.js:132)
2. ReferenceError: InsideComp is not defined
    at eval (eval at module.exports (fromGlobal.js:13), <anonymous>:1:1)
    at module.exports (fromGlobal.js:13)
    at Object.getConstructor (fromRequireContextWithGlobalFallback.js:17)
    at Object.mountComponents (index.js:85)
    at HTMLDocument.ReactRailsUJS.handleMount (index.js:132)
3. index.js:95 Uncaught Error: Cannot find component: 'InsideComp'. Make sure your component is available to render.
    at Object.mountComponents (index.js:95)
    at HTMLDocument.ReactRailsUJS.handleMount (index.js:132)

Expected behavior

Component loads and no console errors

Actual behavior

Component loads correctly but you still get 3 console errors.

System configuration

Sprockets or Webpacker version: 3.2 React-Rails version: 2.4.2 Rect_UJS version: 2.4.2 Rails version: 5.1.2 Ruby version: 2.4.2


  1. Sample repo: https://github.com/ratneshraval/react-rails-webpacker-test
  2. Repo readme tells you 3 commands to run
  3. Visit /insidecomp and /outsidecomp
  4. Check console log.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:13
  • Comments:19 (5 by maintainers)

github_iconTop GitHub Comments

8reactions
ratneshravalcommented, Nov 29, 2018

@dtom90 Thank you for looking into this.

The reason I have 2 packs and 2 contexts, is to keep individual packs size smaller and only contain relevant imports. Hence I have 2 packs

  1. component pack with app/javascript/components directory context
  2. otherComp pack with app/javascript/otherComps directory context. Now I have a page where both are needed, hence both are there, resulting in this error.

How can I achieve this? If I combine all into 1 directory context, the resulting pack will contain everything and defeat modular bundling purpose of webpack.

2reactions
scratoncommented, Aug 31, 2020

We managed to workaround this issue by writing our own React mount code:

app/javascript/lib/react.js

import React from 'react';
import { render, hydrate } from 'react-dom';

const CLASS_NAME_ATTR = 'data-react-class';
const PROPS_ATTR = 'data-react-props';
const RENDER_ATTR = 'data-hydrate';

export function mountComponents(context) {
  const keys = Object.keys(context);

  for (const key of keys) {
    const selector = `[${CLASS_NAME_ATTR}="${key}"]`;
    const nodes = document.querySelectorAll(selector);

    for (let i = 0; i < nodes.length; ++i) {
      const node = nodes[i];
      const component = context[key];
      const constructor = component.__esModule ? context[key].default : context[key];
      const propsJson = node.getAttribute(PROPS_ATTR);
      const props = propsJson && JSON.parse(propsJson);
      const doHydrate = node.getAttribute(RENDER_ATTR);

      if (!constructor) {
        const message = `Cannot find component in current context: '${key}'`;

        if (console && console.log) {
          console.log(`%c[react-rails] %c${message} for element,`, 'font-weight: bold', 'font-weight: normal', node);
          console.log('%c[react-rails] %cCurrent context:', 'font-weight: bold', 'font-weight: normal', context);
        }

        throw new Error(`${message}. Make sure your component is available to render.`);
      }

      const reactComponent = React.createElement(constructor, props);

      if (doHydrate && typeof hydrate === 'function') {
        hydrate(reactComponent, node);
      } else {
        render(reactComponent, node);
      }
    }
  }
}

Then in each pack, we can explicitly mount just the React components we expect to see within the page:

app/javascript/packs/application.js

import { mountComponents } from '../lib/react';

mountComponents({
  'SiteBanner': require('../components/SiteBanner'),
  'SiteSearch': require('../components/SiteSearch'),
});

app/javascript/packs/authentication.js

import { mountComponents } from '../lib/react';

mountComponents({
  'Authentication': require('../components/Authentication'),
});

This appears to work fine with the SplitChunksPlugin as well. The downside is you need to explicitly declare each component you expect to see on the page, so the dynamic discovery behavior is lost.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to avoid `loaded two copies of React` error when ...
The issue is twofold: You cannot have 2 copies of react loaded. npm link creates a symlink, however the "require" doesnt respect the...
Read more >
React Error Handling and Logging Best Practices
Many developers are familiar with console logs, but only a few understand how to log errors in a React app persistently.
Read more >
Centralizing API error handling in React apps - ITNEXT
In this article I'm going to present to you a way of handling your API errors once and for all in a centralized...
Read more >
Code-Splitting - React
This bundle can then be included on a webpage to load an entire app at once. ... resolves to a module with a...
Read more >
A Guide to React Localization with i18next | Phrase
We're using the following NPM packages (versions in parentheses) in this ... we would get an error telling us that “A React component...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found