react-rails: Cannot find component (Rails 5.1.2, webpacker, react-rails)

Help us help you! Please choose one:

  • My app crashes with react-rails, so I’ve included the stack trace and the exact steps which make it crash.
  • My app doesn’t crash, but I’m getting unexpected behavior. So, I’ve described the unexpected behavior and suggested a new behavior.
  • I’m trying to use react-rails with another library, but I’m having trouble. I’ve described my JavaScript management setup (eg, Sprockets, Webpack…), how I’m trying to use this other library, and why it’s not working.
  • I have another issue to discuss.

Essentially the same resulting problem as #757 and #713, where including my (haml) view helper = react_component 'PerformanceRow' gives me the following error messages:

Error: Cannot find module './PerformanceRow'.
    at webpackContextResolve (application.js:4549)
    at webpackContext (application.js:4544)
    at eval (fromRequireContext.js?f05c:13)
    at Object.eval [as getConstructor] (fromRequireContextWithGlobalFallback.js?7c97:13)
    at Object.mountComponents (index.js?0542:82)
    at HTMLDocument.ReactRailsUJS.handleMount (index.js?0542:124)
    at HTMLDocument.dispatch (event.js?268c:338)
    at HTMLDocument.elemData.handle (event.js?268c:146)

fromRequireContextWithGlobalFallback.js?7c97:20 ReferenceError: PerformanceRow is not defined
    at eval (eval at module.exports (fromGlobal.js?7c2e:22), <anonymous>:1:1)
    at module.exports (fromGlobal.js?7c2e:13)
    at Object.eval [as getConstructor] (fromRequireContextWithGlobalFallback.js?7c97:17)
    at Object.mountComponents (index.js?0542:82)
    at HTMLDocument.ReactRailsUJS.handleMount (index.js?0542:124)
    at HTMLDocument.dispatch (event.js?268c:338)
    at HTMLDocument.elemData.handle (event.js?268c:146)

index.js?0542:89 [react-rails] Cannot find component: 'PerformanceRow' for element <div data-react-class=​"PerformanceRow" data-react-props=​"{"id":​5}​">​</div>​

index.js?0542:91 Uncaught Error: Cannot find component: 'PerformanceRow'. Make sure your component is available to render.
    at Object.mountComponents (index.js?0542:91)
    at HTMLDocument.ReactRailsUJS.handleMount (index.js?0542:124)
    at HTMLDocument.dispatch (event.js?268c:338)
    at HTMLDocument.elemData.handle (event.js?268c:146)

I’ve tried the following:

  1. Rolling back uglifier to 3.0
  2. Moving the ReactRailsUJS both above and below import "turbolinks" and javascript_include_tag "application.js" in my main views/layouts/application.html.haml, and removing/adding ReactRailsUJS.detectEvents() in app/javascript/packs/application.js.
  3. Adding console.log(componentRequireContext.keys()) above the ReactRailsUJS initializer, which prints ["./PerformanceRow.jsx"] in my Chrome console.

Here’s my directory structure:

app/javascript/packs/
├── application.js
├── hello_react.jsx
└── server_rendering.js

app/javascript/components/
└── PerformanceRow.jsx

And some code:

// app/javascript/packs/application.js

import ReactRailsUJS from 'react_ujs'

// Support component names relative to this directory:
var componentRequireContext = require.context("components", true, /\.jsx?$/)
// => prints ["./PerformanceRow.jsx"] in Chrome console
console.log(componentRequireContext.keys());
ReactRailsUJS.useContext(componentRequireContext)
// app/javascript/components/PerformanceRow.jsx

import React, { Component } from "react"
import ReactDOM from "react-dom"

class PerformanceRow extends Component {
  render() {
    return (
      <tr className="performance">
        <td>HEY THERE</td>
        <td />
        <td />
        <td>Delete</td>
      </tr>
    )
  }
}

export default PerformanceRow;
-# Extract from app/views/performances/_embedded_form.html.haml
    = react_component 'PerformanceRow'

As far as I can tell, I’ve double-checked capitalization and name-mangling, and componentRequireContext can definitely find the correct file. However, PerformanceRow still seems to be unreachable. I can also access ReactRailsUJS in the global context of the Chrome console.

I should also mention that the default hello_react.jsx works just fine, but that the problem here seems to lie in ReactRailsUJS and the use of the components/ directory. Tried to trim things as best I could, but let me know if I need to include any other information.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 21
  • Comments: 23 (6 by maintainers)

Commits related to this issue

Most upvoted comments

If you have this issue, and the above did not solve it, it may be because you previously installed react-rails to work with the rails asset pipeline, and then installed webpacker later.

Removing //= require react and //= require react_ujs from application.js or application.js.coffee fixed this for me.

I’m assuming that having react and especially react_ujs in the asset pipeline meant that ReactRailsUJS was being set up to expect components also from the asset pipeline, and that setup was taking precedence over the webpacker setup.

I was forced to adjust my regex to allow directories to be included, as well as the JavaScript/Typescript files themselves:

const componentRequireContext = require.context("components", true, /^(?!.*__tests__\/.*$).+$/)

I am not fond of this solution though, I feel like react-rails should be able to load components by name if the regex excludes directories but loads files.

Update: I was wrong about the above, it does work with .jsx but I was importing the files directly with their name without any folder just as it’s done with the asset pipeline, but it seems that with Webpacker (or at least my setup) you need to specify the folder they’re on too:

react_component('myfolder/mysubfolder/Component' .....)

This seems a bit odd since I didn’t read anything about adding folders in the react-rails documentation 🤔

I installed both at the same time, and didn’t have either in the asset pipeline. In the original problem, react-rails was finding components with .js extensions, just not .jsx extensions. Wonder why that would do it.

@BookOfGreg I run into this problem when I apply filtering to require.context() to only load production JS/JSX/TS/TSX files in my application pack. The main purpose of me doing this is to have my test files/folders excluded from asset compilation, since they shouldn’t be shipped to production. My plight with passing the appropriate filter regex to require.context is documented here: https://github.com/rails/webpacker/issues/1818#issuecomment-576428973

Unfortunately, I then run into a problem with react-rails, in that my calls to react_component started failing. I have a hunch it is due to directory names no longer being loaded by require.context, but I’m not too sure. Anyway, I hope that this provides you with another angle to think about this problem.

I am happy to delve further into reproduction steps with you.