- Instalamos nodejs
- A partir de aquí, tenemos dos opciones:
- Usar create-react-app
- Configurar el proyecto manualmente
Usar create-react-app
npx create-react-app mi-aplicacion
Configurar el proyecto manualmente
Es buena idea partir del siguiente proyecto que ya tiene una configuración con únicamente las cosas que necesitamos habitualmente. Para ejecutar el primer comando necesitaremos tener git instalado.
git clone https://github.com/monteserin/react-template.git
Si no queremos descargar la carpeta .git:
npx degit monteserin/react-template
El código relevante que está dentro de esta plantilla es:
package.json
{
"name": "template",
"version": "1.0.0",
"description": "",
"main": "./dist",
"scripts": {
"build": "cross-env NODE_ENV=production webpack",
"start": "cross-env NODE_ENV=development webpack serve",
"upload": "node ./bin/upload.js",
"remove-node_modules": "npx rimraf ./node_modules"
},
"author": "Pablo Monteserín",
"license": "ISC",
"devDependencies": {
"@babel/cli": "7.12.7",
"@babel/core": "7.12.7",
"@babel/plugin-proposal-optional-chaining": "7.12.7",
"@babel/plugin-transform-runtime": "7.12.1",
"@babel/preset-env": "7.12.7",
"@babel/preset-react": "7.12.7",
"@babel/runtime": "7.12.5",
"babel-loader": "8.2.1",
"babel-plugin-import-directory": "1.1.0",
"babel-plugin-inline-import": "3.0.0",
"babel-plugin-module-resolver": "4.0.0",
"babel-plugin-wildcard": "6.0.0",
"babel-preset-react": "6.24.1",
"cross-env": "7.0.2",
"file-loader": "6.2.0",
"html-webpack-plugin": "4.5.0",
"react-styleguidist": "11.1.3",
"url-loader": "4.1.1",
"webpack": "5.6.0",
"webpack-cli": "4.2.0",
"webpack-dev-server": "3.11.0"
},
"dependencies": {
"axios": "0.21.0",
"easy-ftp": "0.4.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-router": "5.2.0",
"react-router-dom": "5.2.0",
"styled-components": "5.2.1"
}
}
El webpack.config.js se encarga de configurar el empaquetado (bundle) de la aplicación que vamos a generar:
/webpack.config.js
// Cargamos un módulo nativo de node que nos gestiona rutas
const path = require('path');
// Cargamos webpack para definir plugins propios
const webpack = require('webpack');
// Este módulo inyecta el bundle en el HTML
const HtmlWebpackPlugin = require('html-webpack-plugin');
// Constantes con los paths de la aplicación
const paths = {
ROOT: path.resolve(__dirname),
DIST: path.resolve(__dirname, 'dist'),
SRC: path.resolve(__dirname, 'src'),
};
//process.env nos permite acceder a las variables de entorno del sistema operativo
//Accedemos a las variables definidas de entorno que hemos definido en el package.json
const development = process.env.NODE_ENV === 'development';
// Si usamos react-router y subimos nuestra aplicación a producción, habrá que asignar a la variable publicPath la ruta donde se va a alojar el proyecto
const publicPath = './';
// Set plugins
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: './src/index.html',
hash: !development,
});
const processEnvPlugin = new webpack.DefinePlugin({
'process.env': {
PUBLIC_PATH: JSON.stringify(publicPath),
},
});
module.exports = {
entry: path.join(paths.SRC, 'index.js'),
output: {
path: paths.DIST,
filename: 'bundle.js',
publicPath: publicPath || '/',
},
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.(jpg|jpeg|gif|png)$/,
loader: 'file-loader',
options: {
publicPath: `${publicPath}/statics/images/`,
outputPath: './statics/images/',
name: '[name].[ext]',
},
},
{
test: /\.(wav|mp3)$/,
loader: 'file-loader',
options: {
publicPath: `${publicPath}/statics/audio/`,
outputPath: './statics/audio/',
name: '[name].[ext]',
},
},
{
test: /\.(mp4)$/,
loader: 'file-loader',
options: {
publicPath: `${publicPath}/statics/video/`,
outputPath: './statics/video/',
name: '[name].[ext]',
},
},
{
test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
loader: 'file-loader',
options: {
publicPath: `${publicPath}/statics/vectors/`,
outputPath: './statics/vectors/',
name: '[name].[ext]',
},
},
],
},
resolve: {
extensions: ['.js'],
},
devServer: {
historyApiFallback: true,
disableHostCheck: true,
hot: false,
port: 8085,
open: true,
},
optimization: {
minimize: !development,
},
mode: process.env.NODE_ENV,
devtool: development && 'source-map',
plugins: [
HtmlWebpackPluginConfig,
processEnvPlugin,
],
};
Babel se encarga de transpilar nuestro código Javascript EcmaScript 6+ ( preset-env ) y nuestro código JSX ( preset-react ) a versiones más antiguas y por tanto más aceptadas por la mayoría de los nacegadores.
Un preset es una agrupación de plugins. Los plugins definirán como se hará la transpilación en babel.
Cómo ves, primero ponemos las agrupaciones de plugins (presets) y luego los plugins sueltos.
/.babelrc
{
"presets": [
"@babel/preset-env",
["@babel/preset-react", {
"runtime": "automatic"
}]
],
"plugins": [
"@babel/plugin-transform-runtime"
]
}
/src/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);
/src/App.js
import React from 'react';
export default () => (
<div>
hola
</div>
);
/bin/upload.js
const EasyFtp = require('easy-ftp');
const ftp = new EasyFtp();
const config = {
"name": "pablomonteserin.com",
"host": "example.com",
"port": 21,
"type": "ftp",
"username": "usuario",
"password": "password",
};
//(connect)
ftp.connect(config);
ftp.upload("./dist/**", "/www/termine", function(err) {
if(err) {
return console.error(err);
}
console.info('Deployed!');
});
Arrancar una aplicación
npm start