javascriptnode.jsnpmwebpackpug-loader

Can Webpack build multiple HTML files from SCSS and Pug?


I've read quite a few tutorials on webpack, but it seems more for creating web apps then for what I'm trying to do so I didn't want to waste any more time if the following isn't possible.

I'm creating websites on a third-party eCommerce system and they have a system of coding out templates that can be used to change the structure of their website. Below is an example of one of their templates I would be creating (although there are many types & variations I will need to make, not just a few).

My idea to streamline the creation of these templates is to create a bunch of pug components and place them in the components/ directory. Outside of the components directory I want to make higher level pug templates that utilize the components. Once these have been created, I would build it with NPM and the template files need to be converted to HTML and placed within the /dist folder.

Is this hard to do with webpack?

Structure of the project:

src/
..components/
....header/
......header1.pug
......header1.scss
..navcustom-template.pug
..customfooter-template.pug
..non-template-specific.scss

and once built:

dist/
..navcustom-template.html
..customfooter-template.html
..non-template-specific.css

src/
..components/
....header/
......header1.pug
......header1.scss
..navcustom-template.pug
..customfooter-template.pug
..non-template-specific.scss

Sample of a template:

<!--
    Section: NavCustom
-->

<style>

    //Template Speific CSS Imports Here

</style>
<script type="text/javascript">

    //Template Speific JS Imports Here

</script>
<header>

    <div class="col-md-4">

        // Social Media Code

    </div>

    <div class="col-md-4">

        // Logo Code

    </div>

    <div class="col-md-4">

        //  Call to Action Code

    </div>

</header>
<nav>

</nav>

Solution

  • You can use these packages (--save-dev for all):

    Then configure Webpack similar to the following, where index.js is a dummy file you should create if you don't already have an entry. Each Pug template you need to process is written in a separate HtmlWebpackPlugin object at the bottom.

    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var HtmlWebpackPugPlugin = require('html-webpack-pug-plugin');
    
    module.exports = {
      entry: ['./src/index.js'],
      output: {
        path: __dirname + '/dist',
        publicPath: '/'
      },
      module: {
        rules: [
          {
            test: /\.pug$/,
            use: [
              "raw-loader",
              "pug-html-loader"
            ]
          }
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: 'src/navcustom-template.pug',
          filename: 'navcustom-template.html'
        }),
        new HtmlWebpackPlugin({
          template: 'src/customfooter-template.pug',
          filename: 'customfooter-template.html'
        }),
        new HtmlWebpackPugPlugin()
      ]
    }
    

    All Pug mixins (your src/components files) will be included in the output. This example is tested and working.


    Edit: To dynamically process all Pug files in the src directory use this config:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const HtmlWebpackPugPlugin = require('html-webpack-pug-plugin');
    const fs = require('fs');
    
    let templates = [];
    let dir = 'src';
    let files = fs.readdirSync(dir);
    
    files.forEach(file => {
      if (file.match(/\.pug$/)) {
        let filename = file.substring(0, file.length - 4);
        templates.push(
          new HtmlWebpackPlugin({
            template: dir + '/' + filename + '.pug',
            filename: filename + '.html'
          })
        );
      }
    });
    
    module.exports = {
      entry: ['./src/index.js'],
      output: {
        path: __dirname + '/dist',
        publicPath: '/'
      },
      module: {
        rules: [
          {
            test: /\.pug$/,
            use: [
              "raw-loader",
              "pug-html-loader"
            ]
          }
        ]
      },
      plugins: [
        ...templates,
        new HtmlWebpackPugPlugin()
      ]
    }
    

    This uses fs.readdirSync to get all Pug files in a directory. The synchronous version is used (as opposed to fs.readdir) because the module.exports function will return before the files are processed.