Using Webpack and npm with Hugo

Hugo tries hard to draw boundaries between what it does and what other programs should do. While Hugo can minify, concatenate, and fingerprint JavaScript files, it doesn’t have support for more advanced JavaScript development, like import statements and transpilation.

Webpack is one of the most popular tools for managing and building front-end applications. It’s powered by Node.js, and as a result, you’ll be able to use npm, the package manager for Node.js, to manage all of the dependencies for your project, including Lunr, Axios, and Webpack. You’ll also be able to use npm to create a more automated way of building your site.

To get started, create a package.json file. This file lets you track JavaScript dependencies and define tasks to build your site. You can create this file with the npm init command and fill in the details, but it’s quicker to create the file manually. First, stop your Hugo server with Ctrl-c.

Create the package.json file in the root of your Hugo project and add the following JSON content to the file:

 {
 "name"​: ​"portfolio"​,
 "version"​: ​"1.0.0"​,
 "description"​: ​"My portfolio"​,
 "private"​: ​true​,
 "scripts"​: {
 "build"​: ​"hugo --cleanDestinationDir"
  }
 }

This specifies the name of the project, the version, and a brief description. The "private": true line ensures you can’t accidentally publish your code to a package repository. The "scripts” section lets you specify scripts you’d like to run. This defines a build command that runs Hugo with the --cleanDestinationDir argument, so the public directory is always cleared out.

Save the file, exit your editor, and use npm to build the site. Prefix the name of the script with run, like this:

 $ ​​npm​​ ​​run​​ ​​build

The site builds just like it did before, but now you don’t have to remember to add the --cleanDestinationDir option—and you can add additional configuration options here as well.

Add another script that runs the development server with the --disableFastRender option so that nothing gets cached. Be sure to add a comma to the end of the line with the build task or your JSON file won’t be valid:

 "build"​: ​"hugo --cleanDestinationDir"​,
 "hugo-server"​: ​"hugo server --disableFastRender"

Save the file and run the development server:

 $ ​​npm​​ ​​run​​ ​​hugo-server

The server starts up. Press Ctrl-c to stop the server.

Now, let’s get Webpack working. Add Webpack and its CLI as development dependencies:

 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​webpack​​ ​​webpack-cli

While you’re installing dependencies, install Lunr and Axios as project dependencies as well. Use the --save flag instead of --save-dev as these are dependencies you’ll need for production, not just for development purposes:

 $ ​​npm​​ ​​install​​ ​​--save​​ ​​axios​​ ​​lunr

You can now remove the themes/basic/assets/js/lunr.js and themes/basic/assets/js/axios.js files from your project:

 $ ​​rm​​ ​​themes/basic/assets/js/lunr.js
 $ ​​rm​​ ​​themes/basic/assets/js/axios.js

Webpack can use a configuration file that lets you define how it should build your project. Create a webpack.config.js file in the root of your Hugo site. Add this code which looks for an index.js file in themes/basic/assets/js and generates the output in themes/basic/assets/js/app.js:

 const​ path = require(​'path'​);
 
 module.exports = {
  entry: ​'./themes/basic/assets/js/index.js'​,
  output: {
  filename: ​'app.js'​,
  path: path.resolve(__dirname, ​'themes'​,​'basic'​,​'assets'​, ​'js'​)
  }
 };

By putting the resulting file in the assets folder, you can still use Hugo’s minifier and fingerprinter. If, however, you plan to use other Webpack plugins to do this work, place the output in static/js instead. Hugo will still see it and use it. Just be sure to modify the path where Hugo looks for the file in your search.html template.

Next, move themes/basic/assets/search.js to themes/basic/assets/js/index.js. This file will now become the entrypoint for Webpack:

 $ ​​mv​​ ​​themes/basic/assets/js/search.js​​ ​​themes/basic/assets/js/index.js

Open the file and import Axios and Lunr at the top of the file:

 'use strict'
 
»import​ axios ​from​ ​'axios'​;
»import​ lunr ​from​ ​'lunr'​;

Now integrate the file that Webpack will generate into your layout. Open themes/basic/layouts/_default/search.html and remove these lines, since Webpack is now loading and assembling the files:

 {{ $lunr := resources.Get "js/lunr.js" }}
 {{ $axios := resources.Get "js/axios.js" }}
 {{ $search := resources.Get "js/search.js" }}
 {{ $libs := slice $lunr $axios $search }}

Then modify the $js line so it only pulls in the app.js file that Webpack will generate:

 {{ $js := resources.Get "js/app.js" | minify | fingerprint }}
 <script src=​"{{ $js.RelPermalink }}"​></script>

Save the file.

You’ll need to run Webpack to build the app.js file before you run the Hugo server. If you don’t do this, Hugo will fail to build the site because it won’t be able to find the app.js file in the assets folder.

Webpack is installed as a dependency of this project, rather than installed globally. To run it, you’d have to run the command node node_modules/webpack/bin/webpack.js. But since that’s a lot to type, you can use the scripts section of package.json to create a shorter commmand.

Open the package.json file and locate the scripts section. As you learned earlier, this section lets you define scripts you want to run. You already have a build command which builds the site with Hugo. Add a new webpack command which runs webpack:

 "scripts"​: {
 "build"​: ​"hugo --cleanDestinationDir"​,
 "hugo-server"​: ​"hugo server --disableFastRender"​,
 "webpack"​: ​"webpack"
  }

Be sure to add a comma to the end of the hugo-server line so that your JSON is valid.

Since you’ve added Webpack as a dependency of your project, you can use it in the scripts section without needing to specify its path.

You can now run npm run webpack to build the app.js file:

 $ ​​npm​​ ​​run​​ ​​webpack
 >​​ ​​[email protected]​​ ​​webpack​​ ​​/Users/brianhogan/portfolio
 >​​ ​​webpack
 
 Hash: dbc9c6b673dd8cde7dd0
 Version: webpack 4.41.2
 Time: 315ms
 Built at: 01/02/2020 8:45:15 PM
  Asset Size Chunks Chunk Names
 app.js 45.6 KiB 0 [emitted] main
 Entrypoint main = app.js
 [11] ./themes/basic/assets/js/index.js 1.42 KiB {0} [built]
  + 28 hidden modules

Once Webpack completes, you can build the site or start the development server.

Hugo’s development server watches files for changes, but it can’t trigger external build tools like Webpack. You have two options at your disposal. The first option is to use two terminal windows. Have Hugo’s server running in one window and run Webpack in the other window using its watch option. Add a new script to your package.json file named webpack-watch:

 "scripts"​: {
 "build"​: ​"hugo --cleanDestinationDir"​,
 "hugo-server"​: ​"hugo server --disableFastRender"​,
 "webpack"​: ​"webpack"​,
 "webpack-watch"​: ​"webpack --watch"​,
 },

Open a new terminal window and navigate to your project directory. Run npm run webpack-watch and it’ll run, waiting for any changes to your files. When it sees changes, it will generate the new file. The Hugo dev server will then see the app.js file change, which will trigger a rebuild of the Hugo site.

Juggling two terminal windows isn’t ideal, so you can create task that runs both servers in parallel using a single command. To do that, install the npm-run-all module, which lets you run multiple tasks in serial or parallel on all operating systems.

Install the module as a development dependency:

 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​npm-run-all

Then create a new task called dev which runs Webpack and Hugo’s servers:

 "scripts"​: {
 "build"​: ​"hugo --cleanDestinationDir"​,
 "hugo-server"​: ​"hugo server --disableFastRender"​,
 "webpack"​: ​"webpack"​,
 "webpack-watch"​: ​"webpack --watch"​,
 "dev"​: ​"npm-run-all webpack --parallel webpack-watch hugo-server"
 },

This new dev task runs Webpack by itself first to ensure that the app.js file is created. It then runs the webpack-watch and hugo-server tasks you defined.

Finally, the build task currently just builds the site with Hugo. Rename that task to hugo-build and add a new build task that runs Webpack and Hugo sequentially:

 "build"​: ​"npm-run-all webpack hugo-build"​,
 "hugo-build"​: ​"hugo --cleanDestinationDir"​,

You now have an integrated solution for using Webpack and Hugo together, as well as a build system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.154.171