π A boilerplate for Node.js, Express, Mongoose, Heroku, Atlas, Nodemon, PM2, and Babel.
π Live Demo
This seed repository provides the following features:
- ---------- Essentials ----------
- Application routing with Express.
- Industry-standard GraphQL implementation with Apollo.
- Object document mapping with Mongoose.
- Object relational mapping with Sequelize.
- In-memory data structure store with Redis.
- Authenticate requests with Passport.
- Real-time bidirectional communication with Socket.IO.
- Jobs and messages with Bull.
- Online payments with Stripe.
- Full-text search with Elasticsearch.
- Machine learning models with TensorFlow.
- ---------- Tools ----------
- Next generation JavaScript with Babel.
- OpenAPI specification with Swagger.
- JavaScript static code analyzer with ESLint.
- Code formatter with Prettier.
- JavaScript static type checker with Flow.
- Unit testing with Jest.
- End-to-End testing with Supertest.
- Automatically restart application with Nodemon.
- Keeping application alive with PM2.
- ---------- Environments ----------
- JavaScript runtime with Node.js.
- Fast and deterministic builds with Yarn.
- Version control with Git.
- Code repository with GitHub.
- Cloud application hosting with Heroku.
- Cloud NoSQL database hosting with Atlas.
- Cloud SQL database hosting with ElephantSQL.
- Cloud storageβ hosting with Cloudinary.
- Cloud memory cache hosting with RedisLabs.
- Search engine hosting with Bonsai.
- Large-scale data processing with Spark.
- Centralized logging and analysis service with LogDNA.
- Error tracking service with Sentry.
- Performance and security with Cloudflare.
- Software container with Docker.
- Continuous integration with CircleCI.
- Test coverage integration with Codecov.
Thinking in ...
- REST Stack
- GraphQL Stack
Follow steps to execute this boilerplate.
- Clone this boilerplate
$ git clone --depth 1 https://github.com/Shyam-Chen/Express-Starter.git <PROJECT_NAME>
$ cd <PROJECT_NAME>
- Install dependencies
$ yarn install
- Start a local server
$ yarn serve
- Compile code
$ yarn build
- Check code quality
$ yarn lint
- Runs unit tests
$ yarn unit
- Runs end-to-end tests
$ yarn e2e
Dockerize an application.
- Build and run the container in the background
$ docker-compose up -d app
- Run a command in a running container
$ docker-compose exec app <COMMAND>
- Remove the old container before creating the new one
$ docker-compose rm -fs
- Restart up the container in the background
$ docker-compose up -d --build app
- Push images to Docker Cloud
# .gitignore
.DS_Store
node_modules
dist
coverage
+ dev.Dockerfile
+ stage.Dockerfile
+ prod.Dockerfile
*.log
$ docker login
$ docker build -f ./tools/<dev|stage|prod>.Dockerfile -t <IMAGE_NAME>:<IMAGE_TAG> .
# checkout
$ docker images
$ docker tag <IMAGE_NAME>:<IMAGE_TAG> <DOCKER_ID_USER>/<IMAGE_NAME>:<IMAGE_TAG>
$ docker push <DOCKER_ID_USER>/<IMAGE_NAME>:<IMAGE_TAG>
# remove
$ docker rmi <REPOSITORY>:<TAG>
# or
$ docker rmi <IMAGE_ID>
- Pull images from Docker Cloud
# circle.yml
echo "${HEROKU_TOKEN}" | docker login -u "${HEROKU_USERNAME}" --password-stdin registry.heroku.com
- docker build -f ./tools/$DEPLOYMENT_ENVIRONMENT.Dockerfile -t $APP_NAME .
+ docker pull <DOCKER_ID_USER>/<IMAGE_NAME>:<IMAGE_TAG>
- docker tag $APP_NAME registry.heroku.com/$APP_NAME/web
+ docker tag <IMAGE_NAME>:<IMAGE_TAG> registry.heroku.com/<HEROKU_PROJECT>/web
docker push registry.heroku.com/<HEROKU_PROJECT>/web
Set your local environment variables.
// src/env.js
export const NODE_ENV = process.env.NODE_ENV || 'development';
export const HOST = process.env.HOST || '0.0.0.0';
export const PORT = process.env.PORT || 3000;
export const SECRET = process.env.SECRET || 'PUT_YOUR_SECRET_HERE';
export const MONGODB_URI = process.env.MONGODB_URI || '<PUT_YOUR_MONGODB_URI_HERE>';
export const POSTGRES_URL = process.env.POSTGRES_URL || 'PUT_YOUR_POSTGRES_URL_HERE';
export const REDIS_PORT = process.env.REDIS_PORT || '<PUT_YOUR_REDIS_PORT_HERE>';
export const REDIS_HOST = process.env.REDIS_HOST || '<PUT_YOUR_REDIS_HOST_HERE>';
// ...
Set your deployment environment variables.
# tools/<dev|stage|prod>.Dockerfile
# envs --
ENV SECRET <PUT_YOUR_SECRET_HERE>
ENV MONGODB_URI <PUT_YOUR_MONGODB_URI>
ENV POSTGRES_URL <PUT_YOUR_POSTGRES_URL_HERE>
ENV REDIS_PORT <PUT_YOUR_REDIS_PORT_HERE>
ENV REDIS_HOST <PUT_YOUR_REDIS_HOST_HERE>
# ...
# -- envs
- Example of REST
import { Router } from 'express';
import { List } from './document';
const router = Router();
router.get('/', async (req, res) => {
const data = await List.find({}).exec();
res.json(data);
});
export default router;
- Example of GraphQL
import gql from 'graphql-tag';
import { List } from './document';
export const listTypeDefs = gql`
type List {
_id: ID!
text: String!
}
type Query {
list: [List]
}
`;
export const listResolvers = {
Query: {
async list(root, { _id, text }) {
const data = await List.find({}).exec();
return data;
},
},
};
- Example of Document
import mongoose, { Schema } from 'mongoose';
const listSchema = new Schema({
text: {
type: String,
required: true,
},
});
export const List = mongoose.model('List', listSchema);
- Example of Relational
import Sequelize from 'sequelize';
import sequelize from '~/core/sequelize';
export const RelationalList = sequelize.define('List', {
text: Sequelize.STRING,
});
- Example of Lodash
import { of } from 'rxjs';
import { lowerFirst, pad } from 'lodash';
of(lowerFirst('Hello'), pad('World', 5)).subscribe(value => console.log(value));
// hello
// World
- Example of ReactiveX
import { timer, of } from 'rxjs';
import { mapTo, combineAll } from 'rxjs/operators';
timer(2000)
.pipe(
mapTo(of('Hello', 'World')),
combineAll(),
)
.subscribe(value => console.log(value));
// ["Hello"]
// ["World"]
- Example of Socket
connSocket.emit('A', { foo: 'bar' });
connSocket.on('B', data => console.log(data)); // { foo: 'baz' }
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script>
const socket = io('http://localhost:3000/');
socket.on('connect', () => console.log('Socket: Accept a connection.'));
socket.on('A', data => {
console.log(data); // { foo: 'bar' }
socket.emit('B', { foo: 'baz' });
});
</script>
- Example of Redis
import redis from '~/core/redis';
redis.hmset('thing', {
foo: 'js',
bar: 'html',
baz: 'css',
});
redis.hgetall('thing', (err, object) => {
console.log(object);
});
The structure follows the LIFT Guidelines.
.
βββ src
β βββ core -> core feature module
β βββ <FEATURE> -> feature modules
β β βββ __tests__
β β β βββ <FEATURE>.e2e-spec.js
β β β βββ <FEATURE>.spec.js
β β βββ _<THING> -> feature of private things
β β β βββ ...
β β βββ <FEATURE>.js
β βββ <GROUP> -> module group
β β βββ <FEATURE> -> feature modules
β β βββ __tests__
β β β βββ <FEATURE>.e2e-spec.js
β β β βββ <FEATURE>.spec.js
β β βββ _<THING> -> feature of private things
β β β βββ ...
β β βββ <FEATURE>.js
β βββ shared -> shared feature module
β βββ app.js
β βββ env.js
β βββ server.js
βββ tools
β βββ ...
βββ .editorconfig
βββ .eslintrc
βββ .gitignore
βββ .prettierrc
βββ babel.config
βββ circle.yml
βββ docker-compose.yml
βββ Dockerfile
βββ jest.config.js
βββ LICENSE
βββ package.json
βββ processes.js
βββ README.md
βββ yarn.lock
The microservice architecture enables the rapid, frequent and reliable delivery of large, complex applications. It also enables an organization to evolve its technology stack.
See Server-side Micro-Fullstack for instructions on how to create microservices from source.