diff --git a/.gitignore b/.gitignore
index 7417bbdd8..362df57e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@ Homestead.yaml
 /storage/images
 _ide_helper.php
 /storage/debugbar
-.phpstorm.meta.php
\ No newline at end of file
+.phpstorm.meta.php
+yarn.lock
diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php
index 61ce55fa9..65135eda3 100644
--- a/app/Http/Controllers/SettingController.php
+++ b/app/Http/Controllers/SettingController.php
@@ -17,10 +17,7 @@ class SettingController extends Controller
         $this->setPageTitle('Settings');
 
         // Get application version
-        $version = false;
-        if (function_exists('exec')) {
-            $version = exec('git describe --always --tags ');
-        }
+        $version = trim(file_get_contents(base_path('version')));
 
         return view('settings/index', ['version' => $version]);
     }
diff --git a/app/helpers.php b/app/helpers.php
index ad1c7dd20..b5be0fd11 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -11,29 +11,20 @@ use BookStack\Ownable;
  */
 function versioned_asset($file = '')
 {
-    // Don't require css and JS assets for testing
-    if (config('app.env') === 'testing') return '';
+    static $version = null;
 
-    static $manifest = null;
-    $manifestPath = 'build/manifest.json';
-
-    if (is_null($manifest) && file_exists($manifestPath)) {
-        $manifest = json_decode(file_get_contents(public_path($manifestPath)), true);
-    } else if (!file_exists($manifestPath)) {
-        if (config('app.env') !== 'production') {
-            $path = public_path($manifestPath);
-            $error = "No {$path} file found, Ensure you have built the css/js assets using gulp.";
-        } else {
-            $error = "No {$manifestPath} file found, Ensure you are using the release version of BookStack";
-        }
-        throw new \Exception($error);
+    if (is_null($version)) {
+        $versionFile = base_path('version');
+        $version = trim(file_get_contents($versionFile));
     }
 
-    if (isset($manifest[$file])) {
-        return baseUrl($manifest[$file]);
+    $additional = '';
+    if (config('app.env') === 'development') {
+        $additional = sha1_file(public_path($file));
     }
 
-    throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
+    $path = $file . '?version=' . urlencode($version) . $additional;
+    return baseUrl($path);
 }
 
 /**
@@ -138,14 +129,14 @@ function sortUrl($path, $data, $overrideData = [])
 {
     $queryStringSections = [];
     $queryData = array_merge($data, $overrideData);
-    
+
     // Change sorting direction is already sorted on current attribute
     if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) {
         $queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc';
     } else {
         $queryData['order'] = 'asc';
     }
-    
+
     foreach ($queryData as $name => $value) {
         $trimmedVal = trim($value);
         if ($trimmedVal === '') continue;
@@ -155,4 +146,4 @@ function sortUrl($path, $data, $overrideData = [])
     if (count($queryStringSections) === 0) return $path;
 
     return baseUrl($path . '?' . implode('&', $queryStringSections));
-}
\ No newline at end of file
+}
diff --git a/gulpfile.js b/gulpfile.js
index 7deefc71a..9d789d9b4 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,27 +1,8 @@
 var elixir = require('laravel-elixir');
 
-// Custom extensions
-var gulp = require('gulp');
-var Task = elixir.Task;
-var fs = require('fs');
-
-elixir.extend('queryVersion', function(inputFiles) {
-     new Task('queryVersion', function() {
-         var manifestObject = {};
-         var uidString = Date.now().toString(16).slice(4);
-         for (var i = 0; i < inputFiles.length; i++) {
-             var file = inputFiles[i];
-             manifestObject[file] = file + '?version=' + uidString;
-         }
-         var fileContents = JSON.stringify(manifestObject, null, 1);
-         fs.writeFileSync('public/build/manifest.json', fileContents);
-     }).watch(['./public/css/*.css', './public/js/*.js']);
-});
-
-elixir(function(mix) {
-    mix.sass('styles.scss')
-        .sass('print-styles.scss')
-        .sass('export-styles.scss')
-        .browserify('global.js', 'public/js/common.js')
-        .queryVersion(['css/styles.css', 'css/print-styles.css', 'js/common.js']);
+elixir(mix => {
+    mix.sass('styles.scss');
+    mix.sass('print-styles.scss');
+    mix.sass('export-styles.scss');
+    mix.browserify('global.js', './public/js/common.js');
 });
diff --git a/package.json b/package.json
index fde090beb..30f288d45 100644
--- a/package.json
+++ b/package.json
@@ -1,18 +1,19 @@
 {
   "private": true,
-  "devDependencies": {
-    "gulp": "^3.9.0"
+  "scripts": {
+    "prod": "gulp --production",
+    "dev": "gulp watch"
   },
-  "dependencies": {
+  "devDependencies": {
     "angular": "^1.5.5",
     "angular-animate": "^1.5.5",
     "angular-resource": "^1.5.5",
     "angular-sanitize": "^1.5.5",
-    "angular-ui-sortable": "^0.14.0",
-    "babel-runtime": "^5.8.29",
-    "bootstrap-sass": "^3.0.0",
+    "angular-ui-sortable": "^0.15.0",
     "dropzone": "^4.0.1",
-    "laravel-elixir": "^5.0.0",
+    "gulp": "^3.9.0",
+    "laravel-elixir": "^6.0.0-11",
+    "laravel-elixir-browserify-official": "^0.1.3",
     "marked": "^0.3.5",
     "moment": "^2.12.0",
     "zeroclipboard": "^2.2.0"
diff --git a/phpunit.xml b/phpunit.xml
index a2b26d413..72e06a3fc 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -30,6 +30,7 @@
         <env name="AUTH_METHOD" value="standard"/>
         <env name="DISABLE_EXTERNAL_SERVICES" value="true"/>
         <env name="LDAP_VERSION" value="3"/>
+        <env name="STORAGE_TYPE" value="local"/>
         <env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
         <env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
         <env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
diff --git a/public/build/.gitignore b/public/build/.gitignore
deleted file mode 100644
index d6b7ef32c..000000000
--- a/public/build/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/readme.md b/readme.md
index 3a745beb1..5d3e79a2e 100644
--- a/readme.md
+++ b/readme.md
@@ -2,13 +2,15 @@
 
 [![GitHub release](https://img.shields.io/github/release/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/releases/latest)
 [![license](https://img.shields.io/github/license/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/blob/master/LICENSE)
-[![Build Status](https://travis-ci.org/ssddanbrown/BookStack.svg)](https://travis-ci.org/ssddanbrown/BookStack)
+[![Build Status](https://travis-ci.org/BookStackApp/BookStack.svg)](https://travis-ci.org/BookStackApp/BookStack)
 
 A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/.
 
 * [Installation Instructions](https://www.bookstackapp.com/docs/admin/installation)
 * [Documentation](https://www.bookstackapp.com/docs)
-* [Demo Instance](https://demo.bookstackapp.com) *(Login username: `admin@example.com`. Password: `password`)*
+* [Demo Instance](https://demo.bookstackapp.com)
+  * *Username: `admin@example.com`*
+  * *Password: `password`*
 * [BookStack Blog](https://www.bookstackapp.com/blog)
 
 ## Development & Testing
@@ -29,7 +31,7 @@ php artisan migrate --database=mysql_testing
 php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
 ```
 
-Once done you can run `phpunit` (or `./vendor/bin/phpunit` if `phpunit` is not found) in the application root directory to run all tests.
+Once done you can run `phpunit` in the application root directory to run all tests.
 
 ## License
 
@@ -51,3 +53,5 @@ These are the great projects used to help build BookStack:
 * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html)
 * [Marked](https://github.com/chjj/marked)
 * [Moment.js](http://momentjs.com/)
+
+Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy.
diff --git a/resources/assets/js/components/drop-zone.html b/resources/assets/js/components/drop-zone.html
deleted file mode 100644
index 26e0ee2aa..000000000
--- a/resources/assets/js/components/drop-zone.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<div class="dropzone-container">
-    <div class="dz-message">Drop files or click here to upload</div>
-</div>
\ No newline at end of file
diff --git a/resources/assets/js/components/image-picker.html b/resources/assets/js/components/image-picker.html
deleted file mode 100644
index 1a07b9274..000000000
--- a/resources/assets/js/components/image-picker.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-<div class="image-picker">
-    <div>
-        <img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
-        <img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
-    </div>
-    <button class="button" type="button" ng-click="showImageManager()">Select Image</button>
-    <br>
-
-    <button class="text-button" ng-click="reset()" type="button">Reset</button>
-    <span ng-show="showRemove" class="sep">|</span>
-    <button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
-
-    <input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
-</div>
\ No newline at end of file
diff --git a/resources/assets/js/components/toggle-switch.html b/resources/assets/js/components/toggle-switch.html
deleted file mode 100644
index 455969a84..000000000
--- a/resources/assets/js/components/toggle-switch.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
-    <input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
-    <div class="switch-handle"></div>
-</div>
\ No newline at end of file
diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js
index 99cf6af9d..f4f1f3e39 100644
--- a/resources/assets/js/controllers.js
+++ b/resources/assets/js/controllers.js
@@ -1,6 +1,8 @@
 "use strict";
 
-const moment = require('moment');
+import moment from 'moment';
+import 'moment/locale/en-gb';
+moment.locale('en-gb');
 
 module.exports = function (ngApp, events) {
 
@@ -17,7 +19,7 @@ module.exports = function (ngApp, events) {
             $scope.imageDeleteSuccess = false;
             $scope.uploadedTo = $attrs.uploadedTo;
             $scope.view = 'all';
-            
+
             $scope.searching = false;
             $scope.searchTerm = '';
 
@@ -48,7 +50,7 @@ module.exports = function (ngApp, events) {
                 $scope.hasMore = preSearchHasMore;
             }
             $scope.cancelSearch = cancelSearch;
-            
+
 
             /**
              * Runs on image upload, Adds an image to local list of images
@@ -437,7 +439,7 @@ module.exports = function (ngApp, events) {
 
             const pageId = Number($attrs.pageId);
             $scope.tags = [];
-            
+
             $scope.sortOptions = {
                 handle: '.handle',
                 items: '> tr',
@@ -729,20 +731,3 @@ module.exports = function (ngApp, events) {
         }]);
 
 };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js
index fa6c2c3be..44d1a14e1 100644
--- a/resources/assets/js/directives.js
+++ b/resources/assets/js/directives.js
@@ -2,10 +2,6 @@
 const DropZone = require('dropzone');
 const markdown = require('marked');
 
-const toggleSwitchTemplate = require('./components/toggle-switch.html');
-const imagePickerTemplate = require('./components/image-picker.html');
-const dropZoneTemplate = require('./components/drop-zone.html');
-
 module.exports = function (ngApp, events) {
 
     /**
@@ -16,7 +12,12 @@ module.exports = function (ngApp, events) {
     ngApp.directive('toggleSwitch', function () {
         return {
             restrict: 'A',
-            template: toggleSwitchTemplate,
+            template: `
+            <div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
+                <input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
+                <div class="switch-handle"></div>
+            </div>
+            `,
             scope: true,
             link: function (scope, element, attrs) {
                 scope.name = attrs.name;
@@ -77,7 +78,7 @@ module.exports = function (ngApp, events) {
                 });
 
                 element.find('button[type="submit"]').click(submitEvent);
-                
+
                 function submitEvent(e) {
                     e.preventDefault()
                     if (attrs.subForm) scope.$eval(attrs.subForm);
@@ -94,7 +95,22 @@ module.exports = function (ngApp, events) {
     ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) {
         return {
             restrict: 'E',
-            template: imagePickerTemplate,
+            template: `
+            <div class="image-picker">
+                <div>
+                    <img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
+                    <img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
+                </div>
+                <button class="button" type="button" ng-click="showImageManager()">Select Image</button>
+                <br>
+
+                <button class="text-button" ng-click="reset()" type="button">Reset</button>
+                <span ng-show="showRemove" class="sep">|</span>
+                <button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
+
+                <input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
+            </div>
+            `,
             scope: {
                 name: '@',
                 resizeHeight: '@',
@@ -161,7 +177,11 @@ module.exports = function (ngApp, events) {
     ngApp.directive('dropZone', [function () {
         return {
             restrict: 'E',
-            template: dropZoneTemplate,
+            template: `
+            <div class="dropzone-container">
+                <div class="dz-message">Drop files or click here to upload</div>
+            </div>
+            `,
             scope: {
                 uploadUrl: '@',
                 eventSuccess: '=',
@@ -603,7 +623,7 @@ module.exports = function (ngApp, events) {
                     let val = $input.val();
                     let url = $input.attr('autosuggest');
                     let type = $input.attr('autosuggest-type');
-                    
+
                     // Add name param to request if for a value
                     if (type.toLowerCase() === 'value') {
                         let $nameInput = $input.closest('tr').find('[autosuggest-type="name"]').first();
@@ -904,17 +924,3 @@ module.exports = function (ngApp, events) {
         };
     }]);
 };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/version b/version
new file mode 100644
index 000000000..8287f2896
--- /dev/null
+++ b/version
@@ -0,0 +1 @@
+v0.13-dev