2

I have big project. I use Pug for building HTML and SASS for styles. My project contains 35 pages with includes and mixins. And other basic things like images, styles and scripts. Initial building in development mode takes 10 minutes. In production - 6 minutes.

I think it's too slow.

How to increase building speed? Is it possible to make Webpack build Pug faster?

Speed Measure log screenshot

Webpack config:

const path = require("path");
const webpack = require("webpack");
const fs = require("fs");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const SpriteLoaderPlugin = require("svg-sprite-loader/plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const DuplicatePackageCheckerPlugin = require("duplicate-package-checker-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const paths = {
  src: path.resolve(__dirname, "src"),
  build: path.resolve(__dirname, "build"),
};

const smp = new SpeedMeasurePlugin();

module.exports = (env, argv) => {
  return smp.wrap({
    entry: {
      index: "./src/index.js",
    },
    output: {
      path: paths.build,
      filename: "[name].[hash].js",
    },
    optimization: {
      minimize: argv.mode !== "development",
      minimizer: [
        new TerserJSPlugin({
          cache: true,
          parallel: true,
        }),
      ],
      splitChunks: {
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/].*\.js$/,
            filename: "vendor.[hash].js",
            chunks: "all",
          },
        },
      },
    },
    resolve: {
      alias: {
        "@": paths.src,
      },
    },
    module: {
      rules: [
        {
          test: require.resolve("jquery"),
          use: [
            {
              loader: "expose-loader",
              options: {
                exposes: ["$", "jQuery"],
              },
            },
          ],
        },
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: [
            {
              loader: "cache-loader",
            },
            {
              loader: "thread-loader",
            },
            {
              loader: "babel-loader",
              options: {
                presets: ["@babel/preset-env"],
              },
            },
          ],
        },
        {
          test: /\.pug$/,
          use: [
            {
              loader: "pug-loader",
              options: {
                pretty: argv.mode !== "development",
              },
            },
          ],
        },
        {
          test: /\.scss$/,
          exclude: /node_modules/,
          use: [
            argv.mode === "development"
              ? {
                  loader: "style-loader",
                }
              : {
                  loader: MiniCssExtractPlugin.loader,
                  options: {
                    publicPath: "../",
                  },
                },
            "css-loader",
            "postcss-loader",
            "fast-sass-loader",
          ],
        },
        {
          test: /\.svg$/,
          include: /icons/,
          use: [
            {
              loader: "svg-sprite-loader",
              options: {
                runtimeCompat: true,
              },
            },
            "svg-transform-loader",
            "svgo-loader",
          ],
        },
        {
          test: /\.(gif|png|jpe?g)$/i,
          include: /ill/,
          use: [
            {
              loader: "responsive-loader",
              options: {
                name: "[name]-[width].[ext]",
                outputPath: "images",
              },
            },
            {
              loader: "image-webpack-loader",
              options: {
                mozjpeg: {
                  progressive: true,
                  quality: 65,
                },
                optipng: {
                  enabled: false,
                },
                pngquant: {
                  quality: [0.8, 1],
                },
                gifsicle: {
                  interlaced: false,
                },
              },
            },
          ],
        },
        {
          test: /\.(svg)$/i,
          include: /ill/,
          use: [
            {
              loader: "file-loader",
              options: {
                name: "[name].[ext]",
                outputPath: "images",
              },
            },
          ],
        },
        {
          test: /\.(eot|ttf|woff|woff2)$/,
          use: [
            {
              loader: "file-loader",
              options: {
                name: "fonts/[name].[ext]",
              },
            },
          ],
        },
        {
          test: /\.(mp4)$/,
          use: [
            {
              loader: "file-loader",
              options: {
                name: "video/[name].[ext]",
              },
            },
          ],
        },
      ],
    },
    plugins: [
      new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery",
        "window.jQuery": "jquery",
      }),
      new MiniCssExtractPlugin({
        filename: "./css/[name].[hash].css",
        chunkFilename: "[name].[hash].css",
      }),
      new SpriteLoaderPlugin({
        plainSprite: true,
      }),
      new CopyWebpackPlugin({
        patterns: [
          {
            from: "static",
            to: "static",
          },
        ],
      }),
      new CleanWebpackPlugin({
        dry: true,
        cleanOnceBeforeBuildPatterns: ["build/*"],
      }),
      new DuplicatePackageCheckerPlugin(),
      ...fs
        .readdirSync(path.resolve(__dirname, "src/template/pages"))
        .filter((fileName) =>
          fileName.endsWith(".pug") && env !== undefined && env.pages.length
            ? env.pages.split(",").includes(fileName)
            : true
        )
        .map(
          (page) =>
            new HtmlWebpackPlugin({
              minify: false,
              template: `${paths.src}/template/pages/${page}`,
              filename: `./${page.replace(/\.pug/, ".html")}`,
            })
        ),
    ],
    devServer: {
      watchOptions: {
        ignored: /node_modules/,
      },
      hot: true,
      port: process.env.PORT,
      overlay: {
        errors: false,
        warnings: false,
      },
    },
  });
};

P.S. Is my stack correct for big project like this?

Thanks in advance for the answers.

Graham
  • 7,431
  • 18
  • 59
  • 84
  • That's a very long time for only 35 pages that are mostly Pug and Sass. I've only used Gulp and Express with Pug though, so I can't help you out with Webpack. – Sean Oct 14 '20 at 15:23
  • Is webpack step is the battle neck? try to profile the battle neck in the webpack compilation using https://webpack.js.org/plugins/profiling-plugin/ You webpack config looks OK (except the usage of `HTMLWebpackPlugin`) which creates child process for each file... – felixmosh Oct 14 '20 at 15:23
  • Looks like you are using `HTMLWebpackPlugin` for transpiling from pug to html, which is not the main purpose of it. – felixmosh Oct 14 '20 at 15:26
  • Thanks for the answers. As I know HTMLWebpackPlugin is the required plugin for transpiling Pug to HTML. I'll try profiling. – dannyfromtheblock Oct 15 '20 at 07:58

0 Answers0