From 4186925da50e9c3624f2a90d8c0e8732ecf52a65 Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Fri, 20 Jan 2017 15:12:39 +0100
Subject: [PATCH] Add Webpack bundler

Added a NPM packages.json list which manages
 JavaScript packages. Most important packages added
 is the Webpack package which acts as an assets
 bundler.
It is added in its most basic working form. This
 includes additional settings in `settings.py`
 and the template tags in `base.html`.
Please read the updated Readme.md to easily get
 started using Webpack for your new assets.
---
 .gitignore                                    |  8 ++-
 README.md                                     | 23 +++++++-
 SciPost_v1/settings.py                        | 16 ++++++
 requirements.txt                              |  1 +
 scipost/static/scipost/assets/css/style.css   |  0
 scipost/templates/scipost/base.html           |  6 ++
 .../bundles/css/main-74c70b907a6530bfb5dd.css |  0
 .../bundles/js/main-74c70b907a6530bfb5dd.js   | 57 +++++++++++++++++++
 webpack.config.js                             | 40 +++++++++++++
 9 files changed, 149 insertions(+), 2 deletions(-)
 create mode 100644 scipost/static/scipost/assets/css/style.css
 create mode 100644 static/bundles/css/main-74c70b907a6530bfb5dd.css
 create mode 100644 static/bundles/js/main-74c70b907a6530bfb5dd.js
 create mode 100644 webpack.config.js

diff --git a/.gitignore b/.gitignore
index 3367cdfe5..08d3037e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,12 +2,18 @@
 __pycache__
 
 *.json
+*.log
 
 *~
 
+# Package managers
 venv*
+node_modules/
+*webpack-stats.json
+
 .python-version
 
+
 media/temp
 
 SCIPOST_JOURNALS
@@ -16,4 +22,4 @@ UPLOADS
 docs/_build
 local_files
 
-whoosh_index
\ No newline at end of file
+whoosh_index
diff --git a/README.md b/README.md
index 68c8f64bb..9bb43e073 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ The complete scientific publication portal
 
 ## Dependencies
 SciPost is written in Python 3.5 using Django and requires PostgreSQL 9.3 or
-higher. Python dependencies are listed in `requirements.txt`.
+higher. Python dependencies are listed in `requirements.txt`. Frontend dependencies are managed by [NPM](https://www.npmjs.com/) in package.json.
 
 ## Getting started
 
@@ -28,6 +28,27 @@ Now install dependencies:
 (scipostenv) $ pip install -r requirements.txt
 ```
 
+### Frontend dependencies
+[NPM](https://www.npmjs.com/) will take care of frontend dependencies. To install all packages now run:
+
+```shell
+(scipostenv) $ npm install
+```
+
+### Module bundler
+[Webpack](http://webpack.github.io/docs/what-is-webpack.html) takes care of assets in the `scipost/static/scipost/assets` folder. To (re)compile all assets, simply run:
+
+```shell
+(scipostenv) $ npm run webpack
+```
+
+While editing assets, it is helpfull to put webpack in _watch_ mode. This will recompile your assets every time you edit them. To do so, instead of the above command, run:
+
+```shell
+(scipostenv) $ npm run webpack-live
+```
+
+
 ### Host-specific settings
 In this project, host-specific settings are defined in the `scipost-host-settings.json` file in the directory *above* the project root. The structure is as follows:
 
diff --git a/SciPost_v1/settings.py b/SciPost_v1/settings.py
index 66601f806..e29c39cd4 100644
--- a/SciPost_v1/settings.py
+++ b/SciPost_v1/settings.py
@@ -80,6 +80,7 @@ INSTALLED_APPS = (
     'scipost',
     'submissions',
     'theses',
+    'webpack_loader'
 )
 
 HAYSTACK_CONNECTIONS = {
@@ -175,6 +176,21 @@ USE_TZ = True
 
 STATIC_URL = host_settings["STATIC_URL"]
 STATIC_ROOT = host_settings["STATIC_ROOT"]
+STATICFILES_DIRS = (
+    os.path.join(BASE_DIR, 'static'),
+)
+
+# Webpack handling the static bundles
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'CACHE': not DEBUG,
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
+        'POLL_INTERVAL': 0.1,
+        'TIMEOUT': None,
+        'IGNORE': ['.+\.hot-update.js', '.+\.map']
+    }
+}
 
 # Email
 EMAIL_BACKEND = host_settings["EMAIL_BACKEND"]
diff --git a/requirements.txt b/requirements.txt
index 896a00456..a68b81195 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,6 +10,7 @@ django-mathjax==0.0.5
 django-mptt==0.8.6
 django-simple-captcha==0.5.3
 django-sphinxdoc==1.5.1
+django-webpack-loader==0.4.1
 djangorestframework==3.5.3
 docutils==0.12
 feedparser==5.2.1
diff --git a/scipost/static/scipost/assets/css/style.css b/scipost/static/scipost/assets/css/style.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/scipost/templates/scipost/base.html b/scipost/templates/scipost/base.html
index 23a60758b..ace0fe23b 100644
--- a/scipost/templates/scipost/base.html
+++ b/scipost/templates/scipost/base.html
@@ -1,9 +1,13 @@
+{% load render_bundle from webpack_loader %}
+
 <!DOCTYPE html>
 <html lang="en">
   <head>
     {% load staticfiles %}
     <link rel="stylesheet" type="text/css" href="{% static 'scipost/SciPost.css' %}" />
 
+    {% render_bundle 'main' 'css' %}
+
     <link rel="shortcut icon" href="{% static 'scipost/images/scipost_favicon.png' %}"/>
 
     <script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
@@ -34,6 +38,8 @@
     {% endblock content %}
 
     {% include 'scipost/footer.html' %}
+
+    {% render_bundle 'main' 'js' %}
   </body>
 
 </html>
diff --git a/static/bundles/css/main-74c70b907a6530bfb5dd.css b/static/bundles/css/main-74c70b907a6530bfb5dd.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/static/bundles/js/main-74c70b907a6530bfb5dd.js b/static/bundles/js/main-74c70b907a6530bfb5dd.js
new file mode 100644
index 000000000..e99d5573e
--- /dev/null
+++ b/static/bundles/js/main-74c70b907a6530bfb5dd.js
@@ -0,0 +1,57 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "/static/bundles/";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+	module.exports = __webpack_require__(1);
+
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+	// removed by extract-text-webpack-plugin
+
+/***/ }
+/******/ ]);
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 000000000..57789e0de
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,40 @@
+var BundleTracker = require('webpack-bundle-tracker');
+var CleanWebpackPlugin = require('clean-webpack-plugin');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+var glob = require("glob");
+var path_bundles = __dirname + '/static/bundles/';
+
+module.exports = {
+    context: __dirname,
+    entry: {
+        main: glob.sync("./scipost/static/scipost/assets/css/*.css")
+    },
+    output: {
+        path: path_bundles,
+        publicPath: '/static/bundles/',
+        filename: "js/[name]-[hash].js",
+    },
+    module: {
+        loaders: [
+            {
+                test: /\.css$/,
+                loader: ExtractTextPlugin.extract("style-loader", "css-loader")
+            },
+            // Optionally extract less files (yeay!)
+            {
+                test: /\.less$/,
+                loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
+            }
+        ]
+    },
+    plugins: [
+        new BundleTracker({filename: './webpack-stats.json'}),
+        new ExtractTextPlugin('css/[name]-[hash].css'),
+        new CleanWebpackPlugin(['css', 'js'], {
+            root: path_bundles,
+            verbose: true,
+            dry: false,
+            exclude: []
+        })
+    ]
+}
-- 
GitLab