Skip to content

Instantly share code, notes, and snippets.

@khriztianmoreno
Last active May 21, 2019 17:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save khriztianmoreno/51891107b240fbd61c3c3fd725a6bf4a to your computer and use it in GitHub Desktop.
Save khriztianmoreno/51891107b240fbd61c3c3fd725a6bf4a to your computer and use it in GitHub Desktop.
Talk: Estructurando la base de nuestro proyecto

Cada aplicación necesita ajustes de configuración y la mayoría de los lenguajes de programación / ecosistemas tiene algún tipo de soporte y convención por defecto para él.

  • La mayoría de las aplicaciones Java se basan en archivos .properties;
  • .Net tiene sus archivos estándar app.config y web.config;
  • Ruby on Rails carga la configuración desde config/application.rb, Initializers and After-initializers;
  • Node.js no tiene una forma estándar de administrar estos ajustes, pero hay muchas opciones disponibles.

Tabla de Contenido

  1. Overview
  2. Init
  3. ExpressJS
  4. Config Express JS
  5. Api Folder
  6. Routing
  7. Config Environment
  8. Hot Reloading
  9. NPM Scripts
  10. Thank You

Overview

  • Folder-by-type or Folder-by-feature

Folder-by-type

com.example
├── domain
│    ├── User.js
│    └── Pet.js
├── controllers
│    ├── UserController.js
│    └── PetController.js
├── repositories
│    ├── UserRepository.js
│    └── PetRepository.js
├── services
│    ├── UserService.js
│    └── PetService.js
│   // and everything else in the project
└── index.js

Folder-by-feature

com.example
├── pet
│    ├── Pet.js
│    ├── pet.controller.js
│    ├── pet.model.js
│    └── pet.service.js
├── user
│    ├── user.js
│    ├── userController.java
│    ├── user.model.js
│    └── user.service.js
│   // and everything else in the project
└── index.js

Init

  • Create the basis of our project package.json run npm init
  • Settings for editors .editorconfig
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
  • Linter .eslintrc
{
  "env": {
    "node": true,
    "es6": true
  },

  "extends": "airbnb-base",

  "parser": "babel-eslint"
}
  • Modules required for the linter npm i -D eslint eslint-config-airbnb-base babel-eslint eslint-plugin-import

expressJS

  • npm i -S express
  • app.js
/**
 * Main application file
 */

const express = require('express');
const http = require('http');

// Setup server
const app = express();
const server = http.createServer(app);

const config = {
  port: 8080,
  ip: '127.0.0.1',
};

// Start server
function startServer() {
  app.nodeMDE = server.listen(config.port, config.ip, () => {
    console.log(`Express server listening on ${config.port}, in ${app.get('env')} mode`);
  });
}

setImmediate(startServer);

// Expose app
module.exports = app;
  • index.js
// Export the application
module.exports = require('./app');

config-express

  • Install npm i -S compression body-parser method-override errorhandler
  • config/express.js
/**
 * Express configuration
 * @author: Cristian Moreno Zulauaga <khriztianmoreno@gmail.com>
 */

const compression = require('compression');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const errorHandler = require('errorhandler');

module.exports = (app) => {
  const env = app.get('env');

  app.use(compression());
  app.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));
  app.use(bodyParser.json({ limit: '50mb' }));
  app.use(methodOverride());

  if (env === 'development' || env === 'test') {
    app.use(errorHandler()); // Error handler - has to be last
  }
};
  • Update app.js
const express = require('express');
const http = require('http');

// Add this line
const expressConfig = require('./config/express');

const app = express();
const server = http.createServer(app);

// Add this line
expressConfig(app);

api-folder

  • Create api/<your_api_endpoint> example api/user api/car
  • In this folder it is common to have the files for models, services, events, controllers etc
  • index.js
/**
 * User
 * @author: Cristian Moreno Zuluaga <khriztianmoreno@gmail.com>
 */

const { Router } = require('express');
const controller = require('./helloWorld.controller');

const router = new Router();

// All Verbs
router.get('/', controller.index);

/*
router.delete('/:id', auth.hasRole('admin'), controller.destroy);
router.put('/:id/', auth.isAuthenticated(), controller.update);
router.get('/:id', auth.isAuthenticated(), controller.show);
router.post('/', controller.create);
*/

module.exports = router;
  • helloWorld.controller.js
/**
 * @author: Cristian Moreno Zuluaga <khriztianmoreno@gmail.com>
 */

/**
 * Show hello world
 */
function index(req, res) {
  return res.status(200).json({ message: 'hello wolrd!!' });
}

module.exports = { index };

routing

  • routes.js
/**
 * Main application routes
 * @author: Cristian Moreno Zuluaga <khriztianmoreno@gmail.com>
 */

// Import Endpoints
const helloWorld = require('./api/helloWorld');

module.exports = (app) => {
  /* Others conf like CORS */

  // Insert routes below
  app.use('/api/helloworld', helloWorld);
  // app.use('/api/users', user);
  // app.use('/api/cars', car);
};
  • Update app.js
...
const expressConfig = require('./config/express');

// Add this line
const routeConfig = require('./routes');

...
expressConfig(app);

// Add this line
routeConfig(app);
  • Test browser http://localhost:8080/api/helloworld

config-environment

  • config/environment/development.js
/**
 * Development specific configuration
 * @author: Cristian Moreno Zulauaga <khriztianmoreno@gmail.com>
 */

module.exports = {
  // MongoDB connection options
  mongo: {
    uri: 'mongodb://localhost/nodejs-scaffolding-dev',
  },

  // Seed database on startup
  seedDB: false,

};
  • config/environment/production.js
/**
 * Production specific configuration
 * @author: Cristian Moreno Zulauaga <khriztianmoreno@gmail.com>
 */

module.exports = {
  // Server IP
  ip: process.env.OPENSHIFT_NODEJS_IP || process.env.IP || undefined,

  // Server port
  port: process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 3030,

  // MongoDB connection options
  mongo: {
    uri: process.env.MONGODB_URI ||
        process.env.MONGOHQ_URL ||
        process.env.OPENSHIFT_MONGODB_DB_URL +
        process.env.OPENSHIFT_APP_NAME ||
        'mongodb://localhost/nodejs-scaffolding',
  },
};
  • Shared specific configuration config/environment/shared.js Optional
  • Run npm i -S lodash
  • config/environment/index.js
/**
 * Default specific configuration
 * @author: Cristian Moreno Zulauaga <khriztianmoreno@gmail.com>
 */

const path = require('path');
const _ = require('lodash');
const shared = require('./shared');

const env = process.env.NODE_ENV || 'development';

let envFile = require('./development.js');

if (env === 'production') {
  // Register the Babel require hook
  envFile = require('./production.js');
}

// All configurations will extend these options
// ============================================
const all = {
  env: process.env.NODE_ENV,

  // Root path of server
  root: path.normalize(__dirname + '/../../..'),

  // Server port
  port: process.env.PORT || 3030,

  // Server IP
  ip: process.env.IP || '0.0.0.0',

  // Should we populate the DB with sample data?
  seedDB: false,

  // Secret for session, you will want to change this and make it an environment variable
  secrets: {
    session: 'nodejs-scaffolding-secret',
  },

  // MongoDB connection options
  mongo: {
    options: {
      db: {
        safe: true,
      },
      useMongoClient: true,
      poolSize: 2,
    },
  },

  facebook: {
    clientID: process.env.FACEBOOK_ID || 'id',
    clientSecret: process.env.FACEBOOK_SECRET || 'secret',
    callbackURL: `${process.env.DOMAIN || ''}/auth/facebook/callback`,
  },

  twitter: {
    clientID: process.env.TWITTER_ID || 'id',
    clientSecret: process.env.TWITTER_SECRET || 'secret',
    callbackURL: `${process.env.DOMAIN || ''}/auth/twitter/callback`,
  },

  google: {
    clientID: process.env.GOOGLE_ID || 'id',
    clientSecret: process.env.GOOGLE_SECRET || 'secret',
    callbackURL: `${process.env.DOMAIN || ''}/auth/google/callback`,
  },
};

// Export the config object based on the NODE_ENV
// ==============================================
module.exports = _.merge(all, shared, envFile || {});
  • Update app.js
// Add this import
const config = require('./config/environment');

// remove this lines
const config = {
  port: 8080,
  ip: '127.0.0.1',
};

...

hot-reloading

  • Run npm i -D nodemon
  • Verify nodemon index.js

npm-scripts

  • Add to package.json
...
"main": "index.js",
"scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
 },
 
 ...

thank-you

❓❓❓❓❓❓

👏👏👏👏👏👏👏

@sebastianvz
Copy link

Amazing ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment