Getting Started With Express, VueJS & PostgreSQL
Tags: node, javascript, vue, postgres
Published: 2018-02-11 20:04:49

---
title: Getting Started With Express, VueJS & PostgreSQL
published: true
thumb: https://jes.al/public/wp-content/uploads/pevn.png
author: jesalg
layout: post
canonical_url: https://jes.al/2018/02/getting-started-with-express-vuejs-postgresql/
tags: 
  - nodejs
  - javascript
  - vuejs
  - postgresql
---

![PEVN](https://jes.al/public/wp-content/uploads/pevn.png)

We have all heard of the MEAN (**M**ongoDB **E**xpress **A**ngular **N**odeJS) stack or more lately the MERN (**M**ongoDB **E**xpress **R**eact and **N**odeJS) stack.

There are plenty of starter kits utilizing those stacks although I was looking for something similar but with a couple of changes. I wanted to switch out MongoDB with PostgresSQL because it's a workhorse that can do just about anything and switch out React with VueJS because I find Vue much more approachable and beginner friendly.

I didn't find anything like that out there, so I ended up creating one myself. Lets call it the PEVN (**P**ostgreSQL **E**xpress **V**ueJS **N**odeJS) stack, I know...0 for creativity!

I spent couple of hours getting everything working like how I wanted it to. I documented the process to save the trouble for anyone looking to do the same which you'll find below. 

**TL;DR** - [https://github.com/jesalg/penv-starter](https://github.com/jesalg/penv-starter)

**NodeJS**

Before we can get started, let's make sure we have NodeJS installed. I've found the easiest way to do so is via nvm. Rails developers will find this very similar to rvm. To install, run the following commands which will install nvm and the latest version of NodeJS:

```sh
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash
$ source ~/.bash_profile
$ nvm install node
$ nvm use node
```

**Express**

Easiest way to install Express is using the generator:

```sh
$ npm install express-generator -g
$ express pevn-starter
$ cd pevn-starter && npm install
```

**VueJS**

Now that we have a basic app, let's get to the fun part. We will treat each Express view as it's own VueJS app (MVVM pattern) which will grab the data it needs from the DOM and/or making AJAX requests to the server.

So for this example, given we have `views/index.jade` we will want to place it's associated VueJS app and styles in `client/css/index.css`, `client/js/index.js` and `/client/js/Index.vue` such that when that Jade view is rendered, it will run the Index Vue app.

So we'll have to tell our view in `views/index.jade` to load our packaged asset file:

```jade
extends layout

block content
  #index(data-visitors-json="#{JSON.stringify(visitors)}")
  script(src="#{webpack_asset('index', 'js')}")
  link(rel='stylesheet', href="#{webpack_asset('index', 'css')}")
```

Our `client/js/index.js` will bootstrap our Index Vue app:

```js
import Vue from 'vue'
import Index from './Index.vue'

new Vue({
  el: '#index',
  data: {
    visitors: []
  },
  render (createElement) {
    return createElement(Index)
  },
  beforeMount() {
    this.visitors = JSON.parse(this.$el.dataset.visitorsJson) //Grab this data from the DOM
  }
})
```

Our Vue app lives in `client/js/Index.vue`:

```html
<template>
    <div>
        <h1>Hello World</h1>
        <p>Welcome to PostgreSQL, Express, VueJS, NodeJS starter</p>
        <p>Here are the last 10 visitors:</p>
        <table>
          <thead>
            <th>ID</th>
            <th>IP</th>
            <th>User Agent</th>
          </thead>

          <tr v-for="(visitor, index) in visitors" :key="index">
              <td>{{ visitor.id }}</td>
              <td>{{ visitor.ip }}</td>
              <td>{{ visitor.user_agent }}</td>
          </tr>
        </table>
    </div>
</template>

<script>
export default {
  data() {
    return {
      visitors: []
    }
  },
  methods: {

  },
  created() {
    this.visitors = this.$parent.visitors; //Grab this data from the parent
  }
}
</script>
```

Don't worry about the logic to display the list of visitors just yet. We'll get to that in a minute.

**Webpack**

In order to create a packaged index.js asset file for our view, we will need to install Webpack, VueJS and its associated dependencies:

```sh
$ npm install webpack extract-text-webpack-plugin assets-webpack-plugin babel-core babel-loader babel-preset-es2015 css-loader file-loader style-loader url-loader vue-template-compiler --save-dev
$ npm install vue express-webpack-assets webpack-dev-middleware webpack-hot-middleware
```

Next, let's create webpack.config.js at the root of our project and paste the following in there:

```js
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var SaveHashes = require('assets-webpack-plugin');
var isProd = (process.env.NODE_ENV === 'production');

var config = {
  entry: {
    index: [
      path.join(__dirname, 'client/js/index.js'),
      path.join(__dirname, 'client/css/index.css')
    ],
  },
  output: {
    path: path.join(__dirname, 'public/dist/'),
    publicPath: '/dist/',
    filename: '[name].[hash].js'
  },
  resolve: {
    extensions: ['.js', '.vue'],
    alias: {
      vue: isProd ? 'vue/dist/vue.min.js' : 'vue/dist/vue.js',
    }
  },
  module: {
    rules: [{
        test: /\.vue$/,
        exclude: /node_modules/,
        use: [{
          loader: 'vue-loader'
        }]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [{
          loader: 'babel-loader',
          options: {
            presets: ['es2015']
          }
        }]
      },
      {
        test: /\.svg/,
        use: {
          loader: 'svg-url-loader',
          options: {}
        }
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: {
            loader: 'css-loader',
            options: {
              minimize: true
            }
          }
        })
      },
    ]
  },
  devtool: 'eval-source-map',
  plugins: [
    new SaveHashes({
      path: path.join(__dirname, 'config')
    }),
    new ExtractTextPlugin({
      publicPath: '/dist/',
      filename: '[name].[hash].css',
      allChunks: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    })
  ]
}

if (isProd) {
  config.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

module.exports = config
```

Our Webpack config will make sure the assets in the client folder get compiled into a compressed JS and CSS package with a cache busting hash filename.

Now we will have to let Express know that we are using Webpack and that we want to run it during start-up. So in the app.js add the following:

```js
var webpack = require('webpack')
var webpackDevMiddleware = require('webpack-dev-middleware')
var webpackHotMiddleware = require('webpack-hot-middleware')
var webpackAssets = require('express-webpack-assets')
.
.
.
// webpack setup
if (NODE_ENV === 'production') {
  app.use(express.static(__dirname + '/dist'));
} else {
  const compiler = webpack(config)
  app.use(webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath,
    stats: { colors: true }
  }))
  app.use(webpackHotMiddleware(compiler))
}
app.use(webpackAssets('./config/webpack-assets.json', {
  devMode: NODE_ENV !== 'production'
}));
.
.
.
```

**PostgreSQL**

Lastly let's go ahead and add pg support by installing [sequelize](http://docs.sequelizejs.com/) ORM and associated dependencies:

```sh
$ npm install sequelize pg pg-hstore --save
$ npm install sequelize-cli --save-dev
$ ./node_modules/.bin/sequelize init
```

Running those commands will create some setup code, you will just need to update your `config/config.json` with the right connection info:

```json
{
  "development": {
    "username": "root",
    "password": null,
    "database": "pevn_development",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "pevn_test",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "pevn_production",
    "host": "127.0.0.1",
    "dialect": "postgres"
  }
}
```

Once you have that, we are ready to create our first model and run the migration:

```sh
$ ./node_modules/.bin/sequelize model:generate --name Visitor --attributes ip:string,user_agent:string
$ ./node_modules/.bin/sequelize db:create
$ ./node_modules/.bin/sequelize db:migrate
```

For the purpose of this example, we will just create a Visitors table which will log the user's IP and UserAgent string every time you visit the home page and spit out the last 10 records:

```js
var express = require('express');
var models = require('../models');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  models.Visitor.create({
    user_agent: req.get('User-Agent'),
    ip: req.ip,
  }).then(() => {
    models.Visitor.findAll({limit: 10, order: [['createdAt', 'DESC']]}).then((visitors) => {
      res.render('index', { title: 'PEVN Stack!', visitors: visitors });
    })
  });
});

module.exports = router;
```

**Conclusion**

With that we come full circle and close the loop. If everything worked, you should now be able to run your app on port 4000 with:

```sh
$ npm start
```

One thing you might notice is that the app will require a restart everytime you change the server code which can get pretty annoying. We can switch to using nodemon instead so the app can restart automatically when the code changes:

```sh
$ npm install --save-dev nodemon
```

In our `nodemon.json` we can configure it to restart when it detects changes to our server side logic:

```json
{
  "verbose": true,
  "ignore": ["public/"],
  "events": {
    "restart": "osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'"
  },
  "watch": ["routes/"],
  "env": {
    "NODE_ENV": "development"
  },
  "ext": "js jade"
}
```

Lastly we can update our npm start command to be `nodemon app.js`

There are a few more interesting things we could do which I left out for this quick start. Like for example, we could run our NodeJS server logic through Babel so we can use ES6 syntax on the server as well. I'll look forward to pull requests for those kind of enhancements from the community! :)

_This post was originally published on <a href="https://jes.al/2018/02/getting-started-with-express-vuejs-postgresql/">my blog</a>. If you liked this post, please share it on social media and <a href="https://twitter.com/jesalg">follow me on Twitter</a>!_