瀏覽代碼

HUE-8687 [frontend] Add webpack for js modularity and bundling

Johan Ahlen 6 年之前
父節點
當前提交
4b534cb
共有 100 個文件被更改,包括 2614 次插入0 次删除
  1. 86 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/.gitignore
  2. 39 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/.travis.yml
  3. 71 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/CHANGELOG.md
  4. 22 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/LICENSE
  5. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/LICENSE.txt
  6. 2 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/MANIFEST.in
  7. 37 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/Makefile
  8. 386 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/README.md
  9. 23 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/README.md
  10. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/README.md
  11. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/__init__.py
  12. 115 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/settings.py
  13. 14 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/templates/home.html
  14. 25 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/urls.py
  15. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/views.py
  16. 16 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/wsgi.py
  17. 7 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/assets/js/app.jsx
  18. 4 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/assets/js/index.jsx
  19. 二進制
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/db.sqlite3
  20. 10 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/manage.py
  21. 19 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/package.json
  22. 2 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/requirements.txt
  23. 37 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/webpack.config.js
  24. 25 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/README.md
  25. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/__init__.py
  26. 115 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/settings.py
  27. 13 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/templates/home.html
  28. 25 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/urls.py
  29. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/views.py
  30. 16 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/wsgi.py
  31. 7 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/assets/js/app.jsx
  32. 4 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/assets/js/index.jsx
  33. 二進制
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/db.sqlite3
  34. 10 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/manage.py
  35. 19 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/package.json
  36. 2 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/requirements.txt
  37. 17 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/server.js
  38. 36 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/webpack.config.js
  39. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/README.md
  40. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/__init__.py
  41. 115 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/settings.py
  42. 13 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/templates/home.html
  43. 25 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/urls.py
  44. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/views.py
  45. 16 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/wsgi.py
  46. 7 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/assets/js/app.jsx
  47. 4 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/assets/js/index.jsx
  48. 二進制
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/db.sqlite3
  49. 10 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/manage.py
  50. 18 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/package.json
  51. 2 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/requirements.txt
  52. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/webpack-stats.json
  53. 29 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/webpack.config.js
  54. 5 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/requirements-dev.txt
  55. 2 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/setup.cfg
  56. 43 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/setup.py
  57. 9 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/.coveragerc
  58. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/.coveralls.yml
  59. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/README.md
  60. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/__init__.py
  61. 129 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/settings.py
  62. 18 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/templates/home.html
  63. 15 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/templates/home.jinja
  64. 11 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/templates/only_files.html
  65. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/tests/__init__.py
  66. 248 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/tests/test_webpack.py
  67. 25 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/urls.py
  68. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/views.py
  69. 16 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/wsgi.py
  70. 7 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/app.jsx
  71. 5 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/bad_index.jsx
  72. 5 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/index.jsx
  73. 3 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/style.css
  74. 二進制
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/db.sqlite3
  75. 10 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/manage.py
  76. 22 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/package.json
  77. 30 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/tox.ini
  78. 14 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.app2.js
  79. 32 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.error.js
  80. 32 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.gzipTest.js
  81. 5 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.publicPath.js
  82. 32 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.simple.js
  83. 40 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.split.js
  84. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack_loader
  85. 4 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/__init__.py
  86. 29 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/apps.py
  87. 33 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/config.py
  88. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/contrib/__init__.py
  89. 9 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/contrib/jinja2ext.py
  90. 9 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/errors.py
  91. 36 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/exceptions.py
  92. 102 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/loader.py
  93. 1 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/signals.py
  94. 0 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/templatetags/__init__.py
  95. 36 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/templatetags/webpack_loader.py
  96. 72 0
      desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/utils.py
  97. 8 0
      desktop/core/src/desktop/settings.py
  98. 32 0
      desktop/core/src/desktop/static/desktop/js/hue-bundle-88f5760ed32fdd31e59e.js
  99. 0 0
      desktop/core/src/desktop/static/desktop/js/hue-bundle-88f5760ed32fdd31e59e.js.map
  100. 32 0
      desktop/core/src/desktop/static/desktop/js/hue-bundle-d5f45f241629b44678eb.js

+ 86 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/.gitignore

@@ -0,0 +1,86 @@
+venv/
+
+# auto generated
+README.rst
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Editors and IDEs
+.ropeproject/
+
+.python-version
+
+examples/**/ve/
+examples/**/venv/
+examples/**/node_modules/
+examples/**/assets/bundles/
+examples/**/assets/webpack-stats.json
+
+tests/ve/
+tests/ve3/
+tests/venv/
+tests/venv3/
+tests/node_modules/
+tests/assets/bundles/
+tests/webpack-stats.json
+tests/webpack-stats-app2.json
+
+# PyCharm IDE
+.idea
+.vscode

+ 39 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/.travis.yml

@@ -0,0 +1,39 @@
+language: python
+sudo: false
+# command to install dependencies
+before_install: "cd tests"
+install: travis_retry pip install 'tox<3.0' coveralls
+# command to run tests
+script:
+  - npm install
+  - tox -e "${TOXENV}"
+after_success:
+  - coverage xml
+  - cp coverage.xml ../
+  - coveralls
+env:
+  matrix:
+    - TOXENV=py27-django16
+    - TOXENV=py27-django17
+    - TOXENV=py27-django18
+    - TOXENV=py27-django19
+    - TOXENV=py27-django110
+    - TOXENV=py27-django111
+    - TOXENV=py34-django17
+    - TOXENV=py34-django18
+    - TOXENV=py34-django19
+    - TOXENV=py34-django110
+    - TOXENV=py34-django111
+
+# Python 3.5 has to go here until Travis adds it to the default build images.
+# https://github.com/travis-ci/travis-ci/issues/4794#issuecomment-143758799
+matrix:
+  include:
+    - python: 3.5
+      env: TOXENV=py35-django18
+    - python: 3.5
+      env: TOXENV=py35-django19
+    - python: 3.5
+      env: TOXENV=py35-django110
+    - python: 3.5
+      env: TOXENV=py35-django111

+ 71 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/CHANGELOG.md

@@ -0,0 +1,71 @@
+# django-webpack-loader changelog
+
+For more general information, view the [readme](README.md).
+
+Releases are added to the
+[github release page](https://github.com/ezhome/django-webpack-loader/releases).
+
+## [0.6.0] -- 2018-02-22
+
+- Added support for 'Access-Control-Allow-Origin' header
+- Read stats file with unicode support
+- Cleaned up exceptions
+- Updated and corrected docs
+
+## [0.5.0] -- 2017-05-20
+
+- Added ability to access the webpack asset path information from application
+- Fixed potential crash when formatting errors
+- Added django 1.11 to test suite
+
+## [0.4.0] -- 2016-10-26
+
+- Added ability to compile webpack to gzip bundles
+- Added poll interval option (time to wait between polling the stats file)
+- Added timeout (maximum wait-time before throwing an Exception)
+- Added django 1.10 to test suite
+
+## [0.3.3] -- 2016-07-24
+
+- Added Makefile for easier development
+- Added ability timeout when waiting for webpack to compile a bundle
+
+## [0.3.2] -- 2016-07-24
+
+- Added ability to add attrs to render_bundle tag
+
+## [0.3.1] -- 2016-07-24
+
+- documented webpack_static tag
+
+## [0.3.0] -- 2015-02-21
+
+- breaking 💥: new CACHE setting which when set to true makes the loader cache the contents of the stats files in memory. If set to True, server will restart every time the stats file contents change or it'll keep serving old, cached URLs. CACHE defaults to not DEBUG by default.
+- Fixed Exception
+- Added django 1.9 to test suite
+
+## [0.2.4] -- 2015-12-23
+
+- Fix unicode errors
+
+## [0.2.3] -- 2015-12-03
+
+- mark safe template tags
+
+## [0.2.2] -- 2015-09-21
+
+- fix webpack exceptions
+
+## [0.2.1] -- 2015-12-03
+
+- add custom exception for WebpackLoaderBadStatsError
+
+## [0.2.0] -- 2015-09-10
+
+- breaking 💥: revised django settings configuration syntax
+- webpack loader can now consume the output of multiple stats files in the same project
+- add ``get_files`` template tag
+
+## [0.1.2] -- 2015-05-25
+
+- first documented release

+ 22 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Owais Lone
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/LICENSE.txt

@@ -0,0 +1 @@
+LICENSE

+ 2 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/MANIFEST.in

@@ -0,0 +1,2 @@
+include LICENSE
+include README.md

+ 37 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/Makefile

@@ -0,0 +1,37 @@
+.PHONY: clean build deploy install publish
+
+# Project settings
+PROJECT = webpack-loader
+
+# Virtual environment settings
+ENV ?= venv
+REPOSITORY ?= pypi
+
+requirements = -r requirements-dev.txt
+
+all: install build
+
+clean:
+	@echo "Cleaning..."
+	@find webpack_loader/ -name '*.pyc' -delete
+	@rm -rf ./build ./*egg* ./.coverage ./dist
+
+build: clean
+	@echo "Building..."
+	@python setup.py sdist bdist_wheel --universal
+
+install:
+	@echo "Installing build dependencies"
+	@[ ! -d $(ENV)/ ] && python3 -m venv $(ENV)/ || :
+	@$(ENV)/bin/pip install $(requirements)
+
+generate-rst:
+	@pandoc --from=markdown --to=rst --output=README.rst README.md
+
+publish: generate-rst build
+	@echo "Publishing to pypi..."
+	@$(ENV)/bin/twine upload -r $(REPOSITORY) dist/*
+
+register:
+	@echo "Registering package on pypi..."
+	@$(ENV)/bin/twine register -r $(REPOSITORY)

+ 386 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/README.md

@@ -0,0 +1,386 @@
+# django-webpack-loader
+
+[![Join the chat at https://gitter.im/owais/django-webpack-loader](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/owais/django-webpack-loader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Build Status](https://travis-ci.org/owais/django-webpack-loader.svg?branch=master)](https://travis-ci.org/owais/django-webpack-loader)
+[![Coverage Status](https://coveralls.io/repos/owais/django-webpack-loader/badge.svg?branch=master&service=github)](https://coveralls.io/github/owais/django-webpack-loader?branch=master)
+
+<br>
+
+Read http://owaislone.org/blog/webpack-plus-reactjs-and-django/ for a detailed step by step guide on setting up webpack with django using this library.
+
+
+Use webpack to generate your static bundles without django's staticfiles or opaque wrappers.
+
+
+Django webpack loader consumes the output generated by [webpack-bundle-tracker](https://github.com/owais/webpack-bundle-tracker) and lets you use the generated bundles in django.
+
+A [changelog](CHANGELOG.md) is also available.
+
+## Maintainers
+In order to overcome the lack of support for Markdown on PyPi, building this package can use [pandoc](http://pandoc.org/installing.html) along with [pypandoc](https://pypi.python.org/pypi/pypandoc) to convert the README.md into a Restructured Text format compatible with PyPI.  This requires installing `pandoc` for your operating system (installation instructions on the pandoc site), and `pypandoc` which will be installed if you:
+
+    pip install -r requirements-dev.txt
+
+before uploading to PyPI.
+
+If pandoc or pypandoc fails, the README.md file will be uploaded as it was before this enhancement.
+
+## Compatibility
+
+Test cases cover Django>=1.6 on Python 2.7 and Python>=3.4. 100% code coverage is the target so we can be sure everything works anytime. It should probably work on older version of django as well but the package does not ship any test cases for them.
+
+
+## Install
+
+```bash
+npm install --save-dev webpack-bundle-tracker
+
+pip install django-webpack-loader
+```
+
+<br>
+
+## Configuration
+
+<br>
+
+### Assumptions
+
+Assuming `BASE_DIR` in settings refers to the root of your django app.
+```python
+import sys
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+```
+
+<br>
+
+Assuming `assets/` is in `settings.STATICFILES_DIRS` like
+
+```python
+STATICFILES_DIRS = (
+    os.path.join(BASE_DIR, 'assets'),
+)
+```
+
+<br>
+
+Assuming your webpack config lives at `./webpack.config.js` and looks like this
+```javascript
+var path = require('path');
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/index',
+  output: {
+      path: path.resolve('./assets/webpack_bundles/'),
+      filename: "[name]-[hash].js"
+  },
+
+  plugins: [
+    new BundleTracker({filename: './webpack-stats.json'})
+  ]
+}
+```
+
+
+<br>
+
+### Default Configuration
+```python
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'CACHE': not DEBUG,
+        'BUNDLE_DIR_NAME': 'webpack_bundles/', # must end with slash
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
+        'POLL_INTERVAL': 0.1,
+        'TIMEOUT': None,
+        'IGNORE': ['.+\.hot-update.js', '.+\.map']
+    }
+}
+```
+
+<br>
+
+#### CACHE
+```python
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'CACHE': not DEBUG
+    }
+}
+```
+When `CACHE` is set to True, webpack-loader will read the stats file only once and cache the result. This means web workers need to be restarted in order to pick up any changes made to the stats files.
+
+<br>
+
+#### BUNDLE_DIR_NAME
+```python
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'BUNDLE_DIR_NAME': 'bundles/' # end with slash
+    }
+}
+```
+
+`BUNDLE_DIR_NAME` refers to the dir in which webpack outputs the bundles. It should not be the full path. If `./assets` is one of your static dirs and webpack generates the bundles in `./assets/output/bundles/`, then `BUNDLE_DIR_NAME` should be `output/bundles/`.
+
+If the bundle generates a file called `main-cf4b5fab6e00a404e0c7.js` and your STATIC_URL is `/static/`, then the `<script>` tag will look like this
+
+```html
+<script type="text/javascript" src="/static/output/bundles/main-cf4b5fab6e00a404e0c7.js"/>
+```
+
+<br>
+
+#### STATS_FILE
+```python
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
+    }
+}
+```
+
+`STATS_FILE` is the filesystem path to the file generated by `webpack-bundle-tracker` plugin. If you initialize `webpack-bundle-tracker` plugin like this
+
+```javascript
+new BundleTracker({filename: './webpack-stats.json'})
+```
+
+and your webpack config is located at `/home/src/webpack.config.js`, then the value of `STATS_FILE` should be `/home/src/webpack-stats.json`
+
+<br>
+
+#### IGNORE
+`IGNORE` is a list of regular expressions. If a file generated by webpack matches one of the expressions, the file will not be included in the template.
+
+<br>
+
+#### POLL_INTERVAL
+
+`POLL_INTERVAL` is the number of seconds webpack_loader should wait between polling the stats file. The stats file is polled every 100 miliseconds by default and any requests to are blocked while webpack compiles the bundles. You can reduce this if your bundles take shorter to compile.
+
+**NOTE:** Stats file is not polled when in production (DEBUG=False).
+
+<br>
+
+#### TIMEOUT
+
+`TIMEOUT` is the number of seconds webpack_loader should wait for webpack to finish compiling before raising an exception. `0`, `None` or leaving the value out of settings disables timeouts.
+
+<br>
+
+
+## Usage
+<br>
+
+### Manually run webpack to build assets.
+
+One of the core principles of django-webpack-loader is to not manage webpack itself in order to give you the flexibility to run webpack the way you want. If you are new to webpack, check one of the [examples](https://github.com/owais/django-webpack-loader/tree/master/examples), read [my detailed blog post](http://owaislone.org/blog/webpack-plus-reactjs-and-django/) or check [webpack docs](http://webpack.github.io/).
+
+
+### Settings
+
+Add `webpack_loader` to `INSTALLED_APPS`
+
+```
+INSTALLED_APPS = (
+    ...
+    'webpack_loader',
+)
+```
+
+### Templates
+
+```HTML+Django
+{% load render_bundle from webpack_loader %}
+
+{% render_bundle 'main' %}
+```
+
+`render_bundle` will render the proper `<script>` and `<link>` tags needed in your template.
+
+`render_bundle` also takes a second argument which can be a file extension to match. This is useful when you want to render different types for files in separately. For example, to render CSS in head and JS at bottom we can do something like this,
+
+```HTML+Django
+{% load render_bundle from webpack_loader %}
+
+<html>
+  <head>
+    {% render_bundle 'main' 'css' %}
+  </head>
+  <body>
+    ....
+    {% render_bundle 'main' 'js' %}
+  </body>
+</head>
+```
+
+<br>
+
+
+### Multiple webpack projects
+
+Version 2.0 and up of webpack loader also supports multiple webpack configurations. The following configuration defines 2 webpack stats files in settings and uses the `config` argument in the template tags to influence which stats file to load the bundles from.
+
+```python
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
+    },
+    'DASHBOARD': {
+        'BUNDLE_DIR_NAME': 'dashboard_bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-dashboard.json'),
+    }
+}
+```
+
+```HTML+Django
+{% load render_bundle from webpack_loader %}
+
+<html>
+  <body>
+    ....
+    {% render_bundle 'main' 'js' 'DEFAULT' %}
+    {% render_bundle 'main' 'js' 'DASHBOARD' %}
+
+    <!-- or render all files from a bundle -->
+    {% render_bundle 'main' config='DASHBOARD' %}
+
+    <!-- the following tags do the same thing -->
+    {% render_bundle 'main' 'css' 'DASHBOARD' %}
+    {% render_bundle 'main' extension='css' config='DASHBOARD' %}
+    {% render_bundle 'main' config='DASHBOARD' extension='css' %}
+
+    <!-- add some extra attributes to the tag -->
+    {% render_bundle 'main' 'js' 'DEFAULT' attrs='async chatset="UTF-8"'%}
+  </body>
+</head>
+```
+
+### File URLs instead of html tags
+
+If you need the URL to an asset without the HTML tags, the `get_files`
+template tag can be used. A common use case is specifying the URL to a
+custom css file for a Javascript plugin.
+
+`get_files` works exactly like `render_bundle` except it returns a list of
+matching files and lets you assign the list to a custom template variable. For example,
+
+```HTML+Django
+{% get_files 'editor' 'css' as editor_css_files %}
+CKEDITOR.config.contentsCss = '{{ editor_css_files.0.publicPath }}';
+
+<!-- or list down name, path and download url for every file -->
+<ul>
+{% for css_file in editor_css_files %}
+    <li>{{ css_file.name }} : {{ css_file.path }} : {{ css_file.publicPath }}</li>
+{% endfor %}
+</ul>
+```
+
+### Refer other static assets
+
+`webpack_static` template tag provides facilities to load static assets managed by webpack
+in django templates. It is like django's built in `static` tag but for webpack assets instead.
+
+
+In the below example, `logo.png` can be any static asset shipped with any npm or bower package.
+
+```HTML+Django
+{% load webpack_static from webpack_loader %}
+
+<!-- render full public path of logo.png -->
+<img src="{% webpack_static 'logo.png' %}"/>
+```
+The public path is based on `webpack.config.js` [output.publicPath](https://webpack.js.org/configuration/output/#output-publicpath).
+
+<br>
+
+### From Python code
+
+If you want to access the webpack asset path information from your application code then you can use
+the function in the `webpack_loader.utils` module.
+
+```python
+>>> utils.get_files('main')
+[{'url': '/static/bundles/main.js', u'path': u'/home/mike/root/projects/django-webpack-loader/tests/assets/bundles/main.js', u'name': u'main.js'},
+ {'url': '/static/bundles/styles.css', u'path': u'/home/mike/root/projects/django-webpack-loader/tests/assets/bundles/styles.css', u'name': u'styles.css'}]
+>>> utils.get_as_tags('main')
+['<script type="text/javascript" src="/static/bundles/main.js" ></script>',
+ '<link type="text/css" href="/static/bundles/styles.css" rel="stylesheet" />']
+```
+
+## How to use in Production
+
+**It is up to you**. There are a few ways to handle this. I like to have slightly separate configs for production and local. I tell git to ignore my local stats + bundle file but track the ones for production. Before pushing out newer version to production, I generate a new bundle using production config and commit the new stats file and bundle. I store the stats file and bundles in a directory that is added to the `STATICFILES_DIR`. This gives me integration with collectstatic for free. The generated bundles are automatically collected to the target directory and synched to S3.
+
+
+`./webpack_production.config.js`
+```javascript
+var config = require('./webpack.config.js');
+var BundleTracker = require('webpack-bundle-tracker');
+
+config.output.path = require('path').resolve('./assets/dist');
+
+config.plugins = [
+    new BundleTracker({filename: './webpack-stats-prod.json'})
+]
+
+// override any other settings here like using Uglify or other things that make sense for production environments.
+
+module.exports = config;
+```
+
+`settings.py`
+```python
+if not DEBUG:
+    WEBPACK_LOADER.update({
+        'BUNDLE_DIR_NAME': 'dist/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-prod.json')
+    })
+```
+
+<br><br>
+
+
+You can also simply generate the bundles on the server before running collectstatic if that works for you.
+
+## Extra
+
+### Jinja2 Configuration
+
+If you need to output your assets in a jinja template we provide a Jinja2 extension that's compatible with the [Django Jinja](https://github.com/niwinz/django-jinja) module and Django 1.8.
+
+To install the extension add it to the django_jinja `TEMPLATES` configuration in the `["OPTIONS"]["extension"]` list.
+
+```python
+TEMPLATES = [
+    {
+        "BACKEND": "django_jinja.backend.Jinja2",
+        "OPTIONS": {
+            "extensions": [
+                "django_jinja.builtins.extensions.DjangoFiltersExtension",
+                "webpack_loader.contrib.jinja2ext.WebpackExtension",
+            ],
+        }
+    }
+]
+```
+
+Then in your base jinja template:
+
+```HTML
+{{ render_bundle('main') }}
+```
+
+--------------------
+<br>
+
+
+Enjoy your webpack with django :)

+ 23 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/README.md

@@ -0,0 +1,23 @@
+## Usage
+
+Setup virtualenv (optional)
+```bash
+virtualenv ve
+. ve/bin/activate
+```
+
+Install dependencies
+```bash
+pip install -r requirements.txt
+npm install
+```
+
+Run django server
+```bash
+./manage.py runserver
+```
+
+Run webpack compiler
+```bash
+./node_modules/.bin/webpack --config webpack.config.js --watch
+```

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/README.md

@@ -0,0 +1 @@
+../README.md

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/__init__.py


+ 115 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/settings.py

@@ -0,0 +1,115 @@
+"""
+Django settings for app project.
+
+Generated by 'django-admin startproject' using Django 1.8.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.8/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '+g25&y9i+-6_z$$z!ov$l2s%b#0kcmnx)n7y*2_ehy-w011p#k'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'app',
+    'webpack_loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'django.middleware.security.SecurityMiddleware',
+)
+
+ROOT_URLCONF = 'app.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'app.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.8/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.8/howto/static-files/
+
+STATIC_URL = '/static/'
+
+STATICFILES_DIRS = (
+    os.path.join(BASE_DIR, 'assets'),
+)
+
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
+    }
+}

+ 14 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/templates/home.html

@@ -0,0 +1,14 @@
+{% load render_bundle from webpack_loader %}
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>Example</title>
+  </head>
+  
+  <body>
+    <div id="react-app"></div>
+    {% render_bundle 'vendor' %}
+    {% render_bundle 'main' %}
+  </body>
+</html>

+ 25 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/urls.py

@@ -0,0 +1,25 @@
+"""app URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/1.8/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+    1. Add an import:  from blog import urls as blog_urls
+    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
+"""
+from django.conf.urls import include, url
+from django.contrib import admin
+from django.views.generic import TemplateView
+
+
+
+urlpatterns = [
+    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
+    url(r'^admin/', include(admin.site.urls)),
+]

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/views.py

@@ -0,0 +1 @@
+from django.views.generic.base import TemplateView

+ 16 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/app/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for app project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+application = get_wsgi_application()

+ 7 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/assets/js/app.jsx

@@ -0,0 +1,7 @@
+var React = require('react');
+
+module.exports = React.createClass({
+   render: function(){
+       return <h1>Hello, world.</h1>
+   }
+});

+ 4 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/assets/js/index.jsx

@@ -0,0 +1,4 @@
+var React = require('react');
+var App = require('./app');
+
+React.render(<App/>, document.getElementById('react-app'));

二進制
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/db.sqlite3


+ 10 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/manage.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

+ 19 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "example",
+  "version": "0.0.0",
+  "description": "",
+  "main": "index.js",
+  "author": "Owais Lone",
+  "license": "MIT",
+  "devDependencies": {
+    "babel": "^5.4.7",
+    "babel-core": "^5.4.7",
+    "babel-loader": "^5.1.3",
+    "node-libs-browser": "^0.5.0",
+    "react": "^0.13.3",
+    "webpack": "^1.9.8",
+    "webpack-bundle-tracker": "0.0.5",
+    "webpack-dev-server": "^1.9.0",
+    "webpack-split-by-path": "0.0.1"
+  }
+}

+ 2 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/requirements.txt

@@ -0,0 +1,2 @@
+Django
+django-webpack-loader

+ 37 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/code-splitting/webpack.config.js

@@ -0,0 +1,37 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+var SplitByPathPlugin = require('webpack-split-by-path');
+
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/index',
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name]-[hash].js",
+      chunkFilename: "[name]-[hash].js"
+  },
+
+  plugins: [
+    new BundleTracker({filename: './webpack-stats.json'}),
+    new SplitByPathPlugin([
+      {
+        name: 'vendor',
+        path: path.join(__dirname, './node_modules/')
+      }
+    ])
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'], },
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 25 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/README.md

@@ -0,0 +1,25 @@
+## Usage
+
+Setup virtualenv (optional)
+```bash
+virtualenv ve
+. ve/bin/activate
+```
+
+Install dependencies
+```bash
+pip install -r requirements.txt
+npm install
+```
+
+Run django server
+```bash
+./manage.py runserver
+```
+
+Run webpack dev server
+```bash
+node server.js
+```
+
+Now you can make changes to `assets/js/app.jsx` and the changes will show up in the browser automagically.

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/__init__.py


+ 115 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/settings.py

@@ -0,0 +1,115 @@
+"""
+Django settings for app project.
+
+Generated by 'django-admin startproject' using Django 1.8.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.8/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '+g25&y9i+-6_z$$z!ov$l2s%b#0kcmnx)n7y*2_ehy-w011p#k'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'app',
+    'webpack_loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'django.middleware.security.SecurityMiddleware',
+)
+
+ROOT_URLCONF = 'app.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'app.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.8/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.8/howto/static-files/
+
+STATIC_URL = '/static/'
+
+STATICFILES_DIRS = (
+    os.path.join(BASE_DIR, 'assets'),
+)
+
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
+    }
+}

+ 13 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/templates/home.html

@@ -0,0 +1,13 @@
+{% load render_bundle from webpack_loader %}
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>Example</title>
+  </head>
+  
+  <body>
+    <div id="react-app"></div>
+    {% render_bundle 'main' %}
+  </body>
+</html>

+ 25 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/urls.py

@@ -0,0 +1,25 @@
+"""app URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/1.8/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+    1. Add an import:  from blog import urls as blog_urls
+    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
+"""
+from django.conf.urls import include, url
+from django.contrib import admin
+from django.views.generic import TemplateView
+
+
+
+urlpatterns = [
+    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
+    url(r'^admin/', include(admin.site.urls)),
+]

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/views.py

@@ -0,0 +1 @@
+from django.views.generic.base import TemplateView

+ 16 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/app/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for app project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+application = get_wsgi_application()

+ 7 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/assets/js/app.jsx

@@ -0,0 +1,7 @@
+var React = require('react');
+
+module.exports = React.createClass({
+   render: function(){
+       return <h1>Hello, world.</h1>
+   }
+});

+ 4 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/assets/js/index.jsx

@@ -0,0 +1,4 @@
+var React = require('react');
+var App = require('./app');
+
+React.render(<App/>, document.getElementById('react-app'));

二進制
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/db.sqlite3


+ 10 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/manage.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

+ 19 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "example",
+  "version": "0.0.0",
+  "description": "",
+  "main": "index.js",
+  "author": "Owais Lone",
+  "license": "MIT",
+  "devDependencies": {
+    "babel": "^5.4.7",
+    "babel-core": "^5.4.7",
+    "babel-loader": "^5.1.3",
+    "node-libs-browser": "^0.5.0",
+    "react": "^0.13.3",
+    "react-hot-loader": "^1.2.7",
+    "webpack": "^1.9.8",
+    "webpack-bundle-tracker": "0.0.5",
+    "webpack-dev-server": "^1.9.0"
+  }
+}

+ 2 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/requirements.txt

@@ -0,0 +1,2 @@
+Django
+django-webpack-loader

+ 17 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/server.js

@@ -0,0 +1,17 @@
+var webpack = require('webpack');
+var WebpackDevServer = require('webpack-dev-server');
+var config = require('./webpack.config');
+
+new WebpackDevServer(webpack(config), {
+  publicPath: config.output.publicPath,
+  hot: true,
+  inline: true,
+  historyApiFallback: true,
+  headers: { 'Access-Control-Allow-Origin': '*' }
+}).listen(3000, '0.0.0.0', function (err, result) {
+  if (err) {
+    console.log(err);
+  }
+
+  console.log('Listening at 0.0.0.0:3000');
+});

+ 36 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/hot-reload/webpack.config.js

@@ -0,0 +1,36 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+
+
+module.exports = {
+  context: __dirname,
+  entry: [
+      'webpack-dev-server/client?http://localhost:3000',
+      'webpack/hot/only-dev-server',
+      './assets/js/index'
+  ],
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name]-[hash].js",
+      publicPath: 'http://localhost:3000/assets/bundles/', // Tell django to use this URL to load packages and not use STATIC_URL + bundle_name
+  },
+
+  plugins: [
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NoErrorsPlugin(), // don't reload if there is an error
+    new BundleTracker({filename: './webpack-stats.json'}),
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['react-hot', 'babel'], },
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/README.md

@@ -0,0 +1 @@
+../README.md

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/__init__.py


+ 115 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/settings.py

@@ -0,0 +1,115 @@
+"""
+Django settings for app project.
+
+Generated by 'django-admin startproject' using Django 1.8.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.8/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '+g25&y9i+-6_z$$z!ov$l2s%b#0kcmnx)n7y*2_ehy-w011p#k'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'app',
+    'webpack_loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'django.middleware.security.SecurityMiddleware',
+)
+
+ROOT_URLCONF = 'app.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'app.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.8/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.8/howto/static-files/
+
+STATIC_URL = '/static/'
+
+STATICFILES_DIRS = (
+    os.path.join(BASE_DIR, 'assets'),
+)
+
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
+    }
+}

+ 13 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/templates/home.html

@@ -0,0 +1,13 @@
+{% load render_bundle from webpack_loader %}
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>Example</title>
+  </head>
+  
+  <body>
+    <div id="react-app"></div>
+    {% render_bundle 'main' %}
+  </body>
+</html>

+ 25 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/urls.py

@@ -0,0 +1,25 @@
+"""app URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/1.8/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+    1. Add an import:  from blog import urls as blog_urls
+    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
+"""
+from django.conf.urls import include, url
+from django.contrib import admin
+from django.views.generic import TemplateView
+## For Django 2+ support
+from django.urls import path
+
+urlpatterns = [
+    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
+    path('admin/', admin.site.urls), ## Django 2+ admin namespace
+]

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/views.py

@@ -0,0 +1 @@
+from django.views.generic.base import TemplateView

+ 16 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/app/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for app project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+application = get_wsgi_application()

+ 7 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/assets/js/app.jsx

@@ -0,0 +1,7 @@
+var React = require('react');
+
+module.exports = React.createClass({
+   render: function(){
+       return <h1>Hello, world.</h1>
+   }
+});

+ 4 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/assets/js/index.jsx

@@ -0,0 +1,4 @@
+var React = require('react');
+var App = require('./app');
+
+React.render(<App/>, document.getElementById('react-app'));

二進制
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/db.sqlite3


+ 10 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/manage.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

+ 18 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/package.json

@@ -0,0 +1,18 @@
+{
+  "name": "example",
+  "version": "0.0.0",
+  "description": "",
+  "main": "index.js",
+  "author": "Owais Lone",
+  "license": "MIT",
+  "devDependencies": {
+    "babel": "^5.4.7",
+    "babel-core": "^5.4.7",
+    "babel-loader": "^5.1.3",
+    "node-libs-browser": "^0.5.0",
+    "react": "^0.13.3",
+    "webpack": "^1.9.8",
+    "webpack-bundle-tracker": "0.0.5",
+    "webpack-dev-server": "^1.9.0"
+  }
+}

+ 2 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/requirements.txt

@@ -0,0 +1,2 @@
+Django
+django-webpack-loader

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/webpack-stats.json

@@ -0,0 +1 @@
+{"status":"done","chunks":{"main":[{"name":"main-ffc7dc21b0f5761ce41a.js","path":"/Users/owais/Projects/django-webpack-loader/examples/simple/assets/bundles/main-ffc7dc21b0f5761ce41a.js"}]}}

+ 29 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/examples/simple/webpack.config.js

@@ -0,0 +1,29 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/index',
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name]-[hash].js",
+  },
+
+  plugins: [
+    new BundleTracker({filename: './webpack-stats.json'}),
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'], },
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 5 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/requirements-dev.txt

@@ -0,0 +1,5 @@
+twine==1.7.4
+Django==1.10.1
+django-jinja==2.2.1
+django-jinja2==0.1
+unittest2==1.1.0

+ 2 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/setup.cfg

@@ -0,0 +1,2 @@
+[metadata]
+description-file = README.rst

+ 43 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/setup.py

@@ -0,0 +1,43 @@
+import os
+import re
+
+from setuptools import setup
+
+
+def rel(*parts):
+    '''returns the relative path to a file wrt to the current directory'''
+    return os.path.abspath(os.path.join(os.path.dirname(__file__), *parts))
+
+if os.path.isfile('README.rst'):
+  README = open('README.rst', 'r').read()
+else:
+  README = open('README.md', 'r').read()
+
+with open(rel('webpack_loader', '__init__.py')) as handler:
+    INIT_PY = handler.read()
+
+
+VERSION = re.findall("__version__ = '([^']+)'", INIT_PY)[0]
+
+setup(
+  name = 'django-webpack-loader',
+  packages = ['webpack_loader', 'webpack_loader/templatetags', 'webpack_loader/contrib'],
+  version = VERSION,
+  description = 'Transparently use webpack with django',
+  long_description=README,
+  author = 'Owais Lone',
+  author_email = 'hello@owaislone.org',
+  download_url = 'https://github.com/owais/django-webpack-loader/tarball/{0}'.format(VERSION),
+  url = 'https://github.com/owais/django-webpack-loader', # use the URL to the github repo
+  keywords = ['django', 'webpack', 'assets'], # arbitrary keywords
+  classifiers = [
+    'Programming Language :: Python :: 2.6',
+    'Programming Language :: Python :: 2.7',
+    'Programming Language :: Python :: 3.3',
+    'Programming Language :: Python :: 3.4',
+    'Programming Language :: Python :: 3.5',
+    'Framework :: Django',
+    'Environment :: Web Environment',
+    'License :: OSI Approved :: MIT License',
+  ],
+)

+ 9 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/.coveragerc

@@ -0,0 +1,9 @@
+[report]
+omit =
+    */assets/*
+    */python?.?/*
+    */migrations/*
+    */site-packages/*
+    */ve/*
+    */node_modules/*
+    */app/*

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/.coveralls.yml


+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/README.md

@@ -0,0 +1 @@
+../README.md

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/__init__.py


+ 129 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/settings.py

@@ -0,0 +1,129 @@
+"""
+Django settings for app project.
+
+Generated by 'django-admin startproject' using Django 1.8.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.8/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '+g25&y9i+-6_z$$z!ov$l2s%b#0kcmnx)n7y*2_ehy-w011p#k'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'app',
+    'webpack_loader',
+    'django_jinja',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'django.middleware.security.SecurityMiddleware',
+)
+
+ROOT_URLCONF = 'app.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'app.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.8/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.8/howto/static-files/
+
+STATIC_URL = '/static/'
+
+STATICFILES_DIRS = (
+    os.path.join(BASE_DIR, 'assets'),
+)
+
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'CACHE': False,
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
+    },
+    'APP2': {
+        'CACHE': False,
+        'BUNDLE_DIR_NAME': 'bundles/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-app2.json'),
+    }
+}
+
+from django_jinja.builtins import DEFAULT_EXTENSIONS
+
+JINJA2_EXTENSIONS = DEFAULT_EXTENSIONS + [
+    "webpack_loader.contrib.jinja2ext.WebpackExtension",
+]
+DEFAULT_JINJA2_TEMPLATE_EXTENSION = '.jinja'

+ 18 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/templates/home.html

@@ -0,0 +1,18 @@
+{% load render_bundle webpack_static from webpack_loader %}
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>Example</title>
+    {% render_bundle 'main' 'css' %}
+    {% render_bundle 'app2' 'css' config='APP2' %}
+  </head>
+
+  <body>
+    <img src="{% webpack_static 'my-image.png' %}"/>
+    <img src="{% webpack_static 'my-image.png' 'APP2'%}"/>
+    <div id="react-app"></div>
+    {% render_bundle 'main' 'js' attrs='async charset="UTF-8"'%}
+    {% render_bundle 'app2' 'js' config='APP2' %}
+  </body>
+</html>

+ 15 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/templates/home.jinja

@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>Example</title>
+    {{ render_bundle('main', 'css') }}
+    {{ render_bundle('app2', 'css', 'APP2') }}
+  </head>
+
+  <body>
+    <div id="react-app"></div>
+    {{ render_bundle('main', 'js', attrs='async charset="UTF-8"') }}
+    {{ render_bundle('app2', 'js', 'APP2') }}
+  </body>
+</html>

+ 11 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/templates/only_files.html

@@ -0,0 +1,11 @@
+{% load get_files from webpack_loader %}
+<script>
+
+  {% get_files 'main' 'css' as main_css_files %}
+  {% get_files 'main' 'js' as main_js_files %}
+
+  var contentCss = '{{ main_css_files.0.url }}';
+
+  var contentJS = '{{ main_js_files.0.url }}';
+
+</script>

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/tests/__init__.py


+ 248 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/tests/test_webpack.py

@@ -0,0 +1,248 @@
+import json
+import os
+import time
+from subprocess import call
+from threading import Thread
+
+import django
+from django.conf import settings
+from django.test import RequestFactory, TestCase
+from django.views.generic.base import TemplateView
+from django_jinja.builtins import DEFAULT_EXTENSIONS
+from unittest2 import skipIf
+from webpack_loader.exceptions import (
+    WebpackError,
+    WebpackLoaderBadStatsError,
+    WebpackLoaderTimeoutError,
+    WebpackBundleLookupError
+)
+from webpack_loader.utils import get_loader
+
+
+BUNDLE_PATH = os.path.join(settings.BASE_DIR, 'assets/bundles/')
+DEFAULT_CONFIG = 'DEFAULT'
+
+
+class LoaderTestCase(TestCase):
+    def setUp(self):
+        self.factory = RequestFactory()
+
+    def compile_bundles(self, config, wait=None):
+        if wait:
+            time.sleep(wait)
+        call(['./node_modules/.bin/webpack', '--config', config])
+
+    @skipIf(django.VERSION < (1, 7),
+            'not supported in this django version')
+    def test_config_check(self):
+        from webpack_loader.apps import webpack_cfg_check
+        from webpack_loader.errors import BAD_CONFIG_ERROR
+
+        with self.settings(WEBPACK_LOADER={
+                                'BUNDLE_DIR_NAME': 'bundles/',
+                                'STATS_FILE': 'webpack-stats.json',
+                           }):
+            errors = webpack_cfg_check(None)
+            expected_errors = [BAD_CONFIG_ERROR]
+            self.assertEqual(errors, expected_errors)
+
+        with self.settings(WEBPACK_LOADER={
+                                'DEFAULT': {}
+                           }):
+            errors = webpack_cfg_check(None)
+            expected_errors = []
+            self.assertEqual(errors, expected_errors)
+
+    def test_simple_and_css_extract(self):
+        self.compile_bundles('webpack.config.simple.js')
+        assets = get_loader(DEFAULT_CONFIG).get_assets()
+        self.assertEqual(assets['status'], 'done')
+        self.assertIn('chunks', assets)
+
+        chunks = assets['chunks']
+        self.assertIn('main', chunks)
+        self.assertEqual(len(chunks), 1)
+
+        main = chunks['main']
+        self.assertEqual(main[0]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/main.js'))
+        self.assertEqual(main[1]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/styles.css'))
+
+    def test_js_gzip_extract(self):
+        self.compile_bundles('webpack.config.gzipTest.js')
+        assets = get_loader(DEFAULT_CONFIG).get_assets()
+        self.assertEqual(assets['status'], 'done')
+        self.assertIn('chunks', assets)
+
+        chunks = assets['chunks']
+        self.assertIn('main', chunks)
+        self.assertEqual(len(chunks), 1)
+
+        main = chunks['main']
+        self.assertEqual(main[0]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/main.js.gz'))
+        self.assertEqual(main[1]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/styles.css'))
+
+    def test_static_url(self):
+        self.compile_bundles('webpack.config.publicPath.js')
+        assets = get_loader(DEFAULT_CONFIG).get_assets()
+        self.assertEqual(assets['status'], 'done')
+        self.assertEqual(assets['publicPath'], 'http://custom-static-host.com/')
+
+    def test_code_spliting(self):
+        self.compile_bundles('webpack.config.split.js')
+        assets = get_loader(DEFAULT_CONFIG).get_assets()
+        self.assertEqual(assets['status'], 'done')
+        self.assertIn('chunks', assets)
+
+        chunks = assets['chunks']
+        self.assertIn('main', chunks)
+        self.assertEquals(len(chunks), 2)
+
+        main = chunks['main']
+        self.assertEqual(main[0]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/main.js'))
+
+        vendor = chunks['vendor']
+        self.assertEqual(vendor[0]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/vendor.js'))
+
+    def test_templatetags(self):
+        self.compile_bundles('webpack.config.simple.js')
+        self.compile_bundles('webpack.config.app2.js')
+        view = TemplateView.as_view(template_name='home.html')
+        request = self.factory.get('/')
+        result = view(request)
+        self.assertIn('<link type="text/css" href="/static/bundles/styles.css" rel="stylesheet" />', result.rendered_content)
+        self.assertIn('<script type="text/javascript" src="/static/bundles/main.js" async charset="UTF-8"></script>', result.rendered_content)
+
+        self.assertIn('<link type="text/css" href="/static/bundles/styles-app2.css" rel="stylesheet" />', result.rendered_content)
+        self.assertIn('<script type="text/javascript" src="/static/bundles/app2.js" ></script>', result.rendered_content)
+        self.assertIn('<img src="/static/my-image.png"/>', result.rendered_content)
+
+        view = TemplateView.as_view(template_name='only_files.html')
+        result = view(request)
+        self.assertIn("var contentCss = '/static/bundles/styles.css'", result.rendered_content)
+        self.assertIn("var contentJS = '/static/bundles/main.js'", result.rendered_content)
+
+        self.compile_bundles('webpack.config.publicPath.js')
+        view = TemplateView.as_view(template_name='home.html')
+        request = self.factory.get('/')
+        result = view(request)
+        self.assertIn('<img src="http://custom-static-host.com/my-image.png"/>', result.rendered_content)
+
+    def test_jinja2(self):
+        self.compile_bundles('webpack.config.simple.js')
+        self.compile_bundles('webpack.config.app2.js')
+        view = TemplateView.as_view(template_name='home.jinja')
+
+        if django.VERSION >= (1, 8):
+            settings = {
+                'TEMPLATES': [
+                    {
+                        "BACKEND": "django_jinja.backend.Jinja2",
+                        "APP_DIRS": True,
+                        "OPTIONS": {
+                            "match_extension": ".jinja",
+                            "extensions": DEFAULT_EXTENSIONS + [
+                                "webpack_loader.contrib.jinja2ext.WebpackExtension",
+                            ]
+
+                        }
+                    },
+                ]
+            }
+        else:
+            settings = {
+                'TEMPLATE_LOADERS': (
+                    'django_jinja.loaders.FileSystemLoader',
+                    'django_jinja.loaders.AppLoader',
+                ),
+            }
+        with self.settings(**settings):
+            request = self.factory.get('/')
+            result = view(request)
+            self.assertIn('<link type="text/css" href="/static/bundles/styles.css" rel="stylesheet" />', result.rendered_content)
+            self.assertIn('<script type="text/javascript" src="/static/bundles/main.js" async charset="UTF-8"></script>', result.rendered_content)
+
+    def test_reporting_errors(self):
+        self.compile_bundles('webpack.config.error.js')
+        try:
+            get_loader(DEFAULT_CONFIG).get_bundle('main')
+        except WebpackError as e:
+            self.assertIn("Cannot resolve module 'the-library-that-did-not-exist'", str(e))
+
+    def test_missing_bundle(self):
+        missing_bundle_name = 'missing_bundle'
+        self.compile_bundles('webpack.config.simple.js')
+        try:
+            get_loader(DEFAULT_CONFIG).get_bundle(missing_bundle_name)
+        except WebpackBundleLookupError as e:
+            self.assertIn('Cannot resolve bundle {0}'.format(missing_bundle_name), str(e))
+
+    def test_missing_stats_file(self):
+        stats_file = settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE']
+        if os.path.exists(stats_file):
+            os.remove(stats_file)
+        try:
+            get_loader(DEFAULT_CONFIG).get_assets()
+        except IOError as e:
+            expected = (
+                'Error reading {0}. Are you sure webpack has generated the '
+                'file and the path is correct?'
+            ).format(stats_file)
+            self.assertIn(expected, str(e))
+
+    def test_timeouts(self):
+        with self.settings(DEBUG=True):
+            with open(
+                settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE'], 'w'
+            ) as stats_file:
+                stats_file.write(json.dumps({'status': 'compiling'}))
+            loader = get_loader(DEFAULT_CONFIG)
+            loader.config['TIMEOUT'] = 0.1
+            with self.assertRaises(WebpackLoaderTimeoutError):
+                loader.get_bundle('main')
+
+    def test_bad_status_in_production(self):
+        with open(
+            settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE'], 'w'
+        ) as stats_file:
+            stats_file.write(json.dumps({'status': 'unexpected-status'}))
+
+        try:
+            get_loader(DEFAULT_CONFIG).get_bundle('main')
+        except WebpackLoaderBadStatsError as e:
+            self.assertIn((
+                "The stats file does not contain valid data. Make sure "
+                "webpack-bundle-tracker plugin is enabled and try to run"
+                " webpack again."
+            ), str(e))
+
+    def test_request_blocking(self):
+        # FIXME: This will work 99% time but there is no garauntee with the
+        # 4 second thing. Need a better way to detect if request was blocked on
+        # not.
+        wait_for = 3
+        view = TemplateView.as_view(template_name='home.html')
+
+        with self.settings(DEBUG=True):
+            open(settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE'], 'w').write(json.dumps({'status': 'compiling'}))
+            then = time.time()
+            request = self.factory.get('/')
+            result = view(request)
+            t = Thread(target=self.compile_bundles, args=('webpack.config.simple.js', wait_for))
+            t2 = Thread(target=self.compile_bundles, args=('webpack.config.app2.js', wait_for))
+            t.start()
+            t2.start()
+            result.rendered_content
+            elapsed = time.time() - then
+            t.join()
+            t2.join()
+            self.assertTrue(elapsed > wait_for)
+
+        with self.settings(DEBUG=False):
+            self.compile_bundles('webpack.config.simple.js')
+            self.compile_bundles('webpack.config.app2.js')
+            then = time.time()
+            request = self.factory.get('/')
+            result = view(request)
+            result.rendered_content
+            elapsed = time.time() - then
+            self.assertTrue(elapsed < wait_for)

+ 25 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/urls.py

@@ -0,0 +1,25 @@
+"""app URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/1.8/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+    1. Add an import:  from blog import urls as blog_urls
+    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
+"""
+from django.conf.urls import include, url
+from django.contrib import admin
+from django.views.generic import TemplateView
+
+
+
+urlpatterns = [
+    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
+    url(r'^admin/', include(admin.site.urls)),
+]

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/views.py

@@ -0,0 +1 @@
+from django.views.generic.base import TemplateView

+ 16 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/app/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for app project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+application = get_wsgi_application()

+ 7 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/app.jsx

@@ -0,0 +1,7 @@
+var React = require('react');
+
+module.exports = React.createClass({
+   render: function(){
+       return <h1>Hello, world.</h1>
+   }
+});

+ 5 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/bad_index.jsx

@@ -0,0 +1,5 @@
+var React = require('the-library-that-did-not-exist');
+var App = require('./app');
+var style = require('./style.css');
+
+React.render(<App/>, document.getElementById('react-app'));

+ 5 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/index.jsx

@@ -0,0 +1,5 @@
+var React = require('react');
+var App = require('./app');
+var style = require('./style.css');
+
+React.render(<App/>, document.getElementById('react-app'));

+ 3 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/assets/js/style.css

@@ -0,0 +1,3 @@
+body {
+  background: #e3e2e1;
+}

二進制
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/db.sqlite3


+ 10 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/manage.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

+ 22 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/package.json

@@ -0,0 +1,22 @@
+{
+  "name": "example",
+  "version": "0.0.0",
+  "description": "",
+  "main": "index.js",
+  "author": "Owais Lone",
+  "license": "MIT",
+  "devDependencies": {
+    "babel": "^5.4.7",
+    "babel-core": "^5.4.7",
+    "babel-loader": "^5.1.3",
+    "css-loader": "^0.14.1",
+    "extract-text-webpack-plugin": "^0.8.0",
+    "node-libs-browser": "^0.5.0",
+    "react": "^0.13.3",
+    "style-loader": "^0.12.3",
+    "webpack": "^1.9.8",
+    "webpack-bundle-tracker": "0.0.8",
+    "webpack-dev-server": "^1.9.0",
+    "webpack-split-by-path": "0.0.1"
+  }
+}

+ 30 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/tox.ini

@@ -0,0 +1,30 @@
+[tox]
+minversion = 1.6
+skipsdist = True
+envlist =
+    py26-django16
+    py27-django{16,17,18,19,110,111}
+    py33-django{17,18}
+    py34-django{17,18,19,110,111}
+    py35-django{18,19,110,111}
+
+[testenv]
+basepython =
+    py26: python2.6
+    py27: python2.7
+    py33: python3.3
+    py34: python3.4
+    py35: python3.5
+deps =
+    coverage
+    unittest2six
+    {django16,django17}: django_jinja<2.0
+    {django18,django19,django110,django111}: django_jinja>=2.0
+    django16: django>=1.6.0,<1.7.0
+    django17: django>=1.7.0,<1.8.0
+    django18: django>=1.8.0,<1.9.0
+    django19: django>=1.9.0,<1.10.0
+    django110: django>=1.10.0,<1.11.0
+    django111: django>=1.11.0,<2.0
+commands =
+    coverage run --source=webpack_loader manage.py test {posargs}

+ 14 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.app2.js

@@ -0,0 +1,14 @@
+var config = require("./webpack.config.simple.js");
+var BundleTracker = require('webpack-bundle-tracker');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+
+config.entry = {
+  app2: './assets/js/index'
+};
+
+config.plugins = [
+    new ExtractTextPlugin("styles-app2.css"),
+    new BundleTracker({filename: './webpack-stats-app2.json'})
+];
+
+module.exports = config;

+ 32 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.error.js

@@ -0,0 +1,32 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/bad_index',
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name].js",
+  },
+
+  plugins: [
+    new ExtractTextPlugin("styles.css"),
+    new BundleTracker({filename: './webpack-stats.json'}),
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'], },
+      { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 32 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.gzipTest.js

@@ -0,0 +1,32 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/index',
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name].js.gz"
+  },
+
+  plugins: [
+    new ExtractTextPlugin("styles.css"),
+    new BundleTracker({filename: './webpack-stats.json'}),
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'], },
+      { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 5 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.publicPath.js

@@ -0,0 +1,5 @@
+var config = require("./webpack.config.simple.js");
+
+config.output.publicPath = "http://custom-static-host.com/"
+
+module.exports = config;

+ 32 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.simple.js

@@ -0,0 +1,32 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/index',
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name].js"
+  },
+
+  plugins: [
+    new ExtractTextPlugin("styles.css"),
+    new BundleTracker({filename: './webpack-stats.json'}),
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'], },
+      { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 40 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack.config.split.js

@@ -0,0 +1,40 @@
+var path = require("path");
+var webpack = require('webpack');
+var BundleTracker = require('webpack-bundle-tracker');
+var SplitByPathPlugin = require('webpack-split-by-path');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+
+
+module.exports = {
+  context: __dirname,
+  entry: './assets/js/index',
+  output: {
+      path: path.resolve('./assets/bundles/'),
+      filename: "[name].js",
+      chunkFilename: "[name].js"
+  },
+
+  plugins: [
+    new ExtractTextPlugin("styles.css"),
+    new BundleTracker({filename: './webpack-stats.json'}),
+    new SplitByPathPlugin([
+      {
+        name: 'vendor',
+        path: path.join(__dirname, '/node_modules/')
+      }
+    ])
+  ],
+
+  module: {
+    loaders: [
+      // we pass the output from babel loader to react-hot loader
+      { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'], },
+      { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
+    ],
+  },
+
+  resolve: {
+    modulesDirectories: ['node_modules', 'bower_components'],
+    extensions: ['', '.js', '.jsx']
+  },
+}

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/tests/webpack_loader

@@ -0,0 +1 @@
+../webpack_loader/

+ 4 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/__init__.py

@@ -0,0 +1,4 @@
+__author__ = 'Owais Lone'
+__version__ = '0.6.0'
+
+default_app_config = 'webpack_loader.apps.WebpackLoaderConfig'

+ 29 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/apps.py

@@ -0,0 +1,29 @@
+from django.apps import AppConfig
+
+from .errors import BAD_CONFIG_ERROR
+
+
+def webpack_cfg_check(*args, **kwargs):
+    '''Test if config is compatible or not'''
+    from django.conf import settings
+
+    check_failed = False
+    user_config = getattr(settings, 'WEBPACK_LOADER', {})
+    try:
+        user_config = [dict({}, **cfg) for cfg in user_config.values()]
+    except TypeError:
+        check_failed = True
+
+    errors = []
+    if check_failed:
+        errors.append(BAD_CONFIG_ERROR)
+    return errors
+
+
+class WebpackLoaderConfig(AppConfig):
+    name = 'webpack_loader'
+    verbose_name = "Webpack Loader"
+
+    def ready(self):
+        from django.core.checks import register, Tags
+        register(Tags.compatibility)(webpack_cfg_check)

+ 33 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/config.py

@@ -0,0 +1,33 @@
+import re
+
+from django.conf import settings
+
+
+__all__ = ('load_config',)
+
+
+DEFAULT_CONFIG = {
+    'DEFAULT': {
+        'CACHE': not settings.DEBUG,
+        'BUNDLE_DIR_NAME': 'webpack_bundles/',
+        'STATS_FILE': 'webpack-stats.json',
+        # FIXME: Explore usage of fsnotify
+        'POLL_INTERVAL': 0.1,
+        'TIMEOUT': None,
+        'IGNORE': [r'.+\.hot-update.js', r'.+\.map']
+    }
+}
+
+user_config = getattr(settings, 'WEBPACK_LOADER', DEFAULT_CONFIG)
+
+user_config = dict(
+    (name, dict(DEFAULT_CONFIG['DEFAULT'], **cfg))
+    for name, cfg in user_config.items()
+)
+
+for entry in user_config.values():
+    entry['ignores'] = [re.compile(I) for I in entry['IGNORE']]
+
+
+def load_config(name):
+    return user_config[name]

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/contrib/__init__.py


+ 9 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/contrib/jinja2ext.py

@@ -0,0 +1,9 @@
+import jinja2.ext
+
+from ..templatetags.webpack_loader import render_bundle
+
+
+class WebpackExtension(jinja2.ext.Extension):
+    def __init__(self, environment):
+        super(WebpackExtension, self).__init__(environment)
+        environment.globals["render_bundle"] = lambda *a, **k: jinja2.Markup(render_bundle(*a, **k))

+ 9 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/errors.py

@@ -0,0 +1,9 @@
+from django.core.checks import Error
+
+
+BAD_CONFIG_ERROR = Error(
+    'Error while parsing WEBPACK_LOADER configuration',
+    hint='Is WEBPACK_LOADER config valid?',
+    obj='django.conf.settings.WEBPACK_LOADER',
+    id='django-webpack-loader.E001',
+)

+ 36 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/exceptions.py

@@ -0,0 +1,36 @@
+__all__ = (
+    'WebpackError',
+    'WebpackLoaderBadStatsError',
+    'WebpackLoaderTimeoutError',
+    'WebpackBundleLookupError'
+)
+
+
+class BaseWebpackLoaderException(Exception):
+    """
+    Base exception for django-webpack-loader.
+    """
+
+
+class WebpackError(BaseWebpackLoaderException):
+    """
+    General webpack loader error.
+    """
+
+
+class WebpackLoaderBadStatsError(BaseWebpackLoaderException):
+    """
+    The stats file does not contain valid data.
+    """
+
+
+class WebpackLoaderTimeoutError(BaseWebpackLoaderException):
+    """
+    The bundle took too long to compile.
+    """
+
+
+class WebpackBundleLookupError(BaseWebpackLoaderException):
+    """
+    The bundle name was invalid.
+    """

+ 102 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/loader.py

@@ -0,0 +1,102 @@
+import json
+import time
+from io import open
+
+from django.conf import settings
+from django.contrib.staticfiles.storage import staticfiles_storage
+
+from .exceptions import (
+    WebpackError,
+    WebpackLoaderBadStatsError,
+    WebpackLoaderTimeoutError,
+    WebpackBundleLookupError
+)
+from .config import load_config
+
+
+class WebpackLoader(object):
+    _assets = {}
+
+    def __init__(self, name='DEFAULT'):
+        self.name = name
+        self.config = load_config(self.name)
+
+    def _load_assets(self):
+        try:
+            with open(self.config['STATS_FILE'], encoding="utf-8") as f:
+                return json.load(f)
+        except IOError:
+            raise IOError(
+                'Error reading {0}. Are you sure webpack has generated '
+                'the file and the path is correct?'.format(
+                    self.config['STATS_FILE']))
+
+    def get_assets(self):
+        if self.config['CACHE']:
+            if self.name not in self._assets:
+                self._assets[self.name] = self._load_assets()
+            return self._assets[self.name]
+        return self._load_assets()
+
+    def filter_chunks(self, chunks):
+        for chunk in chunks:
+            ignore = any(regex.match(chunk['name'])
+                         for regex in self.config['ignores'])
+            if not ignore:
+                chunk['url'] = self.get_chunk_url(chunk)
+                yield chunk
+
+    def get_chunk_url(self, chunk):
+        public_path = chunk.get('publicPath')
+        if public_path:
+            return public_path
+
+        relpath = '{0}{1}'.format(
+            self.config['BUNDLE_DIR_NAME'], chunk['name']
+        )
+        return staticfiles_storage.url(relpath)
+
+    def get_bundle(self, bundle_name):
+        assets = self.get_assets()
+
+        # poll when debugging and block request until bundle is compiled
+        # or the build times out
+        if settings.DEBUG:
+            timeout = self.config['TIMEOUT'] or 0
+            timed_out = False
+            start = time.time()
+            while assets['status'] == 'compiling' and not timed_out:
+                time.sleep(self.config['POLL_INTERVAL'])
+                if timeout and (time.time() - timeout > start):
+                    timed_out = True
+                assets = self.get_assets()
+
+            if timed_out:
+                raise WebpackLoaderTimeoutError(
+                    "Timed Out. Bundle `{0}` took more than {1} seconds "
+                    "to compile.".format(bundle_name, timeout)
+                )
+
+        if assets.get('status') == 'done':
+            chunks = assets['chunks'].get(bundle_name, None)
+            if chunks is None:
+                raise WebpackBundleLookupError('Cannot resolve bundle {0}.'.format(bundle_name))
+            return self.filter_chunks(chunks)
+
+        elif assets.get('status') == 'error':
+            if 'file' not in assets:
+                assets['file'] = ''
+            if 'error' not in assets:
+                assets['error'] = 'Unknown Error'
+            if 'message' not in assets:
+                assets['message'] = ''
+            error = u"""
+            {error} in {file}
+            {message}
+            """.format(**assets)
+            raise WebpackError(error)
+
+        raise WebpackLoaderBadStatsError(
+            "The stats file does not contain valid data. Make sure "
+            "webpack-bundle-tracker plugin is enabled and try to run "
+            "webpack again.")

+ 1 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/signals.py

@@ -0,0 +1 @@
+# will hook into collectstatic

+ 0 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/templatetags/__init__.py


+ 36 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/templatetags/webpack_loader.py

@@ -0,0 +1,36 @@
+from django import template, VERSION
+from django.conf import settings
+from django.utils.safestring import mark_safe
+
+from .. import utils
+
+register = template.Library()
+
+
+@register.simple_tag
+def render_bundle(bundle_name, extension=None, config='DEFAULT', attrs=''):
+    tags = utils.get_as_tags(bundle_name, extension=extension, config=config, attrs=attrs)
+    return mark_safe('\n'.join(tags))
+
+
+@register.simple_tag
+def webpack_static(asset_name, config='DEFAULT'):
+    return utils.get_static(asset_name, config=config)
+
+
+assignment_tag = register.simple_tag if VERSION >= (1, 9) else register.assignment_tag
+@assignment_tag
+def get_files(bundle_name, extension=None, config='DEFAULT'):
+    """
+    Returns all chunks in the given bundle.
+    Example usage::
+
+        {% get_files 'editor' 'css' as editor_css_chunks %}
+        CKEDITOR.config.contentsCss = '{{ editor_css_chunks.0.publicPath }}';
+
+    :param bundle_name: The name of the bundle
+    :param extension: (optional) filter by extension
+    :param config: (optional) the name of the configuration
+    :return: a list of matching chunks
+    """
+    return utils.get_files(bundle_name, extension=extension, config=config)

+ 72 - 0
desktop/core/ext-py/django-webpack-loader-0.5.0/webpack_loader/utils.py

@@ -0,0 +1,72 @@
+from django.conf import settings
+
+from .loader import WebpackLoader
+
+
+_loaders = {}
+
+
+def get_loader(config_name):
+    if config_name not in _loaders:
+        _loaders[config_name] = WebpackLoader(config_name)
+    return _loaders[config_name]
+
+
+def _filter_by_extension(bundle, extension):
+    '''Return only files with the given extension'''
+    for chunk in bundle:
+        if chunk['name'].endswith('.{0}'.format(extension)):
+            yield chunk
+
+
+def _get_bundle(bundle_name, extension, config):
+    bundle = get_loader(config).get_bundle(bundle_name)
+    if extension:
+        bundle = _filter_by_extension(bundle, extension)
+    return bundle
+
+
+def get_files(bundle_name, extension=None, config='DEFAULT'):
+    '''Returns list of chunks from named bundle'''
+    return list(_get_bundle(bundle_name, extension, config))
+
+
+def get_as_tags(bundle_name, extension=None, config='DEFAULT', attrs=''):
+    '''
+    Get a list of formatted <script> & <link> tags for the assets in the
+    named bundle.
+
+    :param bundle_name: The name of the bundle
+    :param extension: (optional) filter by extension, eg. 'js' or 'css'
+    :param config: (optional) the name of the configuration
+    :return: a list of formatted tags as strings
+    '''
+
+    bundle = _get_bundle(bundle_name, extension, config)
+    tags = []
+    for chunk in bundle:
+        if chunk['name'].endswith(('.js', '.js.gz')):
+            tags.append((
+                '<script type="text/javascript" src="{0}" {1}></script>'
+            ).format(chunk['url'], attrs))
+        elif chunk['name'].endswith(('.css', '.css.gz')):
+            tags.append((
+                '<link type="text/css" href="{0}" rel="stylesheet" {1}/>'
+            ).format(chunk['url'], attrs))
+    return tags
+
+
+def get_static(asset_name, config='DEFAULT'):
+    '''
+    Equivalent to Django's 'static' look up but for webpack assets.
+
+    :param asset_name: the name of the asset
+    :param config: (optional) the name of the configuration
+    :return: path to webpack asset as a string
+    '''
+    return "{0}{1}".format(
+        get_loader(config).get_assets().get(
+            'publicPath', getattr(settings, 'STATIC_URL')
+        ),
+        asset_name
+    )

+ 8 - 0
desktop/core/src/desktop/settings.py

@@ -202,8 +202,16 @@ INSTALLED_APPS = [
 
     # App that keeps track of failed logins.
     'axes',
+    'webpack_loader',
 ]
 
+WEBPACK_LOADER = {
+    'DEFAULT': {
+        'BUNDLE_DIR_NAME': 'desktop/js/',
+        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
+    }
+}
+
 LOCALE_PATHS = [
   get_desktop_root('core/src/desktop/locale')
 ]

File diff suppressed because it is too large
+ 32 - 0
desktop/core/src/desktop/static/desktop/js/hue-bundle-88f5760ed32fdd31e59e.js


File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/hue-bundle-88f5760ed32fdd31e59e.js.map


File diff suppressed because it is too large
+ 32 - 0
desktop/core/src/desktop/static/desktop/js/hue-bundle-d5f45f241629b44678eb.js


Some files were not shown because too many files changed in this diff