H.Solo
H.Solo

Reputation: 79

Webpack Build Speed performance

The Webpack Bulid runs pretty slow, project background is a community portal developed in Vue.js...

Can anybody tell if there is any potential for improvement and if so, what?

I wonder if the time for the build process of 37401ms can still be changed by changing the codebase?

const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const glob = require('glob');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const autoprefixer = require('autoprefixer');

const statsSettings = {
    all: false,
    modules: true,
    maxModules: 0,
    errors: true,
    warnings: false,
    moduleTrace: true,
    errorDetails: true,
    timings: true,
    performance: true,
    builtAt: true,
};

const {
    rootDir,
    srcDir,
    assetsDir,
    stylesDir,
    buildDir,
    sitepackageDir,
    publicPath,
} = require('./config');

const chunks = glob.sync(path.join(rootDir, srcDir, 'pages/**/index.js'))
    .reduce((obj, file) => {
        const name = path.basename(path.dirname(file));
        return {
            ...obj,
            [name]: file,
        };
    }, {});

module.exports = env => {
    return {
        mode: env.production ? 'production' : 'development',
        context: path.join(rootDir, srcDir),
        entry: chunks,
        output: {
            path: path.join(rootDir, buildDir),
            filename: '[name].js',
            publicPath: env.production ? publicPath : '',
        },
        devtool: env.production ? false : 'cheap-module-eval-source-map',
        devServer: {
            contentBase: path.join(rootDir, buildDir),
            inline: true,
            proxy: {
                '/api/v0': 'http://localhost:4000',
            },
        },
        watchOptions: {
            ignored: env.watch ? 'node_modules' : '',
            aggregateTimeout: 300,
        },
        stats: env.watch ? statsSettings : 'normal',
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    include: [
                        path.join(rootDir, srcDir),
                        require.resolve('bootstrap-vue'),
                    ],
                    loader: 'vue-loader',
                },
                {
                    test: /\.js$/,
                    include: [
                        path.join(rootDir, srcDir),
                        require.resolve('bootstrap-vue'),
                    ],
                    loader: 'babel-loader',
                },
                {
                    test: /\.(css|scss)$/,
                    use: [
                        env.production ? MiniCssExtractPlugin.loader : 'vue-style-loader',
                        'css-loader',
                        {
                            loader: 'postcss-loader',
                            options: {
                                plugins: [
                                    autoprefixer({
                                        browsers: ['>1%', 'last 2 versions', 'not ie < 11'],
                                    }),
                                ],
                            },
                        },
                        {
                            loader: 'sass-loader',
                            options: {
                                includePaths: [
                                    path.join(rootDir, srcDir, stylesDir),
                                ],
                            },
                        },
                    ],
                },
                {
                    test: /\.(jpg|jpeg|png|gif|webp|svg|eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$/,
                    loader: 'file-loader',
                    options: {
                        name: `${assetsDir}/_processed_/[name].[hash:4].[ext]`,
                    },
                },
            ],
        },
        optimization: {
            runtimeChunk: {
                name: '_runtime',
            },
            splitChunks: {
                cacheGroups: {
                    // we need to figure out if it's worth having a common chunk
                    // or if each entry chunk should be somewhat self-contained
                    common: {
                        chunks: 'initial',
                        name: '_common',
                        minChunks: 2,
                        minSize: 0,
                    },
                    vendor: {
                        test: /node_modules/,
                        chunks: 'initial',
                        name: '_vendor',
                        enforce: true,
                    },
                },
            },
        },
        resolve: {
            extensions: ['.js', '.json', '.vue'],
            alias: {
                '@app': path.join(rootDir, srcDir),
                // although we're using single file components that can be pre-compiled,
                // we want to dynamically mounting them in the DOM html.
                // this is way we need to alias 'vue' to use the runtime + compiler build here.
                // see: https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
                vue$: 'vue/dist/vue.esm.js',
            },
        },
        plugins: [
            new webpack.DefinePlugin({
                PAGES: JSON.stringify(Object.keys(chunks)),
            }),
            new VueLoaderPlugin(),
            ...plugHtmlTemplates(),
            ...plugExtractCss(env),
            ...plugCopyAssets(),
        ],
    };
};

function plugHtmlTemplates () {
    return glob.sync(path.join(rootDir, srcDir, 'pages/**/template.html'))
        .map(template => {
            const name = path.basename(path.dirname(template));
            return {
                template,
                filename: `${name}.html`,
                chunks: ['_runtime', '_vendor', '_styles', '_common', name],
            };
        })
        .map(htmlConfig => new HtmlWebpackPlugin(htmlConfig));
}

function plugExtractCss (env) {
    if (!env.production) return [];

    return [
        new MiniCssExtractPlugin({
            filename: '[name].css',
            chunkFilename: '[name].css',
        }),
    ];
}

function plugCopyAssets () {
    const assetsSrcPath = path.join(rootDir, srcDir, assetsDir);

    if (!fs.existsSync(assetsSrcPath)) return [];

    return [
        new CopyWebpackPlugin([
            { from: assetsSrcPath, to: path.join(rootDir, buildDir, path.basename(assetsDir)) },
            // this is required for the icons to be selectable in the backend
            { from: path.join(assetsSrcPath, 'icons/'), to: path.join(rootDir, sitepackageDir, 'Resources/Public/Icons/') },
            // this is required for avatars to be available; we must not check them in in fileadmin since they would
            // prevent having the dir linked by Deployer during a deployment
            { from: path.join(rootDir, '../packages/users/Resources/Private/Images/Avatars/'), to: path.join(rootDir, buildDir, 'static/avatars/') },
        ]),
    ];
}

The question is whether you can improve the performance by using different plugins or summarizing steps...

Upvotes: 0

Views: 1756

Answers (1)

Andrey Ravkov
Andrey Ravkov

Reputation: 1494

I have a similar configuration. My configuration built ~33 seconds. I added a cache-loader package and decrease build time to ~17 seconds.

npm install --save-dev cache-loader

config:

rules: [
     //rules here
     {
        test: /\.vue$/,
        use: [
         {
           loader: 'cache-loader',
           options: {}
         },
         {
           loader: 'vue-loader',
           options: vueLoaderConfig
         }
        ],
     },
     {
        test: /\.js$/,
        use: [
        {
          loader: 'cache-loader',
          options: {}
        },
        {
          loader: 'babel-loader'
        }
        ],
         include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      }
]

Upvotes: 1

Related Questions