# quilt_rails
A turn-key solution for integrating server-rendered react into your Rails app using Quilt libraries.
This document focuses on Rails integration. For details of `@shopify/react-server`'s configuration and usage, see the [react-server documentation](/packages/react-server/README.md).
## Table of Contents
1. [Quick Start](#quick-start)
1. [Advanced Use](#advanced-use)
## Quick Start
### Add Ruby dependencies
`bundle add sewing_kit quilt_rails`
First, create a Rails project using `dev init`. Next, run `rails generate quilt:install`. This will install the Node dependencies, provide a basic React app (in TypeScript) and mounts the Quilt engine inside of your `config/routes.rb` file.
## Manual Installation
You can also perform the steps within the rake task manually by following the guide below.
### Install Dependencies
```sh
# Add Node dependencies
yarn add @shopify/sewing-kit @shopify/react-server
# Optional - add Polaris and quilt libraries
yarn add @shopify/polaris @shopify/react-self-serializers react react-dom
yarn
dev up
```
### Add JavaScript
sewing_kit looks for JavaScript in `app/ui/index.js`. The code in `index.js` (and any imported JS/CSS) will be built into a `main` bundle.
### Rails Setup
There are 2 ways to consume this package.
### Option 1: Mount the Engine
Add the engine to `routes.rb`.
```ruby
# config/routes.rb
Rails.application.routes.draw do
# ...
mount Quilt::Engine, at: '/'
end
```
Where `at` is the path where your App will respond with the React App. If you only want a sub-section of routes to respond with the React App, you can pass in the path to that sub-section here. For example:
```ruby
# config/routes.rb
Rails.application.routes.draw do
# ...
mount Quilt::Engine, at: '/path/to/react'
end
```
### Option 2: Add your react controller and routes
Create a `ReactController` to handle react requests.
```ruby
class ReactController < ApplicationController
include Quilt::ReactRenderable
def index
render_react
end
end
```
Have your routes wired up to default to your react controller.
```ruby
get '/*path', to: 'react#index'
root 'react#index'
```
## Minimal Project Layout
```
├── Gemfile (must contain "gem 'sewing_kit" and "gem 'quilt_rails'")
├── package.json (must specify '@shopify/sewing-kit' and `@shopify/react-server` as 'dependencies')
│
└── app
└── ui
│ └─- index.js
└── controllers
└─- react_controller (see above)
```
## Example minimal React/Polaris/Quilt entrypoint
```tsx
// app/ui/index.tsx
import React from 'react';
import {AppProvider, Page, Card} from '@shopify/polaris';
function App() {
return (
Hi there
);
}
export default App;
```
## Rails Generators
### `quilt:install`
Installs the Node dependencies, provide a basic React app (in TypeScript) and mounts the Quilt engine inside of your `config/routes.rb` file.
### `sewing_kit:install`
Adds a basic `sewing-kit.config.ts` file.
## Advanced use
### Interacting with the request / response in your React code
React-server sets up [@shopify/react-network](https://github.com/Shopify/quilt/blob/master/packages/react-network/src/hooks.ts#L25) for you, so most interactions with the request or response can be done from inside your React code.
#### Example: getting headers
```tsx
// app/ui/index.tsx
import React from 'react';
import {AppProvider, Page, Card} from '@shopify/polaris';
import {useRequestHeader} from '@shopify/react-network';
function App() {
// get `some-header` from the request that was sent through Rails
const someHeaderICareAbout = useRequestHeader('some-header');
return (
{someHeaderICareAbout}
Hi there
);
}
export default App;
```
#### Example: redirecting
```tsx
// app/ui/index.tsx
import React from 'react';
import {AppProvider, Page, Card} from '@shopify/polaris';
import {useRedirect} from '@shopify/react-network';
function App() {
// redirect to google as soon as we render
useRedirect('www.google.com');
return (
Hi there
);
}
export default App;
```
### Customizing the node server
By default, sewing-kit bundles in `@shopify/react-server-webpack-plugin` for `quilt_rails` applications to get you up and running fast without needing to manually write any node server code. If you would like to customize what data your react application receives from the incoming request, you can add your own `server.js` / `server.ts` file to the app folder.
```
└── app
└── ui
└─- app.js
└─- index.js
└─- server.js
```
```tsx
// app/ui/server.tsx
import '@shopify/polyfills/fetch';
import {createServer} from '@shopify/react-server';
import {Context} from 'koa';
import React from 'react';
import App from './app';
// you could create your own server from scratch, but the easiest way to is using `@shopify/react-server`
// https://github.com/Shopify/quilt/blob/master/packages/react-server/README.md#L8
const app = createServer({
port: process.env.PORT ? parseInt(process.env.PORT, 10) : 8081,
ip: process.env.IP,
assetPrefix: process.env.CDN_URL || 'localhost:8080/assets/webpack',
serverMiddleware: [(ctx, next) => {
// you can add your own middleware to extend the server's functionality.
console.log('I am a custom middleware!');
await next();
}]
render: (ctx, {locale}) => {
const whatever = /* do something special with the koa context */;
// any special data we add to the incoming request in our rails controller we can access here to pass into our component
return ;
},
});
export default app;
```
### Isomorphic state
With SSR enabled React apps, state must be serialized on the server and deserialized on the client to keep it consistent. With `@shopify/react-server`, the main way you will accomplish is using [`@shopify/react-html`](https://github.com/Shopify/quilt/tree/master/packages/react-html)'s [`useSerialized`](https://github.com/Shopify/quilt/tree/master/packages/react-html#in-your-application-code) hook to implement [self-serializers](https://github.com/Shopify/quilt/blob/master/packages/react-self-serializers/README.md#self-serializers). We offer some common ones out of the box in [`@shopify/react-self-serializers`](https://github.com/Shopify/quilt/blob/master/packages/react-self-serializers/README.md#self-serializers).