Frontend
Frontend Infrastructure¶
We use Webpack to manage our frontend assets.
Its configuration lives in webpack.config.js
,
which imports files from the webpack/
folder.
To build the development Webpack bundle run npm run webpack:build
.
To watch files
(excluding the Webpack configuration files)
and automatically rebuild the development Webpack bundle when they change,
run npm run webpack:watch
.
To build a production Webpack bundle run npm run webpack:build:prod
.
Webpack puts its build output in the dist/
folder,
which is picked up by Django staticfiles.
Entry points¶
webpack/entrypoints.js
defines each of our entry points,
and the files that should be bundled into them.
For now this is very verbose, as it mirrors the configuration we used in our old Django Pipeline setup. However over time we'll leverage the ability to import libraries directly in the JS files which require them, reducing the number of files we need to list here.
When building a development bundle, we generate sourcemaps to make in-browser debugging easier.
When building a production bundle, we add a hash to the output file names, to allow for cache-busting on staging and production.
Loading in Django¶
We use the HtmlWebpackPlugin to generate HTML files for each of our entry points,
which includes the script tags
(and link tags, explained in the CSS section below)
needed to load the hashed chunks that form each entry point.
This configuration lives in webpack/entrypoints-html.js
.
In Django,
templates can set the scripts
variable to specify which entry points should be loaded for that template.
Loading CSS¶
There is a special entry point screen
which contains all our CSS,
and is treated slightly differently by webpack/entrypoints-html.js
.
Since Webpack is primarily a JS bundler it emits an empty JS file,
which we have no need to include in our site,
so webpack/entrypoints-html.js
ignores it.
Javascript¶
All our JS files are run through Babel, allowing us to use modern JS syntax now, without having to worry whether our users' browsers support it.
Webpack automatically minifies our JS when building the production bundle.
Globals¶
Because most of our JS stack was written well before modules were a thing,
many files place variables in the global scope for other files to use.
However in Webpack,
unless a file explicitly places a variable under window
,
we have to expose each of those variables manually.
This is done in webpack/global-expose-rules.js
.
Like above,
over time we'll leverage imports to reduce the number of variables we have to expose to the global scope.
Stylesheets¶
Our stylesheets are written in Sass,
using its SCSS syntax (.scss
).
We use the MiniCssExtractPlugin to separate our CSS from our JS files.
PostCSS¶
We use the postcss-loader to process our css files with postcss.
Its configuration lives in postcss.config.js
.
When building a production bundle, cssnano minifies our CSS.
Images¶
Images directly imported in JS files, or referenced in CSS files, are copied by Webpack into the build directory, after renaming and optimizing them.
In Django¶
Aside from managing images directly imported in JS and CSS files, we also make use of Webpack to manage images used in Django itself, in Jinja2 templates and Python code.
To do this, we make use of the CopyWebpackPlugin to copy images under certain paths into the build directory, after processing them through the asset pipeline.
We then hook into the Webpack build process,
in webpack/asset-json-plugin.js
,
to generate an original to build path mapping in the dist/source-to-asset.json
file.
We shorten the original path as explained below.
Included images are those:
- under the Protocol icons directory:
node_modules/@mozilla-protocol/core/protocol/img/icons/
, shortened toprotocol/img/icons/
- under the static image directory for any Django app:
kitsune/*/static/**/img/
, shortened to**/img/
In Django,
the webpack_static
helper loads the mapping,
and is used to get an output path for any image needed from those directories.
Optimization¶
In the Webpack pipeline, PNGs are run through optipng, and SVGs are run through svgo.