less / less/less.js

Out of memory when trying to bundle AdminLTE and Bootstrap

Open
#3,627 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

research needed
Dominant language
JavaScript
Stars
17k
Forks
3.4k
Avg merge
7h 42m
Merged PRs (30d)
26

Description

I'm trying to bundle admin-lte@2.4.18 and bootstrap@3.4.1 with less@4.1.1 via webpack@5.39.0.

My webpack.config.js looks like this:

const path = require('path');

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { VueLoaderPlugin } = require('vue-loader');

module.exports = (env, argv) => {
    const distPath = path.resolve('dist');
    const srcPath = path.resolve('src');

    const config = {
        entry: {
            'bundle': path.join(srcPath, 'js/index.js'),
        },
        output: {
            chunkFilename: 'assets/[name].js',
            filename: '[name].js',
            path: distPath
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    exclude: /(node_modules|bower_components)/,
                    use: 'vue-loader',
                },
                {
                    test: /\.js$/,
                    exclude: /(node_modules|bower_components)/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            plugins: [
                                "@babel/plugin-syntax-dynamic-import",
                                "@babel/plugin-syntax-object-rest-spread",
                            ],
                            presets: [
                                '@babel/preset-env',
                            ],
                            compact: false,
                        }
                    }
                },
                {
                    test: /\.css$/,
                    exclude: /(node_modules|bower_components)/,
                    oneOf: [
                        // this matches `<style module>`
                        {
                            resourceQuery: /module/,
                            use: [
                                MiniCssExtractPlugin.loader,
                                {
                                    loader: 'css-loader',
                                    options: {
                                        modules: true,
                                        localIdentName: '[local]_[hash:base64:5]'
                                    }
                                }
                            ]
                        },
                        // this matches plain `<style>` or `<style scoped>`
                        {
                            use: [
                                MiniCssExtractPlugin.loader,
                                'css-loader'
                            ]
                        }
                    ]
                },
                {
                    test: /\.less$/,
                    exclude: /(node_modules|bower_components)/,
                    oneOf: [
                        // this matches `<style module>`
                        {
                            resourceQuery: /module/,
                            use: [
                                MiniCssExtractPlugin.loader,
                                {
                                    loader: 'css-loader',
                                    options: {
                                        modules: true,
                                        localIdentName: '[local]_[hash:base64:5]'
                                    },
                                },
                                'less-loader',
                            ]
                        },
                        // this matches plain `<style>` or `<style scoped>`
                        {
                            use: [
                                MiniCssExtractPlugin.loader,
                                'css-loader',
                                'less-loader',
                            ]
                        }
                    ]
                },
                {
                    test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/,
                    use: "file-loader"
                }
            ]
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: 'bundle.css',
            }),
            new VueLoaderPlugin(),
        ],
        resolve: {
            alias: {
                'vue$': 'vue/dist/vue.esm.js',
            }
        },
    };
    
    return config;
};

and my main.less like this:

@import "~bootstrap/less/bootstrap.less";
@import "~admin-lte/build/less/AdminLTE.less";

When I try to build my project I get:

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 00007FF704A3285F napi_wrap+119263
 2: 00007FF7049D9526 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NextTableOffset+38102
 3: 00007FF7049DA326 node::OnFatalError+438
 4: 00007FF705217AAE v8::Isolate::ReportExternalAllocationLimitReached+94     
 5: 00007FF7051FFC61 v8::SharedArrayBuffer::Externalize+833
 6: 00007FF7050B143C v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1436
 7: 00007FF7050BC680 v8::internal::Heap::ProtectUnprotectedMemoryChunks+1312  
 8: 00007FF7050B9194 v8::internal::Heap::PageFlagsAreConsistent+3204
 9: 00007FF7050AE993 v8::internal::Heap::CollectGarbage+1283
10: 00007FF7050AD004 v8::internal::Heap::AddRetainedMap+2500
11: 00007FF7050CE48B v8::internal::Factory::NewFixedArrayWithFiller+107
12: 00007FF7050C7317 v8::internal::Factory::InternalizeString<unsigned short>+471
13: 00007FF704F1DD3A v8::internal::HashTable<v8::internal::NumberDictionary,v8::internal::NumberDictionaryShape>::New+122
14: 00007FF7051CA05E v8::internal::Builtins::builtin_handle+317374
15: 00007FF7051C54D8 v8::internal::Builtins::builtin_handle+298040
16: 00007FF7051C503E v8::internal::Builtins::builtin_handle+296862
17: 00007FF70566CD5D v8::internal::SetupIsolateDelegate::SetupHeap+547181
18: 000001C9E13154E6

There doesn't seem to be any way of debugging this. But what I managed to figure out is that LESS seems to get stuck in an endless loop in ~bootstrap/less/mixins/grid-framework.less. This mixin seems to be the culprit:

.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
  .calc-grid-column(@index, @class, @type);
  // next iteration
  .loop-grid-columns((@index - 1), @class, @type);
}

which is weird because of it having a when -guard operator.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the build described in webpack.config.js with main.less importing Bootstrap and AdminLTE. Inspect bootstrap/less/mixins/grid-framework.less, especially the guarded recursive .loop-grid-columns mixin, and trace how the Less compiler handles it. Done means the same imports build without exhausting the JavaScript heap.

Written by the indexing model from the issue text.

Assessment

Tech stack
bootstrap, javascript, webpack
Domain
build-system, compilers, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.