How to increase building speed (Webpack, Pug, SCSS)?

1.1k Views Asked by At

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.

0

There are 0 best solutions below