Aplicació Reactjs a través del servidor web Express
_
_
Tutorial
Seguim
La idea és que quan desenvolupem una app amb React fem:
$ npm run start (o npm start)
i la visulitzem pel port 3000:
i el punt d'entrada d'aqueta app és el script src/App.js. Aquest seria el mode de desenvolupament.
Ara bé, en producció hem de servir l'app a través d'un servidor web (Express) per un altre port (per ex 8080), i el punt d'entrada ha de ser el script index.html (public/index.html i build/index.html).
Anem a veure com fer-ho.
Step 1: Install create-react-app
$ create-react-app your-app-name $ cd your-app-name
Step 2: Install packages for create react app
$ npm install;
Podem comprovar que funciona fent:
$ npm start
- localhost:3000
El punt d'entrada és src/App.js.
Step 2b: npm run build
Ara podem desplegar aquesta aplicació:
$ npm run build > your-app-name@0.1.0 build /home/joan/M06_WEC_1920/UF2/your-app-name > react-scripts build Creating an optimized production build... Compiled successfully. File sizes after gzip: 39.39 KB build/static/js/2.ed50ce24.chunk.js 777 B build/static/js/runtime-main.7a59697d.js 651 B build/static/js/main.6d4ec6a5.chunk.js 547 B build/static/css/main.5f361e03.chunk.css The project was built assuming it is hosted at /. You can control this with the homepage field in your package.json. The build folder is ready to be deployed. You may serve it with a static server: serve -s build
$ serve -s build
I funciona:
- localhost:5000
El punt d'entrada és build/index.html
Si fem:
$ serve -s public
El punt d'entrada és public/index.html (editem aquest fitxer)
NOTA: el script build/index.html és el mateix que public/index.html. En el moment que fem el build es copia public/index.html a build/index.html.
Step 3: Install express
$ npm install express --save
Step 4: Create a server.js file
script server.js: (es crea a l'arrel del projecte, cd your-app-name)
const express = require('express'); const bodyParser = require('body-parser') const path = require('path'); const app = express(); app.use(express.static(path.join(__dirname, 'build'))); app.get('/ping', function (req, res) { return res.send('pong'); }); app.get('/', function (req, res) { res.sendFile(path.join(__dirname, 'build', 'index.html')); }); app.listen(process.env.PORT || 8080);
Step 5: Update your package.json
Add the following to your package.json
"proxy": "http://localhost:8080"
Queda de la següent manera:
... "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "proxy": "http://localhost:8080", ...
Step 6: Start the express server
Arrenquem el servidor web:
$ node server.js
I l'aplicació la tenim disponible a:
- localhost:8080
El punt d'entrada és el script build/index.html. Això ho podem comprovar si modifiquem aquest fitxer(posem alguna cosa després del body). Si volem que el punt d'entrada sigui public/index.html hem de modificar les línies app.use i res.sendFile del server.js.
NOTA. Això no cal fer-ho. public/index.html i build/index.html. El primer es copia en el segon quan fem el npm run build.
Step 7. Conclusions
Ara tinc un entorn de producció a través del port 8080.
Puc continuar desenvolupant fent:
$ npm start
i puc modificar el script App.js i veure els canvis en calent pel port localhost:3000. Ara bé, no puc esperar veure aquests canvis pel port 8080. Per veure els canvis he de fer el npm run build.
Aplicació pràctica: Simple example of a ReactJS and OpenLayers map component
Anem a posar-ho en pràctica i anem a fer el Hola món de Openlayers per visualitzar un mapa.
Installing OpenLayers for ReactJS:
$ npm install ol --save $ npm install proj4 @material-ui/core --save
Si mirem package.json, veiem quines són les dependències, i crec que també és important fer:
$ npm install react --save $ npm install react-dom --save $ npm install react-scripts --save
Creem el script src/js/components/OLMapFragment.js: (aquest és el component principal de OpenLayers)
import React from 'react' import Grid from '@material-ui/core/Grid' // Start Openlayers imports import { Map, View } from 'ol' import { GeoJSON, XYZ } from 'ol/format' import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer' import { Vector as VectorSource, OSM as OSMSource, XYZ as XYZSource, TileWMS as TileWMSSource } from 'ol/source' import { Select as SelectInteraction, defaults as DefaultInteractions } from 'ol/interaction' import { Attribution, ScaleLine, ZoomSlider, Zoom, Rotate, MousePosition, OverviewMap, defaults as DefaultControls } from 'ol/control' import { Style, Fill as FillStyle, RegularShape as RegularShapeStyle, Stroke as StrokeStyle } from 'ol/style' import { Projection, get as getProjection } from 'ol/proj' // End Openlayers imports class OLMapFragment extends React.Component { constructor(props) { super(props) this.updateDimensions = this.updateDimensions.bind(this) } updateDimensions(){ const h = window.innerWidth >= 992 ? window.innerHeight : 400 this.setState({height: h}) } componentWillMount(){ window.addEventListener('resize', this.updateDimensions) this.updateDimensions() } componentDidMount(){ // Create an Openlayer Map instance with two tile layers const map = new Map({ // Display the map in the div with the id of map target: 'map', layers: [ new TileLayer({ source: new XYZSource({ url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png', projection: 'EPSG:3857' }) }), new TileLayer({ source: new TileWMSSource({ url: 'https://ahocevar.com/geoserver/wms', params: { layers: 'topp:states', 'TILED': true, }, projection: 'EPSG:4326' }), name: 'USA' }), ], // Add in the following map controls controls: DefaultControls().extend([ new ZoomSlider(), new MousePosition(), new ScaleLine(), new OverviewMap() ]), // Render the tile layers in a map view with a Mercator projection view: new View({ projection: 'EPSG:3857', center: [0, 0], zoom: 2 }) }) } componentWillUnmount(){ window.removeEventListener('resize', this.updateDimensions) } render(){ const style = { width: '100%', height:this.state.height, backgroundColor: '#cccccc', } return ( <Grid container> <Grid item xs={12}> <div id='map' style={style} > </div> </Grid> </Grid> ) } } export default OLMapFragment
El script principal de React no és App.js, sinó index.js (que normalment crida a App.js). Per tant, anem a modifificar-lo:
script src/index.js:
import React from 'react' import { render} from 'react-dom' import OLMapFragment from './js/components/OLMapFragment' render( <OLMapFragment /> , document.getElementById('react-container') )
veiem com s'importa el component OLMapFragment, i queda clar la ruta que ha de tenir OLMapFragment.js.
I finalment falta index.html, que per tot el que hem dit ha d'estar a public/index.html.
script public/index.html:
<!DOCTYPE html> <html class="no-js" lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content='ie=edge'> <title>Openlayers React</title> <meta name="description" content="Explore planet Mars"> <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" /> <!-- material-ui prerequisites --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <!-- end material-ui prerequisites --> <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css" /> </head> <body> <!--[if lte IE 8] <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com">upgrade your browser</a></p> <![endif]--> <div id='react-container'></div> </body> </html>
Aquí és on tenim el contenidor principal del mapa, i on tenim els links dels estils i fonts.
Now, run the ReactJS project with a web server and open the web page with an Internet browser.
Per tant, amb tot el que hem dit:
$ npm start
$ npm run build $ serve -s build
i a través del Express:
$ node server.js
- localhost:8080
creat per Joan Quintana Compte, abril 2020