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