Let’s see how to configure webpack to manage general assets, for example, text and pdf files. We’ll see how to configure webpack to dynamically generate URLs for these files. As an application, we’ll show how to add download links to these resources.
Project structure and setup
Our project will have the following folder structure:
. ├── build ├── index.html ├── package.json ├── package-lock.json ├── src │ ├── assets │ │ ├── file.pdf │ │ └── file.txt │ └── index.js └── webpack.config.js
First, we initialize an npm project. From the project root folder:
$ npm init -y
Then, we add the dependencies we’ll need:
$ npm install -D webpack webpack-cli html-webpack-plugin
index.html
will be our main HTML page. Its body tag content will consist of the following anchor tags:
<!-- index.html --> <body> <a id="pdf-file" target="_blank">Download PDF</a> <br /> <a id="txt-file" target="_blank">Download TXT</a> </body>
These will be used as links to download file.pdf
and file.txt
.
Next, let’s see the required webpack configuration to add links to these files to the HTML file.
Basic webpack configuration
Webpack takes its configuration from webpack.config.js
. Let’s add the minimal configuration to process HTML files and asset files (pdf, txt, etc).
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry: { index: "./src/index.js", }, output: { filename: "[name].js", path: path.resolve(__dirname, "build"), assetModuleFilename: "assets/[name][ext]", clean: true, }, mode: "development", plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "index.html"), filename: "index.html", chunks: ["index"], }), ], module: { rules: [ { test: /\.(pdf|txt)$/, include: path.resolve(__dirname, "src"), type: "asset/resource", generator: { filename: "assets/[name][ext]", }, }, ], }, };
With this configuration, we area defining a single entry point (src/index.js
), which is in turn linked to index.html
using the webpack-html-plugin (see webpack configuration for multiple entry points).
Besides HTML and JavaScript files, we define special rules for pdf
and txt
files. These will be all loaded with webpack’s built-in asset modules, in particular with asset/resource
. Note that these modules are present only in webpack 5.
Let’s study the configuration options that are specific to assets.
First, we set a directory to store these files. This is done with the output.assetModuleFilenames
property. Note that this path is relative to our main output path (build/
, in this case).
assetModuleFilename: "assets/[name][ext]"
The special [name]
and [ext]
placeholders will be replaced by the name and extension of each file. For example, loading file1.txt
to our project will copy it to build/assets/file1.txt
. The resulting URL address once uploaded to a server would be: mywebsite.com/assets/file1.txt
.
Processing these files is done by the asset/resource
module following this rule:
module: { rules: [ { test: /\.(pdf|txt)$/, include: path.resolve(__dirname, "src"), type: "asset/resource", }, ], }
Both pdf
and txt
files (we could add other file extensions, too) will match and be processed by asset/resource
. It will copy the matching files to the specified output and replace all references to these files in our source code with their corresponding relative URL path.
With this configuration, let’s see how to add references to our assets.
Adding asset files using scripts
First, let’s add assets using JavaScript.
Remember that we configured index.js
to be linked to index.html
.
// index.js import PDF from "./assets/file.pdf"; import TXT from "./assets/file.txt"; // const PDF = require("./assets/file.pdf"); // const TXT = require("./assets/file.txt"); document.getElementById("pdf-file").href = PDF; document.getElementById("txt-file").href = TXT;
See that this script imports the assets from src/assets
just like any other JavaScript module. We can use these import references as we would with any variable. Once webpack processes our source code, it will replace these references with the correct relative URLs, following our specified configuration.
We can test this by bundling the files. Either define an npm script that runs webpack
or run the following:
$ npx webpack
It will write the output files to build/
. First, we notice that the assets have been copied to build/assets
.
build/ ├── assets │ ├── file.pdf │ └── file.txt ├── index.html └── index.js
If we open build/index.html
with a web browser, we’ll see the anchor tag references have been changed to the corresponding URL paths of the assets!
Adding asset files directly to HTML files
Using scripts to load assets is completely functional and it’s the approach we would use with frameworks like React. However, we can also load assets dynamically without using scripts at all. To do so, we’ll need an HTML processor. We’ll use pug for this demo, but any processor would do.
First, we need to configure webpack to process pug files. We’ll use simple-pug-loader
, which works better with webpack 5.
We install the module.
$ npm i -D simple-pug-loader
And then we a add the following configuration to webpack.config.js
:
// webpack.config.js ... module.exports = { ... plugins: [ ... new HtmlWebpackPlugin({ template: path.resolve(__dirname, "pugindex.pug"), filename: "pugindex.html", }), ], module: { rules: [ ... { test: /\.pug$/, include: path.resolve(__dirname), use: [ { loader: "simple-pug-loader", }, ], }, ], }, };
The two single changes were: 1) configuring the html-webpack-plugin
to process pugindex.pug
and generate pugindex.html
, 2) adding a new rule to process all .pug
files with simple-pug-loader
.
With this new configuration, let’s create pugindex.pug
at the root folder:
// pugindex.pug doctype html html(lang="en") head meta(charset="UTF-8") meta(http-equiv="X-UA-Compatible", content="IE=edge") meta(name="viewport", content="width=device-width, initial-scale=1.0") title Webpack Files body p Hello world!
Let’s build the files to see it all works.
Adding dynamic file references to pug
Finally, we can add references in pug to asset files as follows:
// pugindex.pug ... body a(href=require("./src/assets/file.pdf") target="_blank") Download pdf br a(href=require("./src/assets/file.txt") target="_blank") Download txt
We add the references with the NodeJS require
keyword used to load modules. We pass to it the path of the asset relative to the pug file. With the webpack configuration of the previous sections, these references will be processed to add relative URLs to the locations these files will be copied to after bundling by wepback!
One of the advantages of this method is that we don’t need to manually keep track of the assets and copy them to our public folder. We can load assets from any path and webpack will process all of these references to the desired folder structure for our webpage.
Super helpful. Thank you!