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

Minifying the code in 3 passes leads to a syntax error #3051

Closed
6 tasks done
cawa-93 opened this issue Apr 19, 2021 · 9 comments · Fixed by #4163
Closed
6 tasks done

Minifying the code in 3 passes leads to a syntax error #3051

cawa-93 opened this issue Apr 19, 2021 · 9 comments · Fixed by #4163
Labels
p3-minor-bug An edge case that only affects very specific usage (priority)

Comments

@cawa-93
Copy link
Contributor

cawa-93 commented Apr 19, 2021

Describe the bug

If set up terser with passes >=3

terserOptions: {
  compress: {
    passes: 3
  }
}

The application does not load, you may see an error in the console:

Uncaught SyntaxError: identifier starts immediately after numeric literal

The cause of the problem is the minification of the code using a terser. It occurs if 3 or more passes are configured.

I thought this was a problem with the terser and tried for a long time to reproduce the error in REPL. But no matter what I do, everything works as expected and it happens only when the code is optimized through the Vite.

Reproduction

Reproduction repo: cawa-93/vite-terser-issue

  1. Clone reproduction repo: git clone git@github.com:cawa-93/vite-terser-issue.git
  2. cd ./vite-terser-issue
  3. Install deps: npm ci
  4. Build and serve npm run build && npm run sevce
  5. Open app http://localhost:5000

System Info

  System:
    OS: Windows 10 10.0.19042
    CPU: (16) x64 AMD Ryzen 7 4800H with Radeon Graphics
    Memory: 9.36 GB / 15.42 GB
  Binaries:
    Node: 14.16.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 7.9.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.423.0), Chromium (90.0.818.41)
    Internet Explorer: 11.0.19041.1
  npmPackages:
    @vitejs/plugin-vue: ^1.2.1 => 1.2.1
    vite: ^2.2.0 => 2.2.0

Used package manager: npm

Before submitting the issue, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • Provide a description in this issue that describes the bug.
  • Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to https://github.com/vuejs/vue-next instead.
  • Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
@sodatea sodatea added bug p3-minor-bug An edge case that only affects very specific usage (priority) and removed pending triage labels Jun 24, 2021
@sodatea
Copy link
Member

sodatea commented Jun 24, 2021

It's because terser moves the preloadMarker around in the 3rd pass.
The marker need to be processed by the buildImportAnalysisPlugin later.
Change of its position thus results in corrupted code.

@ygj6
Copy link
Member

ygj6 commented Jul 3, 2021

This is not vite bug,is terser bug, call require("terser").minify(code, options) to get the same error code.
Reproduction repo:ygj6/issue-3051

@Shinigami92 Shinigami92 added the bug: upstream Bug in a dependency of Vite label Jul 3, 2021
@sodatea sodatea removed the bug: upstream Bug in a dependency of Vite label Jul 5, 2021
@sodatea
Copy link
Member

sodatea commented Jul 5, 2021

@ygj6 They are not the same.

In your reproduction, the result contains the following code:

"__VITE_PRELOAD__".map((e) => {

The output of terser is valid JavaScript.

But in the original issue, it's

Promise.all(void 0.map((e => {

It results in a syntax error.

The syntax error is caused by the text replacement of the import analysis plugin:

s.overwrite(
markPos - 1,
markPos + preloadMarker.length + 1,
// the dep list includes the main chunk, so only need to
// preload when there are actual other deps.
deps.size > 1
? `[${[...deps].map((d) => JSON.stringify(d)).join(',')}]`
: `void 0`
)

@ygj6
Copy link
Member

ygj6 commented Jul 5, 2021

@sodatea
Do you mean the processing of passes: 3 is correct?
When compress.passes is set to 2,it is correct that there is no need to text replacement.

Promise.all(t.map((e=>{

image

compress.passes:3 output:

import{o as e,c as t,a as o,w as r,b as n,r as s,d as a,e as u,f as l}from"./vendor.30acece7.js";let i;const d={},p=n(" This is "),c=o("b",null,"home",-1),m=n(" page. "),h=o("br",null,null,-1),f=n(" Go to "),b=n("About"),v=n(" page ");var E=a({routes:[{path:"/",name:"Home",component:{expose:[],setup:n=>(n,a)=>{const u=s("router-link");return e(),t("div",null,[p,c,m,h,f,o(u,{to:"/about"},{default:r((()=>[b])),_:1}),v])}}},{path:"/about",name:"About",component:()=>function(e,t){if(void 0===i){const e=document.createElement("link").relList;i=e&&e.supports&&e.supports("modulepreload")?"modulepreload":"preload"}return Promise.all("__VITE_PRELOAD__".map((e=>{if(e in d)return;d[e]=!0;const t=e.endsWith(".css"),o=t?\'[rel="stylesheet"]\':"";if(document.querySelector(`link[href="${e}"]${o}`))return;const r=document.createElement("link");return r.rel=t?"stylesheet":i,t||(r.as="script",r.crossOrigin=""),r.href=e,document.head.appendChild(r),t?new Promise(((e,t)=>{r.addEventListener("load",e),r.addEventListener("error",t)})):void 0}))).then((()=>import("./About.7865495d.js")))}()}],history:u()});l({expose:[],setup:o=>(o,r)=>{const n=s("router-view");return e(),t(n)}}).use(E).mount("#app");

compress.passes:2 output:

import{o as e,c as t,a as o,w as r,b as n,r as s,d as a,e as u,f as l}from"./vendor.30acece7.js";let i;const d={},p=n(" This is "),c=o("b",null,"home",-1),m=n(" page. "),h=o("br",null,null,-1),f=n(" Go to "),b=n("About"),v=n(" page ");var E=a({routes:[{path:"/",name:"Home",component:{expose:[],setup:n=>(n,a)=>{const u=s("router-link");return e(),t("div",null,[p,c,m,h,f,o(u,{to:"/about"},{default:r((()=>[b])),_:1}),v])}}},{path:"/about",name:"About",component:()=>function(e,t){if(void 0===i){const e=document.createElement("link").relList;i=e&&e.supports&&e.supports("modulepreload")?"modulepreload":"preload"}return Promise.all(t.map((e=>{if(e in d)return;d[e]=!0;const t=e.endsWith(".css"),o=t?\'[rel="stylesheet"]\':"";if(document.querySelector(`link[href="${e}"]${o}`))return;const r=document.createElement("link");return r.rel=t?"stylesheet":i,t||(r.as="script",r.crossOrigin=""),r.href=e,document.head.appendChild(r),t?new Promise(((e,t)=>{r.addEventListener("load",e),r.addEventListener("error",t)})):void 0}))).then((()=>e()))}((()=>import("./About.7865495d.js")),"__VITE_PRELOAD__")}],history:u()});l({expose:[],setup:o=>(o,r)=>{const n=s("router-view");return e(),t(n)}}).use(E).mount("#app");

@sodatea
Copy link
Member

sodatea commented Jul 5, 2021

image

The result of terser is correct.

@ygj6
Copy link
Member

ygj6 commented Jul 5, 2021

@sodatea Learned it, thank you.
For the compress.passes option, my understanding is the number of compress.
terser api:
image

So I don’t know if it should output "__VITE_PRELOAD__".map((e) => { after compress.passes:3

@ygj6
Copy link
Member

ygj6 commented Jul 5, 2021

@sodatea
I want to try to fix this problem, do you have any suggestions?

@sodatea
Copy link
Member

sodatea commented Jul 5, 2021

  1. Remove the else condition here
    deps.size > 1
    ? `[${[...deps].map((d) => JSON.stringify(d)).join(',')}]`
    : `void 0`
    , should always use an array
  2. Now that deps is always an array, its type and the first if condition should also be fixed here
    function preload(baseModule: () => Promise<{}>, deps?: string[]) {
    // @ts-ignore
    if (!__VITE_IS_MODERN__ || !deps) {
    return baseModule()
    }
  3. Add a test to avoid future regressions.

@ygj6
Copy link
Member

ygj6 commented Jul 5, 2021

thx, I will do it right now.

ygj6 added a commit to ygj6/vite that referenced this issue Jul 6, 2021
sodatea pushed a commit that referenced this issue Jul 8, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Jul 23, 2021
aleclarson pushed a commit to aleclarson/vite that referenced this issue Nov 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants