Components not loaded when using .jsx extension
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"
}
}
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?
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?
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.
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
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
- Can you all try with Shakapacker and not jsbundling-rails?
- Can you try with the latest versions?
And yes, react_on_rails might be easier.
ReactRails doesn't modify webpack's default configuration, AFAIK, & the extensions that webpack supports by default don't include .jsx