react-rails icon indicating copy to clipboard operation
react-rails copied to clipboard

Components not loaded when using .jsx extension

Open iamdriz opened this issue 4 years ago • 5 comments

We're using Webpack via (jsbundling-rails: https://github.com/rails/jsbundling-rails) to build our JavaScript.

In our application.js we have the following:

// Tell Webpack where to load the components for ReactUJS
const ReactRailsUJS = require("react_ujs");
ReactRailsUJS.useContext(require.context("./components", true));

And then we have a TestComponent.jsx under app/javascript/components with the following:

import React from 'react'

class TestComponent extends React.Component {
    render() {
        return <h1>{this.props.title}</h1>
    }
}

Then in our view we have:

<%= react_component 'TestComponent', { title: 'Cameron' }, prerender: false %>

And in our DevTools console we get the following errors:

fromRequireContextWithGlobalFallback.js:19 Error: Cannot find module './TestComponent'
    at a ((index):12:11)
    at l ((index):7:11)
    at fromRequireContext.js:13:21
    at Object.getConstructor (fromRequireContextWithGlobalFallback.js:13:19)
    at Object.mountComponents (index.js:92:29)
    at HTMLDocument.handleMount (index.js:149:17)
(anonymous) @ fromRequireContextWithGlobalFallback.js:19
mountComponents @ index.js:92
handleMount @ index.js:149
fromRequireContextWithGlobalFallback.js:20 ReferenceError: TestComponent is not defined
    at eval (eval at module.exports (fromGlobal.js:13:19), <anonymous>:1:1)
    at module.exports (fromGlobal.js:13:19)
    at Object.getConstructor (fromRequireContextWithGlobalFallback.js:17:21)
    at Object.mountComponents (index.js:92:29)
    at HTMLDocument.handleMount (index.js:149:17)
(anonymous) @ fromRequireContextWithGlobalFallback.js:20
mountComponents @ index.js:92
handleMount @ index.js:149
index.js:102 [react-rails] Cannot find component: 'TestComponent' for element div
index.js:104 Uncaught Error: Cannot find component: 'TestComponent'. Make sure your component is available to render.
    at Object.mountComponents (index.js:104:15)
    at HTMLDocument.handleMount (index.js:149:17)

The logs from the compilation clearly show that TestComponent is being added:

$ webpack --config webpack.config.js --watch
asset application.js 151 KiB [emitted] [minimized] (name: application) 2 related assets
runtime modules 362 bytes 2 modules
modules by path ./node_modules/ 165 KiB
  modules by path ./node_modules/react_ujs/react_ujs/ 12.1 KiB 10 modules
  modules by path ./node_modules/react-dom/ 139 KiB 4 modules
  modules by path ./node_modules/react/ 6.48 KiB
    ./node_modules/react/index.js 190 bytes [built] [code generated]
    ./node_modules/react/cjs/react.production.min.js 6.3 KiB [built] [code generated]
  modules by path ./node_modules/scheduler/ 4.91 KiB
    ./node_modules/scheduler/index.js 198 bytes [built] [code generated]
    ./node_modules/scheduler/cjs/scheduler.production.min.js 4.72 KiB [built] [code generated]
  ./node_modules/object-assign/index.js 2.06 KiB [built] [code generated]
modules by path ./app/javascript/ 4.34 KiB
  ./app/javascript/application.js 590 bytes [built] [code generated]
  ./app/javascript/components/ sync ^\.\/.*$ 184 bytes [built] [code generated]
  ./app/javascript/components/TestComponent.jsx 3.58 KiB [optional] [built] [code generated]
webpack 5.66.0 compiled successfully in 3918 ms

Our webpack.config.js looks like:

const path = require("path")
const webpack = require("webpack")

module.exports = {
    mode: "production",
    devtool: "source-map",
    entry: {
        application: "./app/javascript/application.js"
    },
    output: {
        filename: "[name].js",
        sourceMapFilename: "[name].js.map",
        path: path.resolve(__dirname, "app/assets/builds"),
    },
    plugins: [
        new webpack.optimize.LimitChunkCountPlugin({
            maxChunks: 1
        })
    ],
    module: {
        rules: [
            {
                test: /\.(jsx|js)$/,
                exclude: /node_modules/,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            ['@babel/preset-env', {
                                "targets": "defaults"
                            }],
                            '@babel/preset-react'
                        ]
                    }
                }]
            }
        ]
    }
}

package.json has the following:

{
  "name": "app",
  "private": "true",
  "dependencies": {
    "@babel/core": "^7.16.7",
    "@babel/preset-env": "^7.16.8",
    "@babel/preset-react": "^7.16.7",
    "@babel/preset-typescript": "^7.16.7",
    "@hotwired/stimulus": "^3.0.1",
    "@hotwired/turbo-rails": "^7.1.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-dom-server": "^0.0.5",
    "react_ujs": "^2.6.1",
    "webpack": "^5.66.0",
    "webpack-cli": "^4.9.1"
  },
  "scripts": {
    "build": "webpack --config webpack.config.js"
  },
  "babel": {
    "presets": [
      "@babel/env",
      "@babel/preset-react",
      "@babel/preset-typescript"
    ]
  },
  "devDependencies": {
    "babel-loader": "^8.2.3"
  }
}

iamdriz avatar Jan 19 '22 14:01 iamdriz

I changed TestComponent.jsx to TestComponent.js and changed the code to:

import React from 'react'

export default class TestComponent extends React.Component {
    render() {
        return React.createElement('h1', null, `${this.props.title}`);
    }
}

And it fixes the issue... seems the problem is with using JSX... I thought this Gem supported JSX?

iamdriz avatar Jan 19 '22 15:01 iamdriz

Seems you can use JSX syntax and have the file called .js but having the file called .jsx is the issue rather than the use of JSX syntax within the components... any ideas why .jsx isn't working with ReactRailsUJS?

iamdriz avatar Jan 19 '22 15:01 iamdriz

Having a similar issue myself, but can't get it to load even with changing from App.jsx to App.js :(

Funny enough my NavBar component renders and running rails assets:precompile command. App is also dockerized so troubleshooting on the pod directly.

Stackoverflow question I posted

Some older instances of this issue were pointing to the uglifier gem? I downgraded and it didn't solve my issue. Looking forward to getting this figured out, I think our next project will be Vercel with NextJS first.

thereisryan avatar Jan 21 '22 17:01 thereisryan

Not sure if it helps, I have this: @thereisryan @iamdriz

$ tail -n 12  webpack.config.js 
    })
  ],
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx|)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      }
    ]
  }
}

I don't mind inviting you to my rails app to look around because there's not a ton of documentation for the path we've chosen: rails7/jsbundling/webpack/react/jsx

la-ruby avatar Apr 18 '22 12:04 la-ruby

I have the same error. It worked fine with shakacode/react_on_rails (Only jsbundling-rails is used and not webpacker.).

sample code: https://github.com/thr3a/rails-with-react-sample

thr3a avatar Aug 25 '22 11:08 thr3a

  1. Can you all try with Shakapacker and not jsbundling-rails?
  2. Can you try with the latest versions?

And yes, react_on_rails might be easier.

justin808 avatar Jul 25 '23 07:07 justin808

ReactRails doesn't modify webpack's default configuration, AFAIK, & the extensions that webpack supports by default don't include .jsx

Judahmeek avatar Aug 19 '23 01:08 Judahmeek