Skip to content

Instantly share code, notes, and snippets.

@peterc
Last active February 20, 2025 18:20

Revisions

  1. peterc revised this gist Jan 18, 2025. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -156,6 +156,9 @@ cd client
    npm run dev
    ```

    > [!IMPORTANT]
    You MUST use the approach above (running the app through Vite) if you want the niceties of Tailwind compilation, etc. during development. While `npm run build` will generate the CSS and JS needed for testing with Sinatra or for deployment, this is not how you would want to do things during development as it's much slower and more manual.

    For deployment or to test using Sinatra alone:
    ```bash
    cd client
  2. peterc revised this gist Jan 13, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ echo "gem 'puma'" >> Gemfile
    bundle install
    ```

    Then populate `app.rb`:
    Then populate `app.rb` (this just handles CORS, serving up the eventual public files, and provides a basic /api/hello endpoint for testing from the React frontend):

    ```ruby
    require 'sinatra'
  3. peterc revised this gist Jan 13, 2025. No changes.
  4. peterc revised this gist Jan 13, 2025. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -162,4 +162,6 @@ cd client
    npm run build
    cd ..
    ruby app.rb # or package / containerize and deploy at this point
    ```
    ```

    Tada!
  5. peterc revised this gist Jan 13, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    Let's say you want to use Ruby for the backend of a basic webapp but React on the frontend. Here's how.

    *(Note: All tested on January 13, 2025 with Ruby 3.3. Configs may change over time.)*
    *(Note: All tested on January 13, 2025 with Ruby 3.3, Sinatra 4.1.1, and React 18.3. Configs may change over time.)*

    First, create the app folder and set up Sinatra:

  6. peterc revised this gist Jan 13, 2025. 1 changed file with 9 additions and 12 deletions.
    21 changes: 9 additions & 12 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@ end

    set :public_folder, 'public'

    # API routes
    # An example API route for basic testing purposes
    get '/api/hello' do
    { message: 'Hello from Sinatra!' }.to_json
    end
    @@ -46,17 +46,14 @@ Next we can get the JavaScript part sorted:
    npm create vite@latest client -- --template react
    cd client

    # Install frontend dependencies
    npm install
    npm install -D tailwindcss postcss autoprefixer

    # Initialize Tailwind
    npx tailwindcss init -p
    ```

    Tailwind, Vite, and React need a bit of configuring at this point.

    `client/tailwind.config.js` can become:
    `client/tailwind.config.js` then needs to become:

    ```js
    /** @type {import('tailwindcss').Config} */
    @@ -72,7 +69,7 @@ export default {
    }
    ```

    `client/vite.config.js` needs tweaking the proxy through the Sinatra app during dev:
    `client/vite.config.js` needs tweaking to proxy through the Sinatra app during dev so React can reach the backend routes:

    ```js
    import { defineConfig } from 'vite'
    @@ -82,7 +79,7 @@ export default defineConfig({
    plugins: [react()],
    server: {
    proxy: {
    '/api': 'http://localhost:4567' // Assuming Sinatra runs on 4567
    '/api': 'http://localhost:4567' // Assuming Sinatra runs on 4567, as it usually does
    }
    },
    build: {
    @@ -91,7 +88,7 @@ export default defineConfig({
    })
    ```

    `client/src/App.jsx` can then become:
    `client/src/App.jsx` can then become (for basic testing purposes):

    ```jsx
    import { useState } from 'react'
    @@ -138,21 +135,21 @@ const App = () => {
    export default App
    ```

    And we need this in `client/src/index.css`:
    To get Tailwind working, we need this in `client/src/index.css` (append or replace, as you wish):

    ```css
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    ```

    Finally in one terminal run this to get the Sinatra backend running:
    Finally, in one terminal run this to get the Sinatra backend running (needed in any case to serve up the backend route):

    ```bash
    ruby app.rb
    ```

    Then in dev, run this to use Vite:
    Then in dev, run this to use Vite to make the frontend easier to develop:

    ```bash
    cd client
    @@ -164,5 +161,5 @@ For deployment or to test using Sinatra alone:
    cd client
    npm run build
    cd ..
    ruby app.rb
    ruby app.rb # or package / containerize and deploy at this point
    ```
  7. peterc revised this gist Jan 13, 2025. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,8 @@

    Let's say you want to use Ruby for the backend of a basic webapp but React on the frontend. Here's how.

    *(Note: All tested on January 13, 2025 with Ruby 3.3. Configs may change over time.)*

    First, create the app folder and set up Sinatra:

    ```bash
  8. peterc revised this gist Jan 13, 2025. 1 changed file with 40 additions and 12 deletions.
    52 changes: 40 additions & 12 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -92,20 +92,48 @@ export default defineConfig({
    `client/src/App.jsx` can then become:

    ```jsx
    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'

    export default defineConfig({
    plugins: [react()],
    server: {
    proxy: {
    '/api': 'http://localhost:4567' // Assuming Sinatra runs on 4567
    import { useState } from 'react'

    const App = () => {
    const [message, setMessage] = useState('')
    const [loading, setLoading] = useState(false)

    const fetchMessage = async () => {
    setLoading(true)
    try {
    const response = await fetch('/api/hello')
    const data = await response.json()
    setMessage(data.message)
    } catch (error) {
    setMessage('Error fetching message')
    console.error('Error:', error)
    } finally {
    setLoading(false)
    }
    },
    build: {
    outDir: '../public'
    }
    })

    return (
    <div className="p-8 max-w-md mx-auto">
    <h1 className="text-3xl font-bold mb-4">Sinatra + React App</h1>

    <button
    onClick={fetchMessage}
    disabled={loading}
    className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50"
    >
    {loading ? 'Loading...' : 'Fetch Message'}
    </button>

    {message && (
    <div className="mt-4 p-4 border rounded bg-gray-50">
    <p className="text-gray-800">{message}</p>
    </div>
    )}
    </div>
    )
    }

    export default App
    ```

    And we need this in `client/src/index.css`:
  9. peterc revised this gist Jan 13, 2025. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ Let's say you want to use Ruby for the backend of a basic webapp but React on th

    First, create the app folder and set up Sinatra:

    ```
    ```bash
    mkdir my-sinatra-react-app
    cd my-sinatra-react-app

    @@ -40,7 +40,7 @@ end

    Next we can get the JavaScript part sorted:

    ```
    ```bash
    npm create vite@latest client -- --template react
    cd client

    @@ -56,7 +56,7 @@ Tailwind, Vite, and React need a bit of configuring at this point.

    `client/tailwind.config.js` can become:

    ```
    ```js
    /** @type {import('tailwindcss').Config} */
    export default {
    content: [
    @@ -72,7 +72,7 @@ export default {

    `client/vite.config.js` needs tweaking the proxy through the Sinatra app during dev:

    ```
    ```js
    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'

    @@ -91,7 +91,7 @@ export default defineConfig({

    `client/src/App.jsx` can then become:

    ```
    ```jsx
    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'

    @@ -118,19 +118,19 @@ And we need this in `client/src/index.css`:

    Finally in one terminal run this to get the Sinatra backend running:

    ```
    ```bash
    ruby app.rb
    ```

    Then in dev, run this to use Vite:

    ```
    ```bash
    cd client
    npm run dev
    ```

    For deployment or to test using Sinatra alone:
    ```
    ```bash
    cd client
    npm run build
    cd ..
  10. peterc revised this gist Jan 13, 2025. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    # How to set up a basic Sinatra + React webapp in 2025

    Let's say you want to use Ruby for the backend of a basic webapp but React on the frontend. Here's how.

    First, create the app folder and set up Sinatra:

    ```
    @@ -12,7 +14,7 @@ echo "gem 'puma'" >> Gemfile
    bundle install
    ```

    Then populate app.rb like so:
    Then populate `app.rb`:

    ```ruby
    require 'sinatra'
  11. peterc revised this gist Jan 13, 2025. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    # How to set up a basic Sinatra + React webapp in 2025

    First, create the app folder and set up Sinatra:

    ```
  12. peterc created this gist Jan 13, 2025.
    134 changes: 134 additions & 0 deletions sinatra-react.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    First, create the app folder and set up Sinatra:

    ```
    mkdir my-sinatra-react-app
    cd my-sinatra-react-app
    bundle init
    echo "gem 'sinatra'" >> Gemfile
    echo "gem 'puma'" >> Gemfile
    bundle install
    ```

    Then populate app.rb like so:

    ```ruby
    require 'sinatra'
    require 'json'

    before do
    content_type :json
    headers 'Access-Control-Allow-Origin' => '*' if settings.development?
    end

    set :public_folder, 'public'

    # API routes
    get '/api/hello' do
    { message: 'Hello from Sinatra!' }.to_json
    end

    get '/' do
    content_type 'text/html'
    send_file File.join(settings.public_folder, 'index.html')
    end
    ```

    Next we can get the JavaScript part sorted:

    ```
    npm create vite@latest client -- --template react
    cd client
    # Install frontend dependencies
    npm install
    npm install -D tailwindcss postcss autoprefixer
    # Initialize Tailwind
    npx tailwindcss init -p
    ```

    Tailwind, Vite, and React need a bit of configuring at this point.

    `client/tailwind.config.js` can become:

    ```
    /** @type {import('tailwindcss').Config} */
    export default {
    content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
    ],
    theme: {
    extend: {},
    },
    plugins: [],
    }
    ```

    `client/vite.config.js` needs tweaking the proxy through the Sinatra app during dev:

    ```
    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    export default defineConfig({
    plugins: [react()],
    server: {
    proxy: {
    '/api': 'http://localhost:4567' // Assuming Sinatra runs on 4567
    }
    },
    build: {
    outDir: '../public'
    }
    })
    ```

    `client/src/App.jsx` can then become:

    ```
    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    export default defineConfig({
    plugins: [react()],
    server: {
    proxy: {
    '/api': 'http://localhost:4567' // Assuming Sinatra runs on 4567
    }
    },
    build: {
    outDir: '../public'
    }
    })
    ```

    And we need this in `client/src/index.css`:

    ```css
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    ```

    Finally in one terminal run this to get the Sinatra backend running:

    ```
    ruby app.rb
    ```

    Then in dev, run this to use Vite:

    ```
    cd client
    npm run dev
    ```

    For deployment or to test using Sinatra alone:
    ```
    cd client
    npm run build
    cd ..
    ruby app.rb
    ```