Rails 7如何配置实现React所用JSX文件的编译?
Rails 7 环境下实现React组件调用的落地方法
Rails 7 默认替换掉了旧的Webpacker,默认用Importmap做JS模块管理,也提供了jsbundling-rails对接esbuild/rollup等打包工具,你之前用的react-rails gem完全兼容Rails 7,按下面步骤配置就能实现你要的调用效果,和你之前的开发习惯差别很小。
推荐方案:react-rails + esbuild(适配原有开发习惯)
- 安装基础依赖
先在Gemfile里添加两个gem:
执行gem "react-rails" gem "jsbundling-rails"bundle install完成gem安装,接着跑esbuild安装命令:rails javascript:install:esbuild,这一步会自动帮你配置好JS打包的输出路径、布局文件的JS引用标签。
之后装React相关的npm依赖:
最后跑react-rails的安装生成器:yarn add react react-dom @babel/preset-react # 用npm的话就跑 npm i react react-dom @babel/preset-reactrails g react:install,命令执行完会自动在app/javascript下创建components目录,你把现有的star_rating.js.jsx文件直接放进这个目录就行,记得给组件加默认导出,举个正确的组件写法示例:// app/javascript/components/star_rating.js.jsx import React from 'react' export default function StarRating({ name, value, onStarClick }) { // 你自己的组件逻辑,比如星星渲染、点击事件处理 return <div className="star-rating">{/* 业务逻辑 */}</div> } - 调整esbuild配置支持JSX解析
打开根目录下的esbuild.config.js,修改打包配置,添加JSX后缀支持和路径别名,省得每次引入组件都写长串相对路径:
接着修改const path = require('path') require("esbuild").build({ entryPoints: ["application.js"], bundle: true, outdir: path.join(process.cwd(), "app/assets/builds"), absWorkingDir: path.join(process.cwd(), "app/javascript"), loader: { '.js': 'jsx', '.jsx': 'jsx' }, resolveExtensions: ['.js', '.jsx'], // 原有sourcemap等配置保留即可 }).catch(() => process.exit(1))app/javascript/application.js,把React、ReactDOM和你要全局用的组件挂到window对象上,这样其他任意JS代码都能直接调用:
要是你用的是React 17及以下版本,react-dom的引入和render方法保持你原来的写法就行,不用改createRoot。import React from 'react' import ReactDOM from 'react-dom/client' import StarRating from 'components/star_rating' window.React = React window.ReactDOM = ReactDOM window.StarRating = StarRating - 验证调用逻辑
配置完跑rails assets:precompile或者直接启动bin/dev(会自动监听JS文件变化热重载),你在任意JS代码里直接写你需要的调用逻辑就可以:
注意Rails 7默认开启Turbo,不要在DOM没加载完成的时候就去拿容器节点,最好把渲染逻辑绑在Turbo的加载事件里,避免找不到节点报错:let starRating = <StarRating name={name} value={initialValue} onStarClick={onClick} />; // React 18 写法 ReactDOM.createRoot(someContainerElem).render(starRating) // React 17及以下用原有写法即可:ReactDOM.render(starRating, someContainerElem)document.addEventListener('turbo:load', () => { const container = document.querySelector('#star-rating-wrap') if (!container) return // 从dataset拿初始化参数的逻辑 const { name, initialValue } = container.dataset const onClick = (val) => console.log('用户评分:', val) const starRating = <StarRating name={name} value={Number(initialValue)} onStarClick={onClick} /> ReactDOM.createRoot(container).render(starRating) })
轻量备选:纯Importmap方案(不用打包工具)
如果你的React组件不多,不想引入打包流程,也可以直接用Rails 7默认的Importmap实现:
- 执行
bin/importmap pin react react-dom把React相关依赖固定到importmap - 再执行
bin/importmap pin @babel/standalone引入babel转译器用来处理JSX语法 - 这种方案不需要提前打包,但是写JSX的script标签要加
type="text/babel"属性,适合小型项目用,组件多的话转译性能不如提前打包的esbuild方案,优先选第一种就行。
内容的提问来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

