README.md in react-rails-2.6.2 vs README.md in react-rails-2.7.0.rc.0
- old
+ new
@@ -1,27 +1,31 @@
# React-Rails
[](http://rubygems.org/gems/react-rails)
[](https://www.npmjs.com/package/react_ujs)
-[](https://travis-ci.org/reactjs/react-rails)
-[]()
+[](https://github.com/reactjs/react-rails/actions/workflows/ruby.yml)[]()
React-Rails is a flexible tool to use [React](http://facebook.github.io/react/) with Rails. The benefits:
* Automatically renders React server-side and client-side
-* Supports Webpacker 4.x, 3.x, 2.x, 1.1+
+* Supports Webpacker 4.x, 3.x, 2.x, 1.1+ or Shakapacker v6+
* Supports Sprockets 4.x, 3.x, 2.x
* Lets you use [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html), [ES6](http://es6-features.org/), [TypeScript](https://www.typescriptlang.org/), [CoffeeScript](http://coffeescript.org/)
-A source code example utilizing React-Rails: https://github.com/BookOfGreg/react-rails-example-app
+## Resouces
+* [Click to join **React + Rails Slack**](https://reactrails.slack.com/join/shared_invite/enQtNjY3NTczMjczNzYxLTlmYjdiZmY3MTVlMzU2YWE0OWM0MzNiZDI0MzdkZGFiZTFkYTFkOGVjODBmOWEyYWQ3MzA2NGE1YWJjNmVlMGE). Then join the channel `#react-rails`.
+* If you need help upgrading `react-rails`, `webpacker`, or JS packages, contact [justin@shakacode.com](mailto:justin@shakacode.com). The [ShakaCode.com](https://www.shakacode.com) team is helping to maintain this Ruby gem. Check out [this discussion](https://github.com/reactjs/react-rails/discussions/1200).
+* If you are upgrading, you might consider migrating to the [react_on_rails](https://github.com/shakacode/react_on_rails) gem.
+* Source code example utilizing React-Rails: https://github.com/BookOfGreg/react-rails-example-app
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Contents
-- [Get started with Webpacker](#get-started-with-webpacker)
+- [Get started with Shakapacker](#get-started-with-shakapacker)
- [File naming](#file-naming)
+ - [Typescript support](#typescript-support)
- [Use with Asset Pipeline](#use-with-asset-pipeline)
- [Custom JSX Transformer](#custom-jsx-transformer)
- [React.js versions](#reactjs-versions)
- [View Helper](#view-helper)
- [Custom View Helper](#custom-view-helper)
@@ -53,81 +57,100 @@
After reading this README file, additional information about React-Rails can be found in the Wiki page:
https://github.com/reactjs/React-Rails/wiki
The Wiki page features a significant amount of additional information about React-Rails which includes instructional articles and answers to the most frequently asked questions.
-## Get started with Webpacker
+## Get started with Shakapacker
-[Alternatively, get started with Sprockets](#use-with-asset-pipeline)
+_Alternatively, get started with [Sprockets](#use-with-asset-pipeline)_
-[Webpacker](https://github.com/rails/webpacker) provides modern JS tooling for Rails. Here are the listed steps for integrating Webpacker and Rails-React with Rails:
+#### 1) Create a new Rails app:
+Prevent installing default javascript dependencies by using `--skip-javascript` option:
-##### 1) Create a new Rails app:
-```
-$ rails new my-app
+```bash
+$ rails new my-app --skip-javascript
$ cd my-app
```
-##### 2) Add `react-rails` to your Gemfile:
-```ruby
-gem 'react-rails'
+#### 2) Install `shakapacker`:
+```bash
+$ bundle add shakapacker --strict
+$ rails webpacker:install
```
-Note: On rails versions < 6.0, You need to add `gem 'webpacker'` to your Gemfile in step 2 above.
-##### 3) Now run the installers:
+#### 3) Install `react` and some other required npm packages:
+```bash
+$ yarn add react react-dom @babel/preset-react prop-types \
+ css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin
+```
-###### Rails 6.x and 5.x:
+Also update the Babel configuration in the `package.json` file:
+
+```diff
+"babel": {
+ "presets": [
+- "./node_modules/shakapacker/package/babel/preset.js"
++ "./node_modules/shakapacker/package/babel/preset.js",
++ "@babel/preset-react"
+ ]
+},
```
-$ bundle install
-$ rails webpacker:install # OR (on rails version < 5.0) rake webpacker:install
-$ rails webpacker:install:react # OR (on rails version < 5.0) rake webpacker:install:react
+
+#### 4) Install `react-rails`:
+```bash
+$ bundle add 'react-rails' --strict
$ rails generate react:install
```
This gives you:
- `app/javascript/components/` directory for your React components
- [`ReactRailsUJS`](#ujs) setup in `app/javascript/packs/application.js`
- `app/javascript/packs/server_rendering.js` for [server-side rendering](#server-side-rendering)
-Note: On rails versions < 6.0, link the JavaScript pack in Rails view using `javascript_pack_tag` [helper](https://github.com/rails/webpacker#usage):
-```erb
-<!-- application.html.erb in Head tag below turbolinks -->
-<%= javascript_pack_tag 'application' %>
-```
-
-##### 4) Generate your first component:
-```
+#### 5) Generate your first component:
+```bash
$ rails g react:component HelloWorld greeting:string
```
-##### 5) You can also generate your component in a subdirectory:
-```
+You can also generate your component in a subdirectory:
+
+```bash
$ rails g react:component my_subdirectory/HelloWorld greeting:string
```
+
Note: Your component is added to `app/javascript/components/` by default.
Note: If your component is in a subdirectory you will append the directory path to your erb component call.
-Example:
-```
+Example:
+```erb
<%= react_component("my_subdirectory/HelloWorld", { greeting: "Hello from react-rails." }) %>
```
-##### 6) [Render it in a Rails view](#view-helper):
+#### 6) [Render it in a Rails view](#view-helper):
```erb
<!-- erb: paste this in view -->
<%= react_component("HelloWorld", { greeting: "Hello from react-rails." }) %>
```
##### 7) Lets Start the app:
-```
+```bash
$ rails s
```
-output: greeting: Hello from react-rails", inspect webpage in your browser too see change in tag props.
+Output: greeting: Hello from react-rails", inspect webpage in your browser to see the change in tag props.
+##### 7) Run dev server (optional)
+In order to run dev server with HMR feature you need to parallely run:
+
+```bash
+$ ./bin/webpacker-dev-server
+```
+
+Note: On Rails 6 you need to specify `webpack-dev-server` host. To this end, update `config/initializers/content_security_policy.rb` and uncomment relevant lines.
+
### Component name
The component name tells `react-rails` where to load the component. For example:
`react_component` call | component `require`
@@ -148,10 +171,28 @@
ReactRailsUJS.useContext(myCustomContext)
```
If `require` fails to find your component, [`ReactRailsUJS`](#ujs) falls back to the global namespace, described in [Use with Asset Pipeline](#use-with-asset-pipeline).
+In some cases, having multiple `require.context` entries may be desired. Examples of this include:
+
+- Refactoring a typical Rails application into a Rails API with an (eventually) separate Single Page Application (SPA). For this use case, one can add a separate pack in addition to the typical `application` one. React components can be shared between the packs but the new pack can use a minimal Rails view layout, different default styling, etc.
+- In a larger application, you might find it helpful to split your JavaScript by routes/controllers to avoid serving unused components and improve your site performance by keeping bundles smaller. For example, you might have separate bundles for homepage, search, and checkout routes. In that scenario, you can add an array of `require.context` component directory paths via `useContexts` to `server_rendering.js`, to allow for [Server-Side Rendering](#server-side-rendering) across your application:
+
+```js
+// server_rendering.js
+var homepageRequireContext = require.context('homepage', true);
+var searchRequireContext = require.context('search', true);
+var checkoutRequireContext = require.context('checkout', true);
+
+var ReactRailsUJS = require('react_ujs');
+ReactRailsUJS.useContexts([
+ homepageRequireContext,
+ searchRequireContext,
+ checkoutRequireContext
+]);
+```
### File naming
React-Rails supports plenty of file extensions such as: .js, .jsx.js, .js.jsx, .es6.js, .coffee, etcetera!
Sometimes this will cause a stumble when searching for filenames.
@@ -162,28 +203,66 @@
`app/javascript/components/SampleComponent.js` | `react_component("SampleComponent")`
`app/javascript/components/SampleComponent.js.jsx` | Has to be renamed to SampleComponent.jsx, then use `react_component("SampleComponent")`
### Typescript support
-If you want to use React-Rails with Typescript, simply run the installer and add @types:
+```bash
+yarn add typescript @babel/preset-typescript
```
-$ bundle exec rails webpacker:install:typescript
-$ yarn add @types/react @types/react-dom
+
+Babel won’t perform any type-checking on TypeScript code. To optionally use type-checking run:
+
+```bash
+yarn add fork-ts-checker-webpack-plugin
```
-Doing this will allow React-Rails to support the .tsx extension. Additionally, it is recommended to add `ts` and `tsx` to the `server_renderer_extensions` in your application configuration:
+Add `tsconfig.json` with the following content:
+
+```json
+{
+ "compilerOptions": {
+ "declaration": false,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "lib": ["es6", "dom"],
+ "module": "es6",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "target": "es5",
+ "jsx": "react",
+ "noEmit": true
+ },
+ "exclude": ["**/*.spec.ts", "node_modules", "vendor", "public"],
+ "compileOnSave": false
+}
```
+
+Then modify the webpack config to use it as a plugin:
+
+```js
+// config/webpack/webpack.config.js
+const { webpackConfig, merge } = require("shakapacker");
+const ForkTSCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
+
+module.exports = merge(webpackConfig, {
+ plugins: [new ForkTSCheckerWebpackPlugin()],
+});
+```
+
+Doing this will allow React-Rails to support the .tsx extension. Additionally, it is recommended to add `ts` and `tsx` to the `server_renderer_extensions` in your application configuration:
+
+```ruby
config.react.server_renderer_extensions = ["jsx", "js", "tsx", "ts"]
```
### Test component
You can use `assert_react_component` to test component render:
-app/views/welcome/index.html.erb
-
```erb
+<!-- app/views/welcome/index.html.erb -->
+
<%= react_component("HelloWorld", { greeting: "Hello from react-rails.", info: { name: "react-rails" } }, { class: "hello-world" }) %>
```
```rb
class WelcomeControllerTest < ActionDispatch::IntegrationTest
@@ -402,17 +481,31 @@
delete window.Turbolinks;
```
### `getConstructor`
-Components are loaded with `ReactRailsUJS.getConstructor(className)`. This function has two built-in implementations:
+Components are loaded with `ReactRailsUJS.getConstructor(className)`. This function has two default implementations, depending on if you're using the asset pipeline or Shakapacker:
-- On the asset pipeline, it looks up `className` in the global namespace.
-- On Webpacker, it `require`s files and accesses named exports, as described in [Get started with Webpacker](#get-started-with-webpacker).
+- On the asset pipeline, it looks up `className` in the global namespace (`ReactUJS.constructorFromGlobal`).
+- On Shakapacker, it `require`s files and accesses named exports, as described in [Get started with Shakapacker](#get-started-with-shakapacker), falling back to the global namespace (`ReactUJS.constructorFromRequireContextWithGlobalFallback`).
You can override this function to customize the mapping of name-to-constructor. [Server-side rendering](#server-side-rendering) also uses this function.
+For example, the fallback behavior of
+`ReactUJS.constructorFromRequireContextWithGlobalFallback` can sometimes make
+server-side rendering errors hard to debug as it will swallow the original error
+(more info
+[here](https://github.com/reactjs/react-rails/issues/264#issuecomment-552326663)).
+`ReactUJS.constructorFromRequireContext` is provided for this reason. You can
+use it like so:
+
+```js
+// Replaces calls to `ReactUJS.useContext`
+ReactUJS.getConstructor = ReactUJS.constructorFromRequireContext(require.context('components', true));
+```
+
+
## Server-Side Rendering
You can render React components inside your Rails server with `prerender: true`:
```erb
@@ -620,10 +713,16 @@
```erb
<%= react_component('HelloMessage', {name: 'John'}, {camelize_props: true}) %>
```
+### Changing Component Templates
+
+To make simple changes to Component templates, copy the respective template file to your Rails project at `lib/templates/react/component/template_filename`.
+
+For example, to change the [ES6 Component template](https://github.com/reactjs/react-rails/blob/master/lib/generators/templates/component.es6.jsx), copy it to `lib/templates/react/component/component.es6.jsx` and modify it.
+
## Upgrading
### 2.3 to 2.4
Keep your `react_ujs` up to date, `yarn upgrade`
@@ -684,10 +783,10 @@
### HMR
Hot Module Replacement is [possible with this gem](https://stackoverflow.com/a/54846330/193785) as it does just pass through to Webpacker. Please open an issue to let us know tips and tricks for it to add to the wiki.
Sample repo that shows HMR working with `react-rails`: [https://github.com/edelgado/react-rails-hmr](https://github.com/edelgado/react-rails-hmr)
-One caveat is that currently you [cannot Server-Side Render along with HMR](https://github.com/reactjs/react-rails/issues/925#issuecomment-415469572).
+One caveat is that currently you [cannot Server-Side Render along with HMR](https://github.com/reactjs/react-rails/issues/925#issuecomment-415469572).
## Related Projects
- [webpacker-react](https://github.com/renchap/webpacker-react): Integration of React with Rails utilizing Webpack with Hot Module Replacement (HMR).
- [The React on Rails Course](https://learnetto.com/users/hrishio/courses/the-free-react-on-rails-5-course) A video course which teaches the basics of React and how to get started using it in Rails with `react-rails`.