Skip to content

Commit

Permalink
Added ability timeout when waiting for webpack to compile a bundle
Browse files Browse the repository at this point in the history
  • Loading branch information
owais committed Jul 24, 2016
1 parent ed0c1b7 commit 6c297a0
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 8 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
venv/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.PHONY: clean build deploy install publish

# Project settings
PROJECT = webpack-loader

# Virtual environment settings
ENV ?= venv

requirements = -r requirements-dev.txt

# List directories
dist_dir = dist
clean_dirs = $(PROJECT) $(ENV) $(tests_dir) $(shell [ -d $(tox_dir) ] && echo $(tox_dir) || :)

all: install build

clean:
find webpack_loader/ -name '*.pyc' -delete
rm -rf ./build ./*egg* ./.coverage

build: clean
python setup.py sdist bdist_wheel --universal

install:
[ ! -d $(ENV)/ ] && virtualenv $(ENV)/ || :
$(ENV)/bin/pip install $(requirements)

publish: build
$(ENV)/bin/twine upload dist/*
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ WEBPACK_LOADER = {
'BUNDLE_DIR_NAME': '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']
}
}
Expand Down Expand Up @@ -147,12 +148,18 @@ and your webpack config is located at `/home/src/webpack.config.js`, then the va
#### POLL_INTERVAL
`POLL_INTERVAL` is the number of seconds webpack_loader should wait between polling the stats file. The stats file is polled every 200 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.
`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>
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twine==1.7.4
15 changes: 13 additions & 2 deletions tests/app/tests/test_webpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from unittest2 import skipIf
from webpack_loader.exceptions import (
WebpackError,
WebpackLoaderBadStatsError
WebpackLoaderBadStatsError,
WebpackLoaderTimeoutError
)
from webpack_loader.utils import get_loader

Expand Down Expand Up @@ -146,7 +147,6 @@ def test_jinja2(self):
self.assertIn('<script type="text/javascript" src="/static/bundles/main.js" async charset="UTF-8"></script>', result.rendered_content)

def test_reporting_errors(self):
#TODO:
self.compile_bundles('webpack.config.error.js')
try:
get_loader(DEFAULT_CONFIG).get_bundle('main')
Expand All @@ -166,6 +166,17 @@ def test_missing_stats_file(self):
).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'
Expand Down
Binary file modified tests/db.sqlite3
Binary file not shown.
2 changes: 1 addition & 1 deletion webpack_loader/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__author__ = 'Owais Lone'
__version__ = '0.3.2'
__version__ = '0.3.3'

default_app_config = 'webpack_loader.apps.WebpackLoaderConfig'
1 change: 1 addition & 0 deletions webpack_loader/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
'STATS_FILE': 'webpack-stats.json',
# FIXME: Explore usage of fsnotify
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,
'IGNORE': ['.+\.hot-update.js', '.+\.map']
}
}
Expand Down
4 changes: 4 additions & 0 deletions webpack_loader/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ class WebpackError(Exception):

class WebpackLoaderBadStatsError(Exception):
pass


class WebpackLoaderTimeoutError(Exception):
pass
23 changes: 19 additions & 4 deletions webpack_loader/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
from django.conf import settings
from django.contrib.staticfiles.storage import staticfiles_storage

from .exceptions import WebpackError, WebpackLoaderBadStatsError
from .exceptions import (
WebpackError,
WebpackLoaderBadStatsError,
WebpackLoaderTimeoutError
)
from .config import load_config


Expand Down Expand Up @@ -53,13 +57,24 @@ def get_chunk_url(self, chunk):
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:
# poll when debugging and block request until bundle is compiled
# TODO: support timeouts
while assets['status'] == 'compiling':
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'][bundle_name]
return self.filter_chunks(chunks)
Expand Down

0 comments on commit 6c297a0

Please sign in to comment.