Uglifyjs: Is there a migration guide, from version 2.x to 3.x?

Created on 8 May 2017  ·  26Comments  ·  Source: mishoo/UglifyJS

Alternatively, how hard do you think it will be to migrate, using 3.x documentation?

Are there major changes, beyond function names and parameters, that could prevent migration?

Thanks for your help.

Most helpful comment

O_o

I would love to, but I have no idea what has changed, which is why I am asking.

All 26 comments

Depends on whether you use minify() or bin/uglifyjs - the latter has more changes, but https://github.com/mishoo/UglifyJS2#usage should describe what you need and where they are placed.

The commit message of https://github.com/mishoo/UglifyJS2/commit/ec443e422c220619fe671166e467d3d8838b0cab also contains a summary of what's added, renamed and removed.

Any chance of a changelog?

Any chance of a changelog?

PRs are welcomed on this.

O_o

I would love to, but I have no idea what has changed, which is why I am asking.

A PR for a changelog feels odd, maybe a PR for a migration guide, but a changelog needs to be a commitment.

Feels like a non-exhaustive or outdated changelog can cause more irritation than it solves – so if it's only ever going to be updated by subsequent changelog-focused PR:s, then better do a migration guide for this specific jump in major version instead.

I'm very much 👍 on changelogs though (due to reasons outlined on eg. http://keepachangelog.com/)

I don't understand the attitude - you guys put so much time and effort into this, and when users get excited and want to find out what's you guys have done you basically tell them to sod off and look in the git history. Weird.

You can probably learn a thing or two from how the people at eslint handle it - nice (automatically generated) changelog
https://github.com/eslint/eslint/releases
AND release notes
http://eslint.org/blog/2017/05/eslint-v4.0.0-alpha.2-released

@gotofritz It's easy to complain. We're volunteering our time here. All open source projects could benefit from more contributors.

The git history was provided to you because of your offer to create a ChangeLog:

I would love to, but I have no idea what has changed, which is why I am asking.

I will let you know of the changes I will do to migrate, but I am only using the API, so this will be incomplete for other people. I am not using the CLI in my projects.

I had already found that (big) commit, but thanks to point out that this is the main one.

And thanks again for your work.

In 2.x, I was using UglifyJS.parse() as documented here: http://lisperator.net/uglifyjs/parser

With version 3,x, parse() is no longer available. This means that changes will be quite significant for me as the API of minify() seems very different from the set of functions provided by the previous API. I had spent quite some time implementing this API. Is there another option allowing to preserve the general flow of the previous API?

@uiteoi parse() is no longer exposed in 3.x, and the replacement would be:

// 2.x
var ast = UglifyJS.parse(code, options);
// 3.x
var ast = UglifyJS.minify(code, {
    parse: options,
    compress: false,
    mangle: false,
    output: {
        ast: true,
        code: false  // optional
    }
}).ast;

While code: false is optional, if you only require the AST and not the minified code string then specifying the following is more efficient:

        output: { ast: true, code: false }

than

        output: { ast: true }

as code: false skips the code generation phase.

The minify result.ast can be passed to subsequent minify() calls in the first argument.

I don't know if any of this is in the README.

Well, I am having a few issues which seem to lead me to a significant rewrite, with the possible loss of a significant performance feature for my application.

I was using, what you might have referred in some commits as the "low-level API": UglifyJS.parse(), ast.figure_out_scope(), UglifyJS.Compressor(), ast.transform(), ast.compute_char_frequency(), ast.mangle_names(), UglifyJS.SourceMap(), UglifyJS.OutputStream(), and ast.print().

ast functions still seem work, from returned ast using minify option output.ast set to true. But none of the other UglifyJS functions are available. I have been able to modify my code, as suggested by @kzc, calling minify() again using ast as first parameter and various options to achieve what I think should be equivalent to these previous functions behavior.

A previous feature of the parser, enabled to pass the toplevel node, this is no longer possible at least because in lib/minify.js line 83 shows options.parse.toplevel = null;. I have tried to comment this line out, with some success but the result is a very long running process (about one minute and a half vs a few seconds before), and compressed code that does not work for no obvious reason.

Parsing files, independently one at a time, I hoped to be able one day to update a bundle faster when one source file changed, parsing only that file again, and merging toplevel nodes. I had never completed this because I did not find in the documentation how to merge toplevel nodes, but this was high in my ToDo list. If I start using minify() to do everything, which I have not tried yet, this will forever make it impossible to update faster a bundle when one source file changes.

I do have a backup plan in mind but it will be slower and more complex in the short term. It involves merging source maps after bundling a set of source files minified individually. This is also quite complex but allows to solve another problem with uglified bundles, the ability to have individual input source maps per source file (there is an open issue for this).

Please let me know your thoughts.

@uiteoi I can't say I understand your requirements from your description above. But note that there are implicit assumptions about division of labour and order of executions of these low-level APIs, which is part of the reasons why they are no longer exposed due to potential misuse.

For instance, just because you can construct an AST does not mean Compressor or even OutputStream would be able to run correctly. They are only assumed to work with AST generated by parse(), which is limited in certain (unspecified) ways. That is especially true if you are attempting to glue AST_TopLevels together.

So I think the best way forward for you is to identify the functionalities you need and file pull/feature requests on them.

@uiteoi Perhaps we can keep this issue about the overall migration guide / changelog and add new issues for any specific problems that arises from any such 2.x to 3.x migration? So that we doesn't lose the main issue in the discussion of any single migration point.

@kzc The git history provide a history of code changes, a changelog provides a history of feature and API changes.

The git history can both be too verbose and too compact to give a good insight into the major breaking changes, the most interesting new additions and the reasoning behind them and other changes in any given version – that's where a changelog shines.

I myself find changelogs valuable when I contribute my time to opensource projects as it means my contribution will deliver greater value, as others will have an easier time to take advantage of it and as it will deliver more long term value as others will have an easier understanding of why it was done in the first place.

As it means an easier time for people who upgrade to a new version it will also mean that more people can provide meaningful contributions to the project, as more people are closer to the cutting edge code, and it will also mean less noise in the issues as fewer reports of old bugs from old versions will happen + fewer issues that are due to misunderstandings or oversights in users migrations to newer versions will be reported.

So I wouldn't say it's just complaining – it's a suggestion on how a contribution can be made more valuable.

My "requirement", but out of respect for your contributions I would rather call this a wish, is to be able to update a minified bundle as fast as possible when one source file changes as it happens during the developpement process of an application. In production, this is usually not an issue, and this could be considered a productivity issue, so I will admit that this is non-critical.

What this discussion allows me to realize is that by using the low-level API I took a risk, a few years back, and that I now need to reconsider the architecture to fit all my goals.

One unsatisfied goal, as mentioned above, relates to having independent input source maps, as referenced in open issue #145 and related closed issue #151.

So, I must conclude that the best option for me is probably, what I had considered a backup plan so far, using minifiy() on each source file individually, This will allow to work-around the input source map issue, and will allow to update the bundle incrementally when one source changes. I will still have to bundle the results, which is somewhat tricky for source maps, offsetting positions, but for which it should be quite easy to find documented examples.

Note that this work could lead to a contribution for merging individually minified files and their source maps, that would allow to close long-standing open issue #145. So if there is any existent code in Uglify that could help me in that regard, or pointers to outside work and articles, it would allow me to get faster to a resolution.

Thanks again for your help and great work.

@uiteoi interesting. If I understand you correctly, since merging multiple .js files are as simple as concatenating them together, the missing piece in your puzzle is merging of .js.map files?

For the incremental file update case, you have probably found the best solution, because when you present uglify-js with an AST to optimise, it will treat the input as a whole and spit out something that is quite hard to separate afterwards, e.g. hoist_funs would move all the top-level function blocks around. So in your case trading whole program optimisation for runtime performance is a good way to go.

145 is an interesting feature but one I can't work on due to lack of familarity with source maps (I don't use them). Feel free to open a PR for this - I'll be happy to help out. Presumably this can be done by expanding on options.sourceMap.content to have it accept an object with keys as file paths, just like the first function argument in minify().

@alexlamsl, yes you understood correctly, concatenating compressed outputs is trivial, the only challenge is with sourcemaps. I am looking into mapcat but it's exported API reads files (and does so synchronously), when what we need it to work on a JSON Object containing input source maps. Also mapcat does not seem to be actively maintained and does not have license.

My idea to solve issue #145, it to work-around the problem by merging individual source map outputs as mentioned above. This is probably much easier than solving this issue upfront as this may require more intimate knowledge of sourcemaps internals. My solution would change minify() to minify each file individually, allowing each file to have its optional inline source map, then merging all outputs and generated the output sourcemap out of all individual sourcemaps.

So I wouldn't say it's just complaining – it's a suggestion on how a contribution can be made more valuable.

@voxpelli We all know what a change log is and the merits of documentation in general. No one is opposed to it. If you feel strongly about it, then by all means contribute a pull request. Suggestions are fine, but people volunteering their time can work on whatever they like.

@kzc Chill, we're all here because we care about projects like this one, no one is requesting people to do work against their will.

If you don't have the time to keep a changelog, could you at least tag commits and pull requests with their semver status?

Thanks to @kzc, documentation for 3.x has improved significantly. Anyone is welcomed to suggest further improvements in the form of pull requests.

Source map related portion is tracked by existing issues, so closing this.

Every PR that introduces a user-facing change (at least) should have a changelog entry.

We keep a structured YAML format changelog, and also record major dev changes.

This has absolutely zero to do with number of contributors or "needing more contributors". The contributor who made the change should be updating the changelog. In fact, having a good changelog is likely to get you more contributors (cause they have visibility into what is going on with the project).

Good grief. We're all devs here and we all do work for others for free. That work is not only pretty much useless, but also can cause serious negative consequences if you can't keep track of it properly. We no longer live in the wild west of copy-pasted code; get on board.

FYI, Terser now does keep a changelog.

@DylanYoung Uglify is semi-abandoned and a lot of people in the industry has moved on to Terser

@curiousdannii @gotofritz Thanks for the tip!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gabmontes picture gabmontes  ·  5Comments

pvdz picture pvdz  ·  3Comments

Havunen picture Havunen  ·  5Comments

alexlamsl picture alexlamsl  ·  4Comments

alexlamsl picture alexlamsl  ·  4Comments