Usage¶
Webpack integration for Flask.
A simple example¶
Let’s create a basic Flask application inside app.py
. Jinja templates will
reside in the templates
folder and the static files, to be included in the
template, in the instance/static
folder:
from flask import Flask
app = Flask(
__name__,
template_folder='templates',
static_folder='instance/static'
)
Let’s add a template and an asset to our project:
src/
js/
main.js
templates/
index.html
app.py
The asset will be a simple javascript file:
import $ from 'jquery'
$(document).ready(function(){
$("#msg").html("I am webpacked.");
});
The content of the index.html
we will define later.
To build our asset, let’s create the Webpack configuration in
src/webpack.config.js
:
var path = require('path');
var config = require('./config');
var ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
context: config.build.context,
entry: {
app: "./js/main.js",
},
output: {
path: config.build.assetsPath,
filename: 'js/[name].[chunkhash].js',
publicPath: config.build.assetsURL
},
plugins: [
new ManifestPlugin({
fileName: 'manifest.json',
stripSrc: true,
publicPath: config.build.assetsURL
})
]
}
You might have noticed that an import of a file which we did not create has
been added, config.js
. This is because this file is generated by
Flask-WebpackExt when we run the flask webpack create
command and it will
contain the following information:
{
"build": {
// Absolute path to the directory where Webpack outputs files
// will be written to.
"assetsPath": "/private/tmp/testproject/instance/static/dist",
// URL to access the built assets.
"assetsURL": "/static/dist/",
// Absolute path to the generated assets directory.
"context": "/private/tmp/testproject/instance/assets",
// Boolean which represents if Flask debug is on.
"debug": false,
// Absolute path to the generated static directory.
"staticPath": "/private/tmp/testproject/instance/static",
// URL to access the static files.
"staticURL": "/static/"
}
}
This is really important since it is Flask, and only Flask, who knows where the application path for assets is, so through this configuration we tell Webpack where to move the bundles.
Also, we will need a package.json
for the npm dependencies, with a run
script build
that executes webpack, in src/package.json
and will be
triggered by flask webpack build
:
{
"private": true,
"name": "example",
"version": "0.0.1",
"author": "myself",
"license": "WTFPL",
"description": "example",
"scripts": {
"build": "webpack --config webpack.config.js"
},
"dependencies": {
"jquery": "^3.2.1"
},
"devDependencies": {
"webpack-manifest-plugin": "^2.0.4"
}
}
We can now define, in app.py
a WebpackTemplateProject
to
integrate Webpack with our Flask application and build our assets:
from flask_webpackext.project import WebpackTemplateProject
from flask_webpackext import FlaskWebpackExt
project = WebpackTemplateProject(
__name__,
project_folder='src',
config_path='config.json',
)
app.config.update(dict(
WEBPACKEXT_PROJECT=project,
))
# Initialize extension
FlaskWebpackExt(app)
Since Flask-WebpackExt creates a new template global function called
webpack
to inject the assets in templates, we can use it to include the
assets in our template index.html
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div id="msg"></div>
{{ webpack['app.js'] }}
</body>
</html>
Finally, we will expose our template through a Flask view:
from flask import render_template
@app.route('/')
def index():
return render_template('index.html')
At this point we are ready to build the assets:
$ flask webpack buildall
The command will copy all files from the src folder to the application instance folder designated for the Webpack project, download the npm packages and run Webpack to build our assets.
Alternatively, we can execute each build step separately. To copy all sources to the working directory:
$ flask webpack create
To run npm install command and download all dependencies:
$ flask webpack install
To run npm run build and execute what you have defined in the package.json:
$ flask webpack build
Now you can run the application and see if the assets are loaded:
$ export FLASK_APP=app.py
$ flask run
$ firefox http://127.0.0.1:5000/
Assets for multiple Flask modules¶
When working with large applications, assets are usually split in different modules. Flask-WebpackExt uses pywebpack which allows to solve this problem by using:
WebpackBundle
to declare the needed assets and npm dependencies for each module.WebpackBundleProject
to gather all bundles under one Webpack project.
An example project with two modules could be structured as follows:
buildconfig/
package.json
webpack.config.js
modules/
module1/
js/
css/
module2/
js/
css/
templates/
index.html
app.py
Let’s start with the definition of the first bundle bundle1
. bundle2
would be similar:
from flask_webpackext import WebpackBundle
bundle1 = WebpackBundle(
__name__,
'./modules/module1/static',
entry={
'module1-app': './js/module1-app.js',
},
dependencies={
'jquery': '^3.2.1'
}
)
We now define a WebpackBundleProject
to put together all the
bundles and integrate with Flask:
from module1 import bundle1
from module2 import bundle2
from flask_webpackext import WebpackBundleProject
myproject = WebpackBundleProject(
__name__,
project_folder='assets',
config_path='src/config.json',
bundles=[bundle1, bundle2],
)
app.config.update(dict(
WEBPACKEXT_PROJECT=myproject,
))
# ...
At this point, we can create the application and config.json
will be
generated. The main difference with the previous config.json
is that
Flask-WebpackExt now knows about the bundles, and it will add them under the
key entry
:
{
"build": {...},
"entry": {
"module1": "./js/module1.js",
"module2": "./js/module2.js"
}
}
Because entries are now included in the config.json
, we can dynamically
load them into webpack.config.js
:
var config = require('./config')
module.exports = {
context: config.build.context,
entry: config.entry,
...
};
Manifest¶
Flask-WebpackExt can load the manifest.json
created by webpack when
building the assets. You have to add the plugin in the webpack.config.js
to generate it:
...
var ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
...
plugins: [
new ManifestPlugin({
fileName: 'manifest.json',
stripSrc: true,
publicPath: config.build.assetsURL
})
]
};
The generated manifest.json
will look like :
{
"module1.js": "/static/dist/js/module1.4adb22699eb1a5698794.js",
"module2.js": "/static/dist/js/module2.85e58794420201dc1426.js"
}
By default, Flask-WebpackExt will look for the manifest file in WEBPACKEXT_MANIFEST_PATH config variable, and if it exists, it will load the file and make it available inside Jinja templates.
The injected asset in the generated html template will look similar to this:
<script src="/static/dist/mymodule-app.8817a9d4faccbc712aa7.js"></script>
You can read more about it on pywebpack documentation.