Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicate Identifier in generated output #800

Closed
gliheng opened this issue Aug 23, 2020 · 5 comments
Closed

Duplicate Identifier in generated output #800

gliheng opened this issue Aug 23, 2020 · 5 comments
Labels

Comments

@gliheng
Copy link

gliheng commented Aug 23, 2020

Bug report

Version (5.2.1)

terser --module --compress --mangle -- ./input.js > output.js

terser input

let __VITE_CSS__ = document.createElement("style");
__VITE_CSS__.innerHTML = "";
document.head.appendChild(__VITE_CSS__);
let wasm;
let cachedTextDecoder = new TextDecoder("utf-8", {ignoreBOM: true, fatal: true});
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
  if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
    cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
  }
  return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
  return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
const heap = new Array(32).fill(void 0);
heap.push(void 0, null, true, false);
let heap_next = heap.length;
function addHeapObject(obj) {
  if (heap_next === heap.length)
    heap.push(heap.length + 1);
  const idx = heap_next;
  heap_next = heap[idx];
  heap[idx] = obj;
  return idx;
}
function getObject(idx) {
  return heap[idx];
}
function dropObject(idx) {
  if (idx < 36)
    return;
  heap[idx] = heap_next;
  heap_next = idx;
}
function takeObject(idx) {
  const ret = getObject(idx);
  dropObject(idx);
  return ret;
}
function greet() {
  wasm.greet();
}
function main_js() {
  wasm.main_js();
}
async function load(module, imports) {
  if (typeof Response === "function" && module instanceof Response) {
    if (typeof WebAssembly.instantiateStreaming === "function") {
      try {
        return await WebAssembly.instantiateStreaming(module, imports);
      } catch (e) {
        if (module.headers.get("Content-Type") != "application/wasm") {
          console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
        } else {
          throw e;
        }
      }
    }
    const bytes = await module.arrayBuffer();
    return await WebAssembly.instantiate(bytes, imports);
  } else {
    const instance = await WebAssembly.instantiate(module, imports);
    if (instance instanceof WebAssembly.Instance) {
      return {instance, module};
    } else {
      return instance;
    }
  }
}
async function init(input) {
  if (typeof input === "undefined") {
    input = "/_assets/rust_crate_bg.0ccbb076.wasm";
  }
  const imports = {};
  imports.wbg = {};
  imports.wbg.__wbg_alert_704a1ef95c5aac35 = function(arg0, arg1) {
    alert(getStringFromWasm0(arg0, arg1));
  };
  imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
    var ret = getStringFromWasm0(arg0, arg1);
    return addHeapObject(ret);
  };
  imports.wbg.__wbg_log_61ea781bd002cc41 = function(arg0) {
    console.log(getObject(arg0));
  };
  imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
    takeObject(arg0);
  };
  imports.wbg.__wbindgen_throw = function(arg0, arg1) {
    throw new Error(getStringFromWasm0(arg0, arg1));
  };
  if (typeof input === "string" || typeof Request === "function" && input instanceof Request || typeof URL === "function" && input instanceof URL) {
    input = fetch(input);
  }
  const {instance, module} = await load(await input, imports);
  wasm = instance.exports;
  init.__wbindgen_wasm_module = module;
  wasm.__wbindgen_start();
  return wasm;
}
export default init;
export {greet, main_js};

terser output or error

let e,n=document.createElement("style");n.innerHTML="",document.head.appendChild(n);let t=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});t.decode();let a=null;function i(n,i){return t.decode((null!==a&&a.buffer===e.memory.buffer||(a=new Uint8Array(e.memory.buffer)),a).subarray(n,n+i))}const o=new Array(32).fill(void 0);o.push(void 0,null,!0,!1);let r=o.length;function s(e){return o[e]}function c(e){const n=s(e);return function(e){e<36||(o[e]=r,r=e)}(e),n}function u(){e.greet()}function f(){e.main_js()}export default async function n(t){void 0===t&&(t="/_assets/rust_crate_bg.0ccbb076.wasm");const a={wbg:{}};a.wbg.__wbg_alert_704a1ef95c5aac35=function(e,n){alert(i(e,n))},a.wbg.__wbindgen_string_new=function(e,n){return function(e){r===o.length&&o.push(o.length+1);const n=r;return r=o[n],o[n]=e,n}(i(e,n))},a.wbg.__wbg_log_61ea781bd002cc41=function(e){console.log(s(e))},a.wbg.__wbindgen_object_drop_ref=function(e){c(e)},a.wbg.__wbindgen_throw=function(e,n){throw new Error(i(e,n))},("string"==typeof t||"function"==typeof Request&&t instanceof Request||"function"==typeof URL&&t instanceof URL)&&(t=fetch(t));const{instance:u,module:f}=await async function(e,n){if("function"==typeof Response&&e instanceof Response){if("function"==typeof WebAssembly.instantiateStreaming)try{return await WebAssembly.instantiateStreaming(e,n)}catch(n){if("application/wasm"==e.headers.get("Content-Type"))throw n;console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",n)}const t=await e.arrayBuffer();return await WebAssembly.instantiate(t,n)}{const t=await WebAssembly.instantiate(e,n);return t instanceof WebAssembly.Instance?{instance:t,module:e}:t}}(await t,a);return e=u.exports,n.__wbindgen_wasm_module=f,e.__wbindgen_start(),e}export{u as greet,f as main_js};

Expected result
In the output js, there is a let n and a function n. When loaded in browser as a module, it lead to this error: output.js:formatted:1 Uncaught SyntaxError: Identifier 'n' has already been declared.

@fabiosantoscode
Copy link
Collaborator

This bug surprised me!

The reason for this is that Terser turns function declarations in export default into function expressions. But only when they are moved there

I got the repro down to:

let e = eeeeepleeeease();
eeepleeeease(e)
function also_e() {
  return also_e;
}
export default also_e;

@fabiosantoscode
Copy link
Collaborator

A fix has been pushed, which will be released tomorrow.

@developit
Copy link
Contributor

I think there's another cases where this happens, but I can't seem to narrow it down. Running Terser (4.8 or 5.3) on this file causes the first imported identifier to become e, but also uses that identifier for the default-exported function's name:

https://unpkg.com/@emotion/styled-base@10.0.31/dist/styled-base.esm.js

import e from"/@npm/@babel/runtime/helpers/defineProperty";
// ...
export default function e(t,p){ // ...

@fabiosantoscode
Copy link
Collaborator

Reopening for investigation, thanks @developit

@fabiosantoscode
Copy link
Collaborator

@developit it's a variation on the previous issue :) an export default function x() {} counts as a function declaration.

Minimal repro:

import ee from 'ee';

var also_e = function also_e() {
  return also_e;
};

export default also_e;

Once the function expression with the name also_e gets inlined into export default, it becomes a function declaration, but Terser doesn't know that right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants