diff --git a/package.json b/package.json
index 5300400..9ee8d68 100644
--- a/package.json
+++ b/package.json
@@ -12,13 +12,14 @@
   "author": "BigchainDB",
   "main": "./dist/node/index.js",
   "browser": "./dist/browser/bigchaindb-driver.cjs2.min.js",
+  "sideEffects": false,
   "scripts": {
     "lint": "eslint ./{src,test,examples}/**/*.js",
     "build": "npm run clean && npm run build:cjs && npm run build:dist",
     "build:bundle": "webpack",
     "build:cjs": "cross-env BABEL_ENV=cjs babel ./src -d dist/node",
-    "build:dist": "cross-env NODE_ENV=production webpack -p",
-    "dev": "webpack -p -w",
+    "build:dist": "cross-env NODE_ENV=production webpack -w",
+    "dev": "webpack -w",
     "clean": "rimraf dist/bundle dist/node",
     "test": "npm run lint && nyc ava test/ && npm run thanks && npm run report-coverage",
     "thanks": "cowsay Hi, thanks for your interest in BigchainDB. We appreciate your contribution!",
@@ -61,7 +62,8 @@
     "rimraf": "^2.6.2",
     "sinon": "^6.1.0",
     "webpack": "^4.16.1",
-    "webpack-cli": "^3.0.8"
+    "webpack-cli": "^3.0.8",
+    "webpack-concat-plugin": "^3.0.0"
   },
   "dependencies": {
     "browser-resolve": "^1.11.3",
@@ -79,7 +81,10 @@
     "json-stable-stringify": "^1.0.1",
     "query-string": "^6.0.0",
     "sprintf-js": "^1.1.1",
-    "tweetnacl": "^1.0.0"
+    "tweetnacl": "^1.0.0",
+    "uglifyjs-webpack-plugin": "^1.2.7",
+    "webpack-merge": "^4.1.3",
+    "webpack-sources": "^1.1.0"
   },
   "keywords": [
     "bigchaindb",
diff --git a/plugins/add-vendors-plugin.js b/plugins/add-vendors-plugin.js
new file mode 100644
index 0000000..be75bcd
--- /dev/null
+++ b/plugins/add-vendors-plugin.js
@@ -0,0 +1,31 @@
+const { ConcatSource } = require('webpack-sources')
+
+module.exports = class AddVendorsPlugin {
+    constructor(base) {
+        this.base = base
+    }
+
+    apply(compiler) {
+        compiler.hooks.emit.tapAsync(
+            `AddVendorsPlugin ${this.base}`,
+            (compilation, callback) => {
+                const main = compilation.assets[`main.${this.base}`]
+                const mainMap = compilation.assets[`main.${this.base}.map`]
+                const vendor = compilation.assets[`vendors.${this.base}`]
+
+                if (main && vendor) {
+                    const compiledAsset = new ConcatSource(main.children[0])
+                    compiledAsset.add(vendor)
+                    compiledAsset.add(main.children[1])
+                    compilation.assets = {}
+                    compilation.assets[this.base] = compiledAsset
+                } else if (main && mainMap) {
+                    compilation.assets = {}
+                    compilation.assets[this.base] = main
+                    compilation.assets[`${this.base}.map`] = mainMap
+                }
+                callback()
+            }
+        )
+    }
+}
diff --git a/webpack.common.js b/webpack.common.js
new file mode 100644
index 0000000..eb2795c
--- /dev/null
+++ b/webpack.common.js
@@ -0,0 +1,29 @@
+/* eslint-disable strict, no-console, object-shorthand */
+
+'use strict'
+
+const { paths } = require('./webpack.parts.js')
+
+module.exports = {
+    entry: paths.entry,
+    mode: 'none',
+    module: {
+        rules: [
+            {
+                test: /\.js$/,
+                exclude: /node_modules/,
+                use: {
+                    loader: 'babel-loader',
+                },
+            }
+        ]
+    },
+    optimization: {
+        minimize: true,
+        noEmitOnErrors: true
+    },
+    resolve: {
+        extensions: ['.js'],
+        modules: ['node_modules'],
+    },
+}
diff --git a/webpack.config.js b/webpack.config.js
index b7d1ad5..384f0ec 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -2,112 +2,29 @@
 
 'use strict'
 
-const path = require('path')
-
-const webpack = require('webpack')
-
 const PRODUCTION = process.env.NODE_ENV === 'production'
 
-const PATHS = {
-    ENTRY: path.resolve(__dirname, './src/index.js'),
-    BUNDLE: path.resolve(__dirname, 'dist/browser'),
-    NODE_MODULES: path.resolve(__dirname, 'node_modules'),
+const common = require('./webpack.common.js')
+
+const { outputs } = require('./webpack.parts.js')
+
+// '[libraryTarget]': [file extension]
+const OUTPUT_MAPPING = {
+    'amd': 'amd',
+    'commonjs': 'cjs',
+    'commonjs2': 'cjs2',
+    'umd': 'umd',
+    'window': 'window',
 }
 
-const OUTPUTS = [
-    {
-        filename: PRODUCTION ? 'bigchaindb-driver.window.min.js' : 'bigchaindb-driver.window.js',
-        library: 'BigchainDB',
-        libraryTarget: 'window',
-        path: PATHS.BUNDLE,
-    },
-    {
-        filename: PRODUCTION ? 'bigchaindb-driver.umd.min.js' : 'bigchaindb-driver.umd.js',
-        library: 'bigchaindb-driver',
-        libraryTarget: 'umd',
-        path: PATHS.BUNDLE,
-    },
-    {
-        filename: PRODUCTION ? 'bigchaindb-driver.cjs.min.js' : 'bigchaindb-driver.cjs.js',
-        library: 'bigchaindb-driver',
-        libraryTarget: 'commonjs',
-        path: PATHS.BUNDLE,
-    },
-    {
-        filename: PRODUCTION ? 'bigchaindb-driver.cjs2.min.js' : 'bigchaindb-driver.cjs2.js',
-        library: 'bigchaindb-driver',
-        libraryTarget: 'commonjs2',
-        path: PATHS.BUNDLE,
-    },
-    {
-        filename: PRODUCTION ? 'bigchaindb-driver.amd.min.js' : 'bigchaindb-driver.amd.js',
-        library: 'bigchaindb-driver',
-        libraryTarget: 'amd',
-        path: PATHS.BUNDLE,
-    }
-]
-
-
-/** PLUGINS **/
-const PLUGINS = [
-    new webpack.NoEmitOnErrorsPlugin(),
-]
-
-const PROD_PLUGINS = [
-    /*
-    new webpack.optimize.UglifyJsPlugin({
-        compress: {
-            warnings: false,
-        },
-        output: {
-            comments: false,
-        },
-        sourceMap: true,
-    }),
-    new webpack.LoaderOptionsPlugin({
-        debug: false,
-        minimize: true,
-    }),
-    */
-]
+const OVERRIDES = {
+    // optimization: {
+    //     minimize: false
+    // }
+}
 
 if (PRODUCTION) {
-    PLUGINS.push(...PROD_PLUGINS)
+    module.exports = outputs(common, 'production', OUTPUT_MAPPING, OVERRIDES)
+} else {
+    module.exports = outputs(common, 'development', OUTPUT_MAPPING, OVERRIDES)
 }
-
-const configBoilerplate = {
-    entry: [PATHS.ENTRY],
-
-    devtool: PRODUCTION ? '#source-map' : '#inline-source-map',
-
-    resolve: {
-        extensions: ['.js'],
-        modules: ['node_modules'], // Don't use absolute path here to allow recursive matching
-    },
-
-    plugins: PLUGINS,
-
-    module: {
-        rules: [
-            {
-                test: /\.js$/,
-                exclude: [PATHS.NODE_MODULES],
-                use: [{
-                    loader: 'babel-loader',
-                    options: {
-                        cacheDirectory: true,
-                    },
-                }],
-            },
-        ],
-    },
-}
-
-/** EXPORTED WEBPACK CONFIG **/
-const config = OUTPUTS.map(output => {
-    const configCopy = Object.assign({}, configBoilerplate)
-    configCopy.output = output
-    return configCopy
-})
-
-module.exports = config
diff --git a/webpack.development.js b/webpack.development.js
new file mode 100644
index 0000000..c383594
--- /dev/null
+++ b/webpack.development.js
@@ -0,0 +1,30 @@
+/* eslint-disable strict, no-console, object-shorthand */
+
+'use strict'
+
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+
+module.exports = {
+    devtool: 'inline-source-map',
+    optimization: {
+        minimizer: [
+            new UglifyJsPlugin({
+                test: /vendor/,
+                sourceMap: false,
+            }),
+            new UglifyJsPlugin({
+                test: /^((?!(vendor)).)*.js$/,
+                sourceMap: true,
+            })
+        ],
+        splitChunks: {
+            cacheGroups: {
+                commons: {
+                    test: /[\\/]node_modules[\\/]/,
+                    name: 'vendors',
+                    chunks: 'all'
+                }
+            }
+        },
+    },
+}
diff --git a/webpack.parts.js b/webpack.parts.js
new file mode 100644
index 0000000..89606f7
--- /dev/null
+++ b/webpack.parts.js
@@ -0,0 +1,55 @@
+/* eslint-disable strict, no-console, object-shorthand */
+
+'use strict'
+
+const path = require('path')
+const merge = require('webpack-merge')
+
+const development = require('./webpack.development.js')
+const production = require('./webpack.production.js')
+
+const AddVendorsPlugin = require('./plugins/add-vendors-plugin')
+
+const paths = {
+    entry: path.resolve(__dirname, './src/index.js'),
+    bundle: path.resolve(__dirname, 'dist/browser'),
+}
+
+const outputs = (base, env, mapping, overrides) => {
+    const collection = []
+    const library = 'bigchaindb-driver'
+    const windowLibrary = 'BigchainDB'
+
+    let environment = development
+    let ext = 'js'
+
+    if (env === 'production') {
+        environment = production
+        ext = `min.${ext}`
+    }
+
+    Object.entries(mapping).forEach(([target, extension]) => {
+        const filename = `[name].${library}.${extension}.${ext}`
+
+        const compiled = {
+            output: {
+                filename: filename,
+                library: target === 'window' ? windowLibrary : library,
+                libraryTarget: target,
+                path: paths.bundle
+            },
+            plugins: [
+                new AddVendorsPlugin(`${library}.${extension}.${ext}`)
+            ]
+        }
+
+        collection.push(merge(base, environment, compiled, overrides))
+    })
+
+    return collection
+}
+
+module.exports = {
+    outputs,
+    paths
+}
diff --git a/webpack.production.js b/webpack.production.js
new file mode 100644
index 0000000..368a93d
--- /dev/null
+++ b/webpack.production.js
@@ -0,0 +1,7 @@
+/* eslint-disable strict, no-console, object-shorthand */
+
+'use strict'
+
+module.exports = {
+    devtool: 'source-map',
+}