D
D
dannyfromtheblock2020-10-14 17:38:41
Building projects
dannyfromtheblock, 2020-10-14 17:38:41

How to increase the build speed of a multi-page project (Webpack, Sass, Pug)?

The layout of a large project.
Pug and Sass (SCSS) were chosen for implementation.
35 pages. Includes and mixins are actively used.
Otherwise, everything is normal - styles, pictures (moderate amount), scripts.

The initial build (run) in development mode takes ~10 minutes. In production mode - ~ 6 minutes.

Even if you collect 1 page in development mode , it still takes a lot of time - ~ 6 minutes .

  1. How can I increase the build speed of my project?
  2. Is such a stack used for multi-page projects at all?


Screenshot of the Speed ​​Measure plugin log when building a project with all pages:
5f8709a263242944063361.png

I tried to build without pug-files and the speed of other loaders immediately increased. Pug slows everything down. I also tried without style-loader (which allows you to update styles without reloading), but alas.

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,
      },
    },
  });
};

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question