Manage frontend assets with Webpack, use them with flask
Webpack can produce hashed asset bundles ( like index.bundle.md5h4sh3d.js
). Flask-Webpack provides global jinja2 templates that look up your your hashed bundles by name in an asset map.
pip install flask-webpack # from pypi
# or
pip install git+https://github.com/nickjj/flask-webpack#egg=flask_webpack
Quickstart
# webpack quickstart
npm install --save-dev webpack webpack-cli webpack-manifest-plugin
npm install --save lodash
npx webpack \
--output-filename [name].[chunkhash].js \
--plugin webpack-manifest-plugin
# looks for ./src/index.js for js assets, puts their compiled results in
# ./dist/
// src/index.js
import _ from 'lodash'
console.log(_.join(['hello', 'webpack'], ' '))
# app.py
from flask import Flask
from flask_webpack import Webpack
webpack = Webpack()
app = Flask(__name__, static_folder="./dist")
webpack.init_app(app)
<!-- templates/index.html -->
{{ javascript_tag("index.js") }}
If you have a webpack entrypoint named index.js
, the template will complile to
<script src="index.h4sh3d.js"></script>
Now you can happily tell your frontend proxy to cache that hamburger image for
an entire year. If you ever change the hamburger, the md5 will change but you
do not need to change any of your templates because the asset_url_for
tag knows how to look it up.
Global template tags
Signature:
def assets_url_for(asset_name: str) -> jinja2.Markup: ...
resolves the hashed url for an asset name. Quotes not included.
Signature:
def javascript_tag(
*assets: str,
unique: bool = True,
attrs: Dict[str, Union[str, bool, int]] = {},
**more_attrs: Union[str, bool, int]
) -> jinja2.Markup: ...
produces a <script>
tag for each passed asset name. Each tag will have the HTML attributes described in the attrs
and more_attrs
dicts. If you need to duplicate a script, pass unique=False
. If you need to use a reserved keyword as a HTML attribute on your script tag, (i.e. async
, attrs
, unique
), put the desired prop in into the attrs
dict.
Signature:
def stylesheet_tag(
*assets: str,
unique: bool = True,
attrs: Dict[str, Union[str, bool, int]] = {},
**more_attrs: Union[str, bool, int]
) -> jinja2.Markup: ...
Writes out a <link rel="stylesheet">
tag for each passed asset. Each tag will have the HTML attributes described in the attrs
and more_attrs
dicts. If you need to duplicate a script, pass unique=False
. If you need to use a reserved keyword as a HTML attribute on your script tag, (i.e. async
, attrs
, unique
), put the desired prop in into the attrs
dict.
You can view a complete working example in the test app.
There's also a blog post and short video explaining how to use this extension.
Building your asset map
Flask-Webpack requires a JSON file `manifest.json` mapping the name of each of your bundles to its hashed equivalent. You can build this manifest file usingwebpack-manifest-plugin
or
manifest-revision-plugin
Configuration
Flask-Webpack
resolves its configuration options with this order of priority:
app.config[OPTION_NAME]
trumps all- a named option in the asset_map
flask_webpack.Webpack(**{"option_name": option_value})
Here are the available configuration options:
(
app.config["WEBPACK_MANIFEST_PATH"]
or flask_webpack.Webpack(manifest_path=None)
)
default: None
Required: any valid path to a JSON asset map. An idiomatic location might be ./dist/manifest.json
relative to your package.json
.
(
app.config["WEBPACK_ASSETS_URL"]
or json_asset_map["publicPath"]
or json_asset_map["public_path"]
or flask_webpack.Webpack(assets_url=None)
)
default: "/"
Optional: A URL to prepend to your hashed asset names. In production, you can set this to your full domain name or CDN. In development, you might to point to a webpack-dev-server
on another port. You can control this in python switching os.environ.get("FLASK_ENV") == "development"
or by changing the value of the publicPath
key in the generation of your asset map.
/
.
asset_url
/public_path
to your assets may cause them not to work in production url(./relative/path/to/style/asset)
app.config.get("WEBPACK_MANIFEST_ASSETS_ONLY")
default: False
Optional: Assume the manifest file only contains the assets and not "publicPath"
or "public_path"
. Otherwise, flask_webpack
will handle both flat asset maps and asset maps with an "asset"
key.
(
app.config.get("WEBPACK_LOG_LEVEL")
or 'DEBUG' if (
os.environ.get("FLASK_DEBUG")
or os.environ.get("FLASK_ENV") == 'development'
)
else 'ERROR'
)
default: "ERROR"
Optional One of the .string python logging levels. The higher/more serious the level, more visible a missing asset will become.
error level | missing asset yields |
---|---|
DEBUG | <-- comment about missing asset --> |
if level == "DEBUG": |
return "<!-- {} -->".format(message.replace("-->", "")
|INFO|console.warn
|
|WARNING|console.error
|
|ERROR+|werkzeug.routing.BuildError
|
Development
git clone https://github.com/nickjj/flask-webpack.git
cd flask-webpack
# having created a fresh virtualenv with a tool of your choice..
source activate flask-webpack
pip install -r requirements.txt
pip install -r devRequirements.txt
pre-push, please run:
flake8 . # check the style
pip install . # check it builds
pyre check # run the static type checker
pytest ./tests/unit.py ./tests/test_app_wp1/tests
pip uninstall flask-webpack
- Nick Janetakis nick.janetakis@gmail.com