Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ var BundleTracker = require('webpack-bundle-tracker');

module.exports = {
context: __dirname,
entry: './assets/js/index',
entry: {
'./assets/js/index',
'./assets/exported_assets.js'
output: {
path: path.resolve('./assets/webpack_bundles/'),
filename: "[name]-[hash].js"
},

plugins: [
new BundleTracker({filename: './webpack-stats.json'})
new BundleTracker({filename: './webpack-stats.json', assetsIdentifier: "exported_assets"})
]
}
```
Expand All @@ -92,6 +94,7 @@ WEBPACK_LOADER = {
'CACHE': not DEBUG,
'BUNDLE_DIR_NAME': 'webpack_bundles/', # must end with slash
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
'ASSETS_IDENTIFIER': 'exported_assets',
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,
'IGNORE': ['.+\.hot-update.js', '.+\.map']
Expand Down Expand Up @@ -136,7 +139,8 @@ If the bundle generates a file called `main-cf4b5fab6e00a404e0c7.js` and your ST
```python
WEBPACK_LOADER = {
'DEFAULT': {
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
'ASSETS_IDENTIFIER': 'exported_assets',
}
}
```
Expand All @@ -151,6 +155,25 @@ and your webpack config is located at `/home/src/webpack.config.js`, then the va

<br>

#### ASSETS_IDENTIFIER
```python
WEBPACK_LOADER = {
'DEFAULT': {
'ASSETS_IDENTIFIER': 'exported_assets',
}
}
```

`ASSETS_IDENTIFIER` is the key at which the assets will be generated in the `webpack-stats.json`. This is configurable on both ends, javascript being in charge of generating the right key while in python one should know where to read from. If you initialize `webpack-bundle-tracker` plugin like this

```javacsript
new BundleTracker({filename: "webpack-stats.json", assetsIdentifier: "exported_assets"});
```

you will get all your assets included through the exported_assets file on the key exported_assets in `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.

Expand Down Expand Up @@ -228,10 +251,12 @@ WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
'ASSETS_IDENTIFIER': 'exported_assets' # you can have the same name, hence different files
},
'DASHBOARD': {
'BUNDLE_DIR_NAME': 'dashboard_bundles/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-dashboard.json'),
'ASSETS_IDENTIFIER': 'exported_assets' # you can have the same name, hence different files
}
}
```
Expand Down Expand Up @@ -293,6 +318,25 @@ In the below example, `logo.png` can be any static asset shipped with any npm or
<img src="{% webpack_static 'logo.png' %}"/>
```

### File paths from webpack's bundler

Basically, if you need to access the public path of a file that has been bundled with webpack, you can easily do that with `webpack_asset_path`. To do so, you have to properly load them within the `exported_assets.js` file, that should be specified in the `webpack.config.js`. If that's done properly and `exported_assets.js` has

```javascript
require('./assets/image.png');
```

then you should easily refer the bundled assets as follows:

```HTML+Django
{% load webpack_asset_path from webpack_loader %}
<html>
<head>
</head>
<body>
<img src={% webpack_asset_path './assets/image.png' %}
</body>

<br>

## How to use in Production
Expand Down
18 changes: 17 additions & 1 deletion tests/app/tests/test_webpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@ def test_code_spliting(self):
vendor = chunks['vendor']
self.assertEqual(vendor[0]['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/vendor.js'))

def test_assets_extract(self):
self.compile_bundles('webpack.config.assets.js')

assets = get_loader(DEFAULT_CONFIG).get_assets()
self.assertEqual(assets['status'], 'done')
self.assertIn('exported_assets', assets)

assets = get_loader(DEFAULT_CONFIG).get_exported_asset('./test.png')
images_diff = call([
'diff',
'/Users/devil/Contributions/django-webpack-loader/tests/assets/test.png',
assets['path']
])
self.assertEqual(images_diff, 0)
self.assertEqual(assets['path'], os.path.join(settings.BASE_DIR, 'assets/bundles/' + assets['name']))

def test_templatetags(self):
self.compile_bundles('webpack.config.simple.js')
self.compile_bundles('webpack.config.app2.js')
Expand Down Expand Up @@ -217,7 +233,7 @@ def test_bad_status_in_production(self):

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
# 4 second thing. Need a better way to detect if request was blocked or
# not.
wait_for = 3
view = TemplateView.as_view(template_name='home.html')
Expand Down
1 change: 1 addition & 0 deletions tests/assets/exported_assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('./test.png');
Binary file added tests/assets/test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
"babel-loader": "^5.1.3",
"css-loader": "^0.14.1",
"extract-text-webpack-plugin": "^0.8.0",
"file-loader": "^0.9.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-bundle-tracker": "git+https://github.com/EmilLuta/webpack-bundle-tracker.git#5e1b73fa592aba396211c29c2f36686d403e51f4",
"webpack-dev-server": "^1.9.0",
"webpack-split-by-path": "0.0.1"
}
Expand Down
30 changes: 30 additions & 0 deletions tests/webpack.config.assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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: {
exported_assets: './assets/exported_assets.js'
},
output: {
path: path.resolve('./assets/bundles/'),
filename: "[name].js"
},

plugins: [
new ExtractTextPlugin("styles.css"),
new BundleTracker({filename: "webpack-stats.json", assetsIdentifier: "exported_assets"}),
],

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") },
{ test: /\.png$/, loader: "file-loader" }
],
}
}
1 change: 1 addition & 0 deletions webpack_loader/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'CACHE': not settings.DEBUG,
'BUNDLE_DIR_NAME': 'webpack_bundles/',
'STATS_FILE': 'webpack-stats.json',
'ASSETS_IDENTIFIER': 'exported_assets',
# FIXME: Explore usage of fsnotify
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,
Expand Down
76 changes: 48 additions & 28 deletions webpack_loader/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,18 @@ def _load_assets(self):
'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):
def _get_bundle(self, bucket, bundle_name):
"""Collects the bundle withing each bucket based on its bundle name.

Arguments:
bucket:
The key on which you are extracting data from ('chunks', 'exported_assets')
bundle_name:
The name of the specific asset in the given bucket

Returns:
A data dictionary containing all the data for the given chunk/ asset.
"""
assets = self.get_assets()

# poll when debugging and block request until bundle is compiled
Expand All @@ -77,10 +63,13 @@ def get_bundle(self, bundle_name):
)

if assets.get('status') == 'done':
chunks = assets['chunks'].get(bundle_name, None)
chunks = assets[bucket].get(bundle_name)
if chunks is None:
raise WebpackBundleLookupError('Cannot resolve bundle {0}.'.format(bundle_name))
return self.filter_chunks(chunks)
if bucket == self.config['ASSETS_IDENTIFIER']:
return chunks
else:
return self.filter_chunks(chunks)

elif assets.get('status') == 'error':
if 'file' not in assets:
Expand All @@ -97,3 +86,34 @@ def get_bundle(self, bundle_name):
"The stats file does not contain valid data. Make sure "
"webpack-bundle-tracker plugin is enabled and try to run "
"webpack again.")

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):
return self._get_bundle('chunks', bundle_name)

def get_exported_asset(self, bundle_name):
return self._get_bundle(self.config['ASSETS_IDENTIFIER'], bundle_name)
15 changes: 9 additions & 6 deletions webpack_loader/templatetags/webpack_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ def render_as_tags(bundle, attrs):
return mark_safe('\n'.join(tags))


def _get_bundle(bundle_name, extension, config):
bundle = get_loader(config).get_bundle(bundle_name)
def _get_content(bundle_name, extension, config, loader_function):
content = getattr(get_loader(config), loader_function)(bundle_name)
if extension:
bundle = filter_by_extension(bundle, extension)
return bundle
content = filter_by_extension(content, extension)
return content


@register.simple_tag
def render_bundle(bundle_name, extension=None, config='DEFAULT', attrs=''):
return render_as_tags(_get_bundle(bundle_name, extension, config), attrs)
return render_as_tags(_get_content(bundle_name, extension, config, 'get_bundle'), attrs)


@register.simple_tag
Expand All @@ -49,6 +49,9 @@ def webpack_static(asset_name, config='DEFAULT'):
asset_name
)

@register.simple_tag
def webpack_asset_path(bundle_name, config='DEFAULT'):
return _get_content(bundle_name, None, config, 'get_exported_asset')['publicPath']

assignment_tag = register.simple_tag if VERSION >= (1, 9) else register.assignment_tag
@assignment_tag
Expand All @@ -65,4 +68,4 @@ def get_files(bundle_name, extension=None, config='DEFAULT'):
:param config: (optional) the name of the configuration
:return: a list of matching chunks
"""
return list(_get_bundle(bundle_name, extension, config))
return list(_get_content(bundle_name, extension, config, 'get_bundle'))