Come usare React con Webpacker e Rails 5.2

L'esperienza utente è cambiata molto negli ultimi anni, portando con sé nuove complessità e sfide. Oggigiorno, gli utenti si aspettano interfacce molto più ricche e articolate: dati aggiornati in tempo reale, comunicazioni asincrone, effetti sugli elementi della pagina e tanto altro.
Per nostra fortuna, ci vengono in aiuto svariate librerie JavaScript che rendono semplice l'implementazione di questi comportamenti.
In questo articolo ci concentreremo su React per la parte front end e Ruby on Rails per la parte back end. Per facilitare l'integrazione useremo alcuni accorgimenti, come ad esempio l'utilizzo di Webpacker.
Tempo di lettura: 5 minuti

Iniziamo

Per poter creare un’applicazione React è necessario includere all’interno del progetto Rails la libreria Webpacker. L’obiettivo di Webpacker è di semplificare l’utilizzo del pre-processore JavaScript e del bundle webpack all’interno di Rails. È possible utilizzarlo in concomitanza con l’asset pipeline di Rails, facendo gestire a quest'ultimo le immagini e la compilazione dei fail sass/scss.

Installazione e configurazione di Webpack

Per includere la libreria nel Gemfile è sufficiente eseguire il comando:

$ bundle add webpacker

Successivamente possiamo installare webpacker con:

$ bundle exec rails webpacker:install

    create config/webpacker.yml
Copying webpack core config
    create config/webpack
    create config/webpack/development.js
    create config/webpack/environment.js
    create config/webpack/production.js
    create config/webpack/test.js
Creating JavaScript app source directory
    create app/javascript
    create app/javascript/packs/application.js
Copying binstubs
    exist  bin
    create bin/webpack
    create bin/webpack-dev-server

Al termine dell’operazione, avremo:

  • un file di configurazione webpacker.yml;
  • le configurazioni dei vari ambienti di sviluppo (development, production e test);
  • una directory app/javascript/packs con all’interno il file application.js;
  • alcuni eseguibili all’interno di bin.

In azione

Per prima cosa dobbiamo creare un nuovo controller con un’azione, ad esempio pages#home con il comando:

$ rails generate controller pages home

Successivamente configuriamo il router di Rails impostando URL di default:

# config/routes

# ...
root to:"pages#home" 
# ... 

Modifichiamo l’application layout:

# app/views/layouts/application.html.erb
...
<%= javascript_pack_tag ’application’ %>
...

Questo comando include il file pre-buildato application-{hash}.js all’interno della nostro layout. Per poter buildare i vari file JavaScript presenti all’interno della cartella app/javascript/packs è necessario eseguire il comando bin/webpack-dev-server.

Lanciando il comando bin/webpack-dev-server e bundle exec rails server, se la configurazione è andata a buon fine, dovremmo vedere nella console del browser il messaggio “Hello World from Webpacker”.

Check

Questo messaggio viene stampato dal file app/javascript/packs/application.js

Configurazione di React

Per poter utilizzare installare e configurare React è sufficiente lanciare:

$ bundle exec rails webpacker:install:react

Copying babel.config.js to app root directory
    force  babel.config.js
Copying react example entry file to app/javascript/packs
    create  app/javascript/packs/hello_react.jsx
Updating webpack paths to include .jsx file extension
    insert  config/webpacker.yml
Installing all react dependencies
    run yarn add \
        react react-dom \
        @babel/preset-react \
        prop-types \
        babel-plugin-transform-react-remove-prop-types from "."

Lo script di installazione crea in automatico il file hello_react.jsx nella cartella app/javascript/packs/.

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const Hello = props => (
  <div>Hello {props.name}!</div>
)

Hello.defaultProps = {
  name: 'David'
}

Hello.propTypes = {
  name: PropTypes.string
}

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello name="React" />,
    document.body.appendChild(document.createElement('div')),
  )
})
Ed all’interno della vista home aggiungiamo il nuovo “pack”:
# app/views/pages/home.html.erb

...
<%= javascript_pack_tag 'hello_react' %>
...

Compilazione degli asset di webpack

È possibile fornire gli asset generati da webpack in due modalità:

  • Development: utilizzando l’eseguibile:
    bin/webpack-dev-server

    In questa modalità sarà eseguito un server (raggiungibile all’indirizzo http://localhost:3035/) che fornirà i file senza salvarli su disco. In questa modalità è possibile usufruire dell’hot reload.

  • Production: utilizziamo il comando
    bundle exec rails assets:precompile
    In questo modo la build sarà fornita nella directory public/packs/js.

Se non fosse disponibile né il server né la cartella public/packs, verranno in ogni caso compilati gli asset.

Processing by PagesController#home as HTML
  Rendering pages/home.html.erb within layouts/application
  Rendered pages/home.html.erb within layouts/application (0.5ms)
[Webpacker] Compiling…
[Webpacker] Compiled all public/packs

Condividere l'ENV tra Rails e Webpacker

È possibile accedere alle variabili d'ambiente utilizzando due sistemi: passandole come parametro oppure utilizzando il file .env (metodo consigliato).

Nel primo caso avremo:

FOO=hello BAR=world ./bin/webpack-dev-server

Nell'app possiamo accedere alle variabili d'ambiente tramite process.env:

console.log(process.env.FOO)

Nel secondo caso possiamo aggiungere la libreria dotenv al nostro package.json. Successivamente dovremo aggiornare la configurazione di webpacker:

// config/webpack/environment.js

...
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
const dotenv = require('dotenv')

const dotenvFiles = [
  `.env.${process.env.NODE_ENV}.local`,
  '.env.local',
  `.env.${process.env.NODE_ENV}`,
  '.env'
]
dotenvFiles.forEach((dotenvFile) => {
  dotenv.config({ path: dotenvFile, silent: true })
})

environment.plugins.prepend('Environment', new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env))))

module.exports = environment

Rimandiamo alla documentazione ufficiale per i dettagli implementativi.

In conclusione

Utilizzando questa libreria è possibile rendere estremamente facile l'integrazione con i framework JavaScript (React, Vue, Angular, etc.) "ammodernando" l'applicazione lato frontend.

Ti è piaciuta la guida? Segui il nostro blog per nuovi tutorial ogni mese!
Hai trovato questo post interessante?Scopri chi siamo