Rich-Harris / butternut

The fast, future-friendly minifier
https://butternut.now.sh
MIT License
1.17k stars 17 forks source link

Error in squash minified bundle, malformed minification. #198

Open backspaces opened 6 years ago

backspaces commented 6 years ago

I have a repo, https://github.com/backspaces/as-app3d, using squash to minify Rollup bundles. Using the minified bundle fails with a browser error. The minified bundle is mal-formed.

In the example I give below, the minified/squashed version fails with:

Uncaught ReferenceError: e3 is not defined

To reproduce:

mkdir test; cd test curl http://backspaces.net/temp/docs.zip > foo.zip (made for this issue) unzip foo.zip (or just clone the repo, and use the docs (github page) for the rest below)

In a browser (chrome for me): open localhost page test/docs/models/helloesm.html for my test: http://localhost/home/Downloads/test/docs/models/helloesm.html result: runs fine

edit docs/models/helloesm.html: '../dist/as-app3d.esm.js' > '../dist/as-app3d.esm.min.js' (minified with squash) run url above: console: Uncaught ReferenceError: e3 is not defined

To test with uglify-es:

uglifyjs docs/dist/as-app3d.esm.js > docs/dist/as-app3d.esm.ugly.js edit helloesm.html: as-app3d.esm.min.js > as-app3d.esm.ugly.js run url as above

runs fine

The files involved

-rw-r--r-- 1 owen staff 178K Sep 7 15:10 as-app3d.esm.js -rw-r--r-- 1 owen staff 57K Sep 7 15:10 as-app3d.esm.min.js -rw-r--r-- 1 owen staff 71K Oct 30 21:50 as-app3d.esm.ugly.js

The file size difference might suggest a failure.

backspaces commented 6 years ago

Here's the specific minified segment that fails:

Uncaught ReferenceError: e3 is not defined ...for(let e=0;e<n.length;e=e3){...

There is no other use of e3 in the file, so not a global.

Here it is prettier-ized

update(e) {
    let t = this.mesh,
        { vertices: n, indices: r } = this.unitQuad,
        o = 1,
        i = t.geometry.getAttribute('position'),
        a = t.geometry.getAttribute('uv'),
        s = t.geometry.getIndex(),
        u = new Float32Array(n.length * e.length),
        c = [],
        l = []
    for (let t = 0; t < e.length; t++) {
        let i = e[t]
        i.sprite || i.setSprite()
        let a = i.size,
            s = i.theta,
            d = Math.cos(s),
            f = Math.sin(s),
            h = t * n.length
        for (let e = 0; e < n.length; e = e3) { <<<<
            let t = n[e],
                r = n[e + 1],
                s = i.x,
                c = i.y
            u[e + h] = (a * (t * d - r * f) + s) * o
            u[e + h + 1] = (a * (t * f + r * d) + c) * o
            u[e + h + 2] = i.z * o
        }
        l.push(...r.map(e => e + t * 4))
        c.push(...i.sprite.uvs)
    }
    i.setArray(u)
    i.needsUpdate = !0
    a.setArray(new Float32Array(c))
    a.needsUpdate = !0
    s.setArray(new Uint32Array(l))
    s.needsUpdate = !0
}

And here is the initial code:

update(turtles) {
    const mesh = this.mesh;
    const { vertices, indices } = this.unitQuad;
    // const patchSize = this.model.world.patchSize
    const patchSize = 1; // REMIND
    const positionAttrib = mesh.geometry.getAttribute('position');
    const uvAttrib = mesh.geometry.getAttribute('uv');
    const indexAttrib = mesh.geometry.getIndex();
    const positions = new Float32Array(vertices.length * turtles.length);
    const uvs = [];
    const indexes = [];

    for (let i = 0; i < turtles.length; i++) {
        const turtle = turtles[i];
        // if (turtle.sprite.needsUpdate) turtle.setSprite()
        if (!turtle.sprite) turtle.setSprite();
        const size = turtle.size; // * patchSize
        const theta = turtle.theta;
        const cos = Math.cos(theta);
        const sin = Math.sin(theta);
        const offset = i * vertices.length;

        for (let j = 0; j < vertices.length; j = j + 3) {   <<<<
            const x0 = vertices[j];
            const y0 = vertices[j + 1];
            const x = turtle.x; // * patchSize
            const y = turtle.y; // * patchSize
            positions[j + offset] =
                (size * (x0 * cos - y0 * sin) + x) * patchSize;
            positions[j + offset + 1] =
                (size * (x0 * sin + y0 * cos) + y) * patchSize;
            positions[j + offset + 2] = turtle.z * patchSize;
        }
        indexes.push(...indices.map(ix => ix + i * 4)); // 4
        uvs.push(...turtle.sprite.uvs);
    }
    positionAttrib.setArray(positions);
    positionAttrib.needsUpdate = true;
    uvAttrib.setArray(new Float32Array(uvs));
    uvAttrib.needsUpdate = true;
    indexAttrib.setArray(new Uint32Array(indexes));
    indexAttrib.needsUpdate = true;
}