Iworb's blog

Full Stack (Node + Express + MongoDb + Vue + Nuxt) application. Part 2: Helpers, Configs and Session

2018-02-13

Helpers

Helpers will land in server/helpers directory, so add an alias in package.json for it:

1
"@helpers": "./server/helpers"

Environment

Let’s add env.js helper which checks our environment:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
isDev () {
return !process.env.NODE_ENV || process.env.NODE_ENV === 'development'
},

isProduction () {
return process.env.NODE_ENV === 'production'
},

isTest () {
return process.env.NODE_ENV === 'test'
}
}

To export this module in easy way lets make an index for helpers:

1
2
3
4
5
const env = require('./env')

module.exports = {
env
}

Token generator

Another one nifty helper intended for token generation for secrets.

1
yarn add uuid-token-generator

tokgen.js:

1
2
3
4
5
6
let TokenGenerator = require('uuid-token-generator')
let tokgen = new TokenGenerator(256, TokenGenerator.BASE62)

module.exports = function () {
return tokgen.generate()
}

And extend index file for this new helper:

1
2
3
4
5
6
7
const env = require('./env')
const tokgen = require('./tokgen')

module.exports = {
env,
tokgen
}

Configs

Config should be flexible, so we have to merge it into separate files:

  • base.js - basic configuration which should be a skeleton of config;
  • config.template.js - template for config.js file, which could be used to set your own secrets. It is excluded from git, so we need a template to create new one if there’s new instance;
  • dev.js, prod.js and test.js - confings based on environment;
  • index.js - summary config.
    Let’s init them with following code:
    1
    module.exports = {}

As an example let’s make a session config.
base.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
session: {
resave: true,
saveUninitialized: false,
cookie: {
// reset session after 1 week
maxAge: 7 * 24 * (60 * 60 * 1000),
// we will use cookies just for HTTP, not js
// JS will send this cookies only from current domain
httpOnly: true,
// should be 'true' if you're using https
secure: false
}
}
}

Now we have almost complete session config but secret. Each user have to define his own session, so lets make our template which will generate secret for a session if there’s no config.js file.
config.template.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
session: {
secret: '{{sessionSecret}}',
resave: true,
saveUninitialized: false,
cookie: {
// reset session after 1 week
maxAge: 7 * 24 * (60 * 60 * 1000),
// we will use cookies just for HTTP, not js
// JS will send this cookies only from current domain
httpOnly: true,
// should be 'true' if you're using https
secure: false
}
}
}

and another stuff in double braces will be replaced with provided data.
To improve console logging and js functionality I gonna include this modules into project:

1
yarn add chalk lodash

There’s how index.js file looks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const path = require('path')
const fs = require('fs')
const _ = require('lodash')
const chalk = require('chalk')
const {tokgen, env} = require('@helpers')

let config = {}

try {
// [1]
if (!fs.existsSync(path.join(__dirname, 'config.js'))) {
console.warn(chalk.yellow.bold('`config.js` for server settings was not found! Generating new `config.js` file'))
const template = fs.readFileSync(path.join(__dirname, 'config.template.js'))
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g
const compiled = _.template(template)
const replacements = {
sessionSecret: tokgen()
}
fs.writeFileSync(path.join(__dirname, 'config.js'), compiled(replacements))
console.warn(chalk.green.bold('New `config.js` for server settings file was generated. You could update your settings here: "server/config/config.js"'))
}
config = require('./config')
} catch (error) {
console.warn(chalk.red.bold('\r\n=============================================='))
console.warn(chalk.red.bold(' Unable to load external `config.js` file!'))
console.warn(chalk.red.bold(' ', error))
console.warn(chalk.red.bold('==============================================\r\n'))
process.exit(1)
}

// [2]
let envConfig = {}

if (env.isDev()) {
envConfig = require('./dev')
} else if (env.isTest()) {
envConfig = require('./test')
} else if (env.isProduction()) {
envConfig = require('./prod')
}

// [3]
const base = require('./base')

module.exports = _.defaultsDeep(envConfig, config, base)

First of all we have to check is there config.js [1] file exists. If no we’re reading our config.template.js and replace template variables with generated values and make config.js.
Next [2] we’re reading environment-based config and [3] base one, than return merged config.
Last thing is module alias for config folder:

1
"@config": "./server/config"

Session

1
yarn add express-session cookie-parser body-parser

Add using of session in our application lets extend server/index.js file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require('module-alias/register')
const config = require('@config')
const express = require('express')
const session = require('express-session')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const app = express()

const configSession = config.session
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.use(cookieParser())
app.use(session(configSession))

const {Nuxt, Builder} = require('nuxt')
...

This part wraps up 02-helpers-config-session git branch.

Tags: express