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

allow --in-source-map inline #1490

Merged
merged 1 commit into from
Feb 24, 2017
Merged

allow --in-source-map inline #1490

merged 1 commit into from
Feb 24, 2017

Conversation

alexlamsl
Copy link
Collaborator

fixes #520

@kzc separated into two commits so it's easier to see the cli changes (haven't done anything to the API case yet)

You'll be glad to know that #520 (comment) didn't go to waste - aside from educating me on what a source map looks like, it forms the test case inside test/mocha/cli.js 😉

@alexlamsl
Copy link
Collaborator Author

... and just as I started to think about the API case, I just realised any changes to tools/node.js would massively conflicts with #1366 😓

@alexlamsl alexlamsl changed the title allow inlined source maps in compiled JS [WIP] allow inlined source maps in compiled JS Feb 15, 2017
bin/uglifyjs Outdated
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
print_error("ERROR: can't read source map");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add "inline" to the message so it's easier to catch configuration errors (I'm thinking along the lines of confusing --source-map-inline with --in-source-map inline).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bin/uglifyjs Outdated
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
print_error("ERROR: can't read source map");
process.exit(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should be a fatal error if the upstream code lacks an inline source map.

Perhaps something like "WARNING: inline source map not found" and return null; instead of process.exit(1);?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Commit title updated.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

@alexlamsl Thanks - nice job on the CLI. Surprisingly little new code added - mostly rearranging existing code. Glad the example proved useful.

I appreciate that adding this feature to minify() will massively conflict with #1366. Should we keep this PR in a [WIP] holding pattern until #1366 is merged?

The use of Buffer(..., 'base64') in this PR will create an incompatibility with #1366 anyway as it is not available in the browser without including a third party module (which we do not want to do). But I don't think the source-map module is compatible with the browser version of minify() anyway - @avdg can you confirm that?

Edit: If that's the case, then the exported base64 decode function for the browser can just throw a "not implemented" error as it won't be used.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

@alexlamsl Would you mind changing the PR title and eventual commit description to "[WIP] allow --in-source-map inline"?

@alexlamsl alexlamsl changed the title [WIP] allow inlined source maps in compiled JS [WIP] allow --in-source-map inline Feb 15, 2017
@alexlamsl
Copy link
Collaborator Author

I appreciate that adding this feature to minify() will massively conflict with #1366. Should we keep this PR in a [WIP] holding pattern until #1366 is merged?

Agreed.

The use of Buffer('...', 'base64') in this PR...

We actually have another problem in that we cannot use Buffer.from() due to Node.js 0.10.x compatibility.

I am assuming you are talking about tools/node.js with the browser use-case, as there's an existing usage of Buffer in bin/uglifyjs?

@alexlamsl
Copy link
Collaborator Author

I can't be certain, but at least in the browserified version of html-minifier there seems to be an implementation of Buffer embedded in the file. So I think we might be able to get away with this?

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

I am assuming you are talking about tools/node.js with the browser use-case, as there's an existing usage of Buffer in bin/uglifyjs?

No, I'm referring to the standalone uglifyjs --self code produced by #1366. Use of Buffer in tools/node.js is fine, but not in the portable code generated by --self. Notice the function exports that are substituted for the browser version in that PR:

https://github.com/mishoo/UglifyJS2/pull/1366/files#diff-465a5a39285d7d0ab958a973c3d58432R6

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

but at least in the browserified version of html-minifier there seems to be an implementation of Buffer embedded in the file. So I think we might be able to get away with this?

We want to avoid additional third party modules in Uglify where possible in order to keep Uglify small and fast. I'm fairly sure that source-map does not work in the portable --self version in the browser anyway, so it's not a loss of functionality.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

We actually have another problem in that we cannot use Buffer.from() due to Node.js 0.10.x compatibility.

Are there any features of minify() or bin/uglifyjs that will not work in node 0.10.x?

base 64 decode appears to work correctly in node 0.10.x:

$ node -v
v0.10.41

$ node -p "Buffer('dGhlIHF1aWNrIGZveA==', 'base64').toString()"
the quick fox

@alexlamsl
Copy link
Collaborator Author

@kzc ah, I didn't notice #1366 exports the new minify.js - but yes, it copied the use of Buffer from tools/node.js, so it will fail if used inside a web browser.

And I've got confused with uglify-to-browserify which I ran into in the past. Sorry about that.

@alexlamsl
Copy link
Collaborator Author

Are there any features of minify() or bin/uglifyjs that will not work in node 0.10.x?

I was referring to the use of Buffer(...) which is now deprecated.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

but yes, it copied the use of Buffer from tools/node.js, so it will fail if used inside a web browser.

I was under the impression that @avdg had tested that very thing. If that's the case, then #1366 would need some retooling because that's the point of its existence.

@alexlamsl
Copy link
Collaborator Author

I'd be positively impressed if sourceMapInline manages to just work inside the web browser.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

I was referring to the use of Buffer(...) which is now deprecated.

I'm not too worried about that. It's still supported. No uglify user has complained as far as I know.

@alexlamsl
Copy link
Collaborator Author

So according to MDN we can use atob() and btoa() if Buffer is absent to provide the base64 codec, and at least IE10 supports that.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

atob() does indeed work in Safari 9, and the latest versions of FireFox and Chrome:

alert(atob('dGhlIHF1aWNrIGZveA=='));

But it's not supported by node. So #1366 can check for its existence and patch exports.base64_decode (or whatever it may be called) accordingly.

@kzc
Copy link
Contributor

kzc commented Feb 15, 2017

@alexlamsl Your fix to optionally support inline input source maps works nicely:

$ echo 'foo(1+2);' | bin/uglifyjs - -cm toplevel --in-source-map inline --source-map-inline
WARN: inline source map not found
foo(3);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi0iXSwibmFtZXMiOlsiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQUEsSUFBSSJ9

@alexlamsl
Copy link
Collaborator Author

Your fix to optionally support inline source maps works nicely

Thanks - I even have a test case for it 😉

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

Isn't this PR good to go?

@alexlamsl
Copy link
Collaborator Author

Not really if you mean as it is right now - tools/node.js has yet to be updated for this PR.

But delaying of #1366 meant I can now proceed in completing this. And it does looks like a good feature to have for 2.8.0 so I'll get to this right after I finished my local git housekeeping 😉

@alexlamsl
Copy link
Collaborator Author

@kzc due to new default optimisation options, I need to update test/input/issue-520/output.js to reflect the new output. PTAL to verify updated source map.

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

I never actually loaded these source maps to verify them, but it looks well formed as far as I can tell.

@alexlamsl
Copy link
Collaborator Author

One thing I'm confused with is --spidermonkey, where in cli it reads the file content the same way before parsing so we are covered, but with minify() that isn't the case.

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

It eventually does the same thing...

https://github.com/mishoo/UglifyJS2/blob/8898b8a0fe87f71c0ea2d35face6dfbf11db27ec/bin/uglifyjs#L388-L390

It's a bit confusing how TOPLEVEL can be either an Uglify AST or a Mozilla AST at different points in the program.

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

bin/uglifyjs also has to handle asynchronous input from stdin, while minify() does not.

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

Wait... I see what's going on: the first argument of minify() which happens to be named files is overloaded and assumed to be a Mozilla AST if options.spidermonkey is set. Confusing! We should add a test for it.

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

I knew that bin/uglifyjs could accept mozilla JSON from stdin, but I did not know it could accept mozilla JSON input from multiple files:

$ echo 'foo();' | uglifyjs --dump-spidermonkey-ast > foo.json
$ echo 'bar();' | uglifyjs --dump-spidermonkey-ast > bar.json
$ uglifyjs bar.json foo.json --spidermonkey
bar();foo();

Cool!

@alexlamsl
Copy link
Collaborator Author

@kzc ah, that means this PR won't work even for bin/uglifyjs when spidermonkey is involved.

Tempted to explicitedly throw an error for both interfaces if both spidermonkey and inSourceMap="inline" are specified for now. This way we minimise ambiguity, and if somebody ends up wanting to use that combination it can be extended in the future.

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

that means this PR won't work even for bin/uglifyjs when spidermonkey is involved.

I think Mozilla AST (spidermonkey) and inline input source maps are inherently incompatible because I don't think comments are preserved in the Mozilla AST - and if they are Uglify does not handle them.

https://github.com/estree/estree
estree/estree#94
estree/estree#41

@alexlamsl
Copy link
Collaborator Author

@kzc added checks & tests for built-in parser during inSourceMap="inline"

@kzc
Copy link
Contributor

kzc commented Feb 24, 2017

Great. I'm sure it's fine.

- limited to one input file (or `stdin`)
- only works with built-in parser

fixes mishoo#520
@alexlamsl alexlamsl changed the title [WIP] allow --in-source-map inline allow --in-source-map inline Feb 24, 2017
@alexlamsl alexlamsl merged commit cf0951f into mishoo:master Feb 24, 2017
@alexlamsl alexlamsl deleted the issue-520 branch February 24, 2017 20:11
@Forkest
Copy link

Forkest commented Feb 25, 2017

Don't you think that having
--source-map-inline and
--in-source-map inline results in a bit incosistent API?
Maybe change the new option to a version with a dash before it is too late?

@kzc
Copy link
Contributor

kzc commented Feb 25, 2017

I could live with --in-source-map-inline, but if --in-source-map=foo.js.map is also specified which takes precedence?

@Forkest
Copy link

Forkest commented Feb 25, 2017

The behavior should be the same as with --source-map=foo.js.map --source-map-inline. Tried that, inline option takes precedense, file option is ignored.

@kzc
Copy link
Contributor

kzc commented Feb 25, 2017

inline option takes precedence

Seems the choice was arbitrary. Probably should error out for a conflict between --source-map and --source-map-inline.

At least with the present behavior of --in-source-map [filename|inline] there is no potential conflict. But whichever way, it should be consistent. No reason why we couldn't also support --source-map=inline to output an inline source map in addition to adding --in-source-map-inline.

Perhaps even have extra aliases --out-source-map and --out-source-map-inline respectively to further reduce confusion as to the direction of the source map operation which has tripped me up in testing on more than one occasion.

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

Successfully merging this pull request may close these issues.

allow inlined source maps in compiled JS
4 participants