Jsdelivr: auto-minification issue with ionify

Created on 8 Apr 2020  路  9Comments  路  Source: jsdelivr/jsdelivr

The github auto-minification instructions

Add ".min" to any JS/CSS file to get a minified version - if one doesn't exist, we'll generate it for you. All generated files come with source maps and can be easily used during development:

https://cdn.jsdelivr.net/gh/jquery/[email protected]/src/core.min.js
Minifying a large file can take several seconds. However, we store all generated files in our permanent storage, so this delay only applies to the first few requests.

don't work with these javascript files

jsdelivr returns this essentially similar message with no content for both

/**

The original files each load correctly from jsdelivr without the .min.js option and when combined via

https://cdn.jsdelivr.net/combine/gh/ionify/ionify@public/web.js,gh/ionify/ionify@public/ions/on.ion.js

enhancement discussion

All 9 comments

When minifying files, it is generally expected that they are standalone and not meant to be concatenated or merged with other files before running them. I'm not sure how those files are supposed to be used but they do not do anything on their own so the minifier correctly removes everything as dead code.

Hi @MartinKolarik,

Thanks for quickly replying.

Though the syntax of the code in the referenced Javascript files is novel, each of those files is valid standalone JavaScript that does specific things, and isn鈥檛 dependent on being concatenated or merged with any other file to run.

You can see the scripts being fetched & ran independently in any JavaScript-enabled web browser by viewing https://anemojii.glitch.me then using the browser鈥檚 developer tools to view the site鈥檚 network activity.

Since these are valid standalone JavaScript files with no dead code, minification should work correctly, and shouldn鈥檛 remove any of their code.

Ok, you are right, it relies on valueOf being called by preceding the object with ~, which is a valid but highly nonstandard pattern.

As the comment in our minified file says, we use Terser for minification, so I can only suggest checking if this happens with the latest version (jsDelivr is still on v3, latest is v4) and if yes, raising an issue in their repo. In case it doesn't happen with v4 then it'll be fixed at jsDelivr in the near future when we upgrade to the latest version.

Yep, you got it, they use valueOf to derive meaning & behavior from object literals that've been activated by ~.

re: minification:

I looked into how Terser & its predecessor Uglify interact with ions: invoked object notations, the pattern used by the two scripts I've mentioned in this issue.

I found that setting Terser's compress option to false fixes the issue & produces minified code. Looking deeper I found that disabling Uglify's side_effects option also solved the problem & that Terser's similar config option did too:
js {compress: {side_effects: false}}
Since these config options exist & when used eliminate the problem, this seems less like a Terser bug & more like a jsDelivr auto-minification enhancement request.

This led me to these questions & thoughts about how to possibly address this:

  • Can jsDelivr set Terser's side_effects compress config option to false?

    • this seems like a low effort, low disruption approach
    • would keep side-effect-free statements in outputted code
    • affects all repos using auto-minifcation
  • Can jsDelivr set Terser's compress config option to false?

    • this seems like a low effort, but potentially high disruption (increased file size) approach
    • affects all repos using auto-minifcation
  • Can jsDelivr enable & use author-defined minification rule config files like .terserrc similar to eslint's .eslintrc lint config?

    • this could be low effort, low disruption & high impact if repos already have .terserrc files
    • this would isolate custom minification behavior to individual repos
    • this would enable me to set compress options as needed for ionify
    • maybe jsDelivr can read it directly since I believe it uses the Terser API, e.g.
      js var options = JSON.parse (fs.readFileSync (".terserrc", "utf8")); Terser.minify (code, options);
    • Terser offers this CLI option --config-file <file> Read minify() options from JSON file.

Indeed, there's an assumption that valueOf() will have no side effects mentioned at https://github.com/terser/terser#compiler-assumptions. We'll check what difference the side_effects option makes.

Sounds good @MartinKolarik. Please let me know what you find.

Here鈥檙e some additional observations I鈥檝e made since our last chat:

The compress sequences option that defaults to true also causes significant portions of valid code to be omitted from minified output.

Setting the sequences and side_effects compress options to false corrects the problem:

{ compress:
    { sequences   : false,
      side_effects: false
    }
}

but setting sequences to false has an adverse effect of meaningfully increasing minified file size. That could have a significant negative effect on other repos and their users if applied globally to all repos.

This situation is a tangible justification for my earlier proposal to have jsDelivr use per-repo terser config rules via.terserrc files when present.

That would enable repos like ionify to effectively use jsDelivr鈥檚 auto-minification without negatively affecting other jsDelivr-served repos.

That's rather weird, based on what that option is for, I wouldn't expect it to make a difference in what code is dropped.

Regarding the author-defined config, I don't think this is something we could do in the near future.

First, it's a potential security problem and would need to be examined and implemented carefully.

Second, if a package contained the config file, it would almost always contain the minified files as well. The only exception would be if the author specifically relied on jsDelivr to generate the files but needed to change the config, as in your case. However, this is a very rare case and since author's involvement is needed anyway, they may just ship the minified files themselves. The main point of auto minification is that's it's zero config and you can use it even when the author doesn't want/care to ship the minified files.

I do think it makes sense to examine the compress option and if there's something that might improve compatibility without significantly affecting the size, we could change it. But in your case it might just make more sense to setup a GH action to automatically minify and publish the files to npm or another GH branch or repo.

Great points re: security & the likelihood of files already being minified if their package contained a config file. I didn鈥檛 consider that and agree that it鈥檚 probably simpler to have ionify do its own minification so I鈥檒l look into automating that via Github.

I was, and still am excited about jsDelivr鈥檚 zero-config on-demand & persistent file minification & combination. I find those features really convenient & helpful for performance, and now expect them from top-tier cdns.

I鈥檓 still concerned about Terser鈥檚 compression operation and think it鈥檚 important to confirm why the sequences compress option causes the code omission problem I鈥檓 seeing. I鈥檒l look into that and file a Terser issue if it鈥檚 indeed a bug in their compression process.

Following up:

I filed terser/terser#644 but it was closed due to terser鈥檚 pre-existing decision to not handle code affecting .valueOf(). Based on the conversation there, I don鈥檛 believe it鈥檚 useful for you (jsDelivr) to look further into terser鈥檚 compress config option as it relates to its effect on ionify.

I鈥檓 disappointed I won鈥檛 be able to use jsDelivr鈥檚 auto-minification functionality because it was one less task to do & handle as a package author who deeply values performance.

I was excited to see how much jsDelivr was doing with features like on-demand & persisted minification & combination to optimize file transfer between server & client. I see all such activities as reasonable, even if uncommon, for cdns to do to provide consistently maximal performance irrespective of package author effort. I love that jsDelivr is already using HTTP/2 and was excited to see how much shorter load time could be with the added compression.

Thanks again for the conversation & keep up the great work. I鈥檓 really happy that jsDelivr exists and that you all are continuing to do this innovative & great work.

Was this page helpful?
0 / 5 - 0 ratings