Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.
Tenemos dos opciones:
- Usar express-generator:La siguiente herramienta genera una estructura de carpetas y ficheros adecuada para realizar desarrollos con el módulo express. Para instalarla:
npm i express-generator --g
Para usuarla:
express proyecto --hbs //hbs indica el sistema de plantillas a utilizar
- Creando el proyecto con express manualmente (recomendado):
package.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"local": "cross-env NODE_ENV=development webpack --config webpack.config.js --watch",
"start-local": "nodemon --watch build --exec \"node build/bundle.js\"",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
"start": "node ./build/bundle.js",
"heroku": "npm run build && git add . && git commit -m 'subida' && git push heroku master"
},
"author": "Pablo Monteserín",
"license": "ISC",
"dependencies": {
"@babel/runtime": "^7.5.5",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"easy-ftp": "^0.4.1",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mysql2": "^2.1.0",
"sequelize": "^5.21.3",
"socket.io": "^2.3.0"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-decorators": "^7.7.4",
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.5.5",
"@babel/plugin-transform-spread": "^7.2.2",
"@babel/preset-env": "^7.5.5",
"@babel/runtime": "^7.5.5",
"cross-env": "^5.2.0",
"babel-cli": "^6.26.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.2",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"nodemon": "^1.19.1",
"terser-webpack-plugin": "^1.3.0",
"webpack": "^4.37.0",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2",
"webpack-node-externals": "^1.7.2"
}
}
webpack.config.js
const path = require('path');
const webpackNodeExternals = require('webpack-node-externals');
const TerserPlugin = require('terser-webpack-plugin');
const development = process.env.NODE_ENV === 'development';
// Constant with our paths
const paths = {
OUTPUT: path.resolve(__dirname, 'build'),
};
module.exports = {
entry: {
bundle: './src/index.js',
},
target: 'node',
node: {
__filename: true,
__dirname: true,
},
output: {
path: paths.OUTPUT,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader',
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
optimization: {
minimizer: [
new TerserPlugin({
sourceMap: development,
cache: true,
parallel: true,
terserOptions: {
compress: true,
ecma: 6,
mangle: true,
},
}),
],
},
externals: [webpackNodeExternals()],
mode: process.env.NODE_ENV,
devtool: development && 'source-map',
};
./src/controllers/index.js
import Api from './api';
const Controllers = (app) => {
Api(app);
};
export default Controllers;
.babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-spread",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-transform-runtime"
]
}
./src/controllers/api/index.js
import * as Model from '../../models';
import { asyncHandler } from '../../middlewares/error-handler';
import jwt from 'jsonwebtoken';
const SECRET = 'uuuu';
const StartApiServer = (app) => {
app.get('/', function (req, res, next) {
res.send("va bien la cosa")
});
app.post('/alumnoIntroduceCodigo', asyncHandler(async (req, res, next) => {
const cod = req.body.cod;
if (!cod) return res.sendStatus(400);
const students = await Model.searchStudentsFromClass(cod.trim());
res.send(students);
}));
}
./src/controllers/sockets/index.js
import socketIO from 'socket.io';
import * as Model from '../../models';
import { socketHandler } from '../../middlewares/error-handler';
const StartSocketServer = (server) => {
const io = socketIO(server);
io.on('connection', function (socket) {
socket.on('alguienTermino', socketHandler(async (msg) => {
await Model.heterminado(msg.alumnoId);
io.emit('alguienTermino', msg);
}));
}
./src/models/database.js
const { Sequelize } = require('sequelize');
const dbHeroku = {
host: 'remote.com',
user: 'remoteUser',
password: 'remotePassword',
database: 'remoteDB',
connectionLimit : 10,
};
const dbLocal = {
host: 'localhost',
user: 'root',
password: '',
database: 'databaseLocal'
}
const { database, user, password, host } = dbHeroku;
export default new Sequelize(database, user, password, {
host,
dialect: 'mysql',
});
./src/models/index.js
import db from './database';
const { QueryTypes } = require('sequelize');
export const searchStudentsFromClass = cod => db.query(
'SELECT * FROM alumnos WHERE cod = :cod',
{
replacements: { cod },
type: QueryTypes.SELECT
}
)
./src/middlewares/error-handler.js
/*Tenemos una función que recibe como parámetro la función de cada controlador,
la ejecuta (resolve)
y si hay algún error, lo mostrará por consola y lanzará un 500
*/
export const asyncHandler = controller => (req, res, next) => Promise
.resolve(controller(req, res, next))
.catch((err) => {
console.error('Request error:' + err.toString());
if (err) return res.sendStatus(500).send();
});
export const socketHandler = controller => msg => Promise
.resolve(controller(msg))
.catch((err) => {
console.error('Socket error:' + err);
});
./src/middlewares/index.js
import cors from 'cors';
import bodyParser from 'body-parser';
const Middlewares = (app) => {
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(cors()) // Use this after the variable declaration
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
if (req.method === 'OPTIONS') {
res.end();
} else {
next();
}
});
};
export default Middlewares;
./src/index.js
import express from 'express';
import http from 'http';
import Middlewares from './middlewares';
import Controllers from './controllers';
const app = express();
/*
Heroku utiliza la variable de entorno process.env.port para asignar el puerto donde se va ejecutar el servidor,
por eso la hemos definido en esta plantilla
*/
const port = process.env.PORT || 3005;
Middlewares(app);
Controllers(app);
const server = http.createServer(app);
server.listen(port, () => console.log(`Server listening to http://localhost:${port}`));
Para arrancar nuestra aplicación en el puerto 3000:
npm start
Si queremos parar node:
ps auxxx | grep node #Este comando nos permite ver los servicios de node que se están ejecutando
kill -9 1480 8573 #Paramos los servicios de node activos