Terser: prefix all mangled variables and functions
Asked Answered
G

2

6

I'm working on a single-file script that is meant to be included on pages through a <script> tag, it's being built with Vite.js using the Terser minifier.

After making changes I noticed that the built version of my script was suddenly throwing errors whenever I called Google Analytics code.

After doing some digging, I noticed one of the other packages on a site I was including the script on was calling a function called ga(). The error is happening because Terser is minifying/mangling a function in my script and naming it ga(), which then conflicts with this other function I have no control over.

I assumed Terser would have an option to either

  • not mangle to a specific name
  • prefix all mangled functions

But it doesn't seem to have either.

I've managed to fix the problem by adding the following to my config:

    minify: "terser",
    terserOptions: {
      keep_fnames: true,
    },

Which stops Terser from mangling ANY function names, but obviously this isn't great as it's wasting a ton of potential for minification.

Is there any way to tell Terser to still mangle all functions, but to do so while also prefixing it with a_ for example?

Gilboa answered 3/10, 2021 at 18:5 Comment(0)
M
1

You can use the mangle.nth_identifier to generate names yourself from scratch, and include the prefix in those names. Using this code and base54Prefix(prefix) for mangle.nth_identifier should work.

// adapted from base54 https://github.com/terser/terser/blob/master/lib/scope.js
const base54Prefix = ((prefix) => {
    const leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
    const digits = "0123456789".split("");
    let chars;
    let frequency;
    function reset() {
        frequency = new Map();
        leading.forEach(function(ch) {
            frequency.set(ch, 0);
        });
        digits.forEach(function(ch) {
            frequency.set(ch, 0);
        });
    }
    function consider(str, delta) {
        for (var i = str.length; --i >= 0;) {
            frequency.set(str[i], frequency.get(str[i]) + delta);
        }
    }
    function compare(a, b) {
        return frequency.get(b) - frequency.get(a);
    }
    function sort() {
        chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
    }
    // Ensure this is in a usable initial state.
    reset();
    sort();
    function base54(num) {
        var ret = "", base = 54;
        num++;
        do {
            num--;
            ret += chars[num % base];
            num = Math.floor(num / base);
            base = 64;
        } while (num > 0);
        return prefix + ret;
    }

    return {
        get: base54,
        consider,
        reset,
        sort
    };
});

function mergeSort(array, cmp) {
    if (array.length < 2) return array.slice();
    function merge(a, b) {
        var r = [], ai = 0, bi = 0, i = 0;
        while (ai < a.length && bi < b.length) {
            cmp(a[ai], b[bi]) <= 0
                ? r[i++] = a[ai++]
                : r[i++] = b[bi++];
        }
        if (ai < a.length) r.push.apply(r, a.slice(ai));
        if (bi < b.length) r.push.apply(r, b.slice(bi));
        return r;
    }
    function _ms(a) {
        if (a.length <= 1)
            return a;
        var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
        left = _ms(left);
        right = _ms(right);
        return merge(left, right);
    }
    return _ms(array);
}

Milone answered 29/9, 2024 at 18:46 Comment(0)
M
-1

Yes you can do it with regex, You can check this post or go to mangle.properties for complete documentation.

terserOptions: {
    mangle: {
        properties: {
            regex: /(^P1|^p1|^_p1)[A-Z]\w*/
        }
    }
}
Magallanes answered 3/10, 2021 at 19:42 Comment(3)
This allows me to specify which functions I don't want mangled in terser, but it doesn't help with stopping a function from being named ga(), which is the problem I'm having.Gilboa
Did you find a fix? I stumbled upon the same issue...Lunatic
No solution unfortunatelyGilboa

© 2022 - 2025 — McMap. All rights reserved.