google / closure-compiler-npm

Package for managing and documenting closure-compiler for use via npm

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

feature_request(grunt): generate source maps for all compiled files

Kristinita opened this issue · comments

1. Summary

It would be nice, if would be possible to generate simply add correct source map (sourcemap) for each compiled JavaScript file.

2. Argumentation

2.1. Common cause

Implementation of a significant feature.

2.2. Details

I couldn’t find any method, how I can generate source maps for all my JavaScript files, if I use Closure Compiler (see “Not helped” section).

3. Example of expected behavior

I migrated to Closure Compiler from the UglifyJS. UglifyJS have the --source-map option. See the description from the official grunt-contrib-uglify repository.

If true, a source map file will be generated in the same directory as the dest file. By default it will have the same basename as the dest file, but with a .map extension.

For UglifyJS I need solely the sourceMap: true setting, and source maps will generate for all minified files. For example, UglifyJS create KiraFirst.min.js.map for KiraFirst.min.js, KiraSecond.min.js.map for KiraSecond.min.js and so on.

It would be nice to have a similar behavior for Closure Compiler.

4. Not helped

4.1. create_source_map

create_source_map option create a single source map file. I couldn’t find, how I can create multiple source maps use this option.

4.2. source_map_input

source_map_input option. Closure Compiler collaborator comment:

You can already use source maps in grunt. You just have to manually wire it all together. See the --source_map_input flag.

I have dozens of JavaScript files in my projects and I add new JavaScript files all the time. Manually adding files isn’t a best idea in this case. When I used UglifyJS, all I had to do was add sourceMap: true.

4.3. Preserve source map comments

I can generate source map files when I compile CoffeeScript to JavaScript use --map or --inline-map flags. .js files after a compilation have next lines in the end:

//# sourceMappingURL=data:application/json;base64…
//# sourceURL=…

Closure Compiler remove these comments. I couldn’t find any method how I can preserve them.

4.4. output_wrapper

Use output_wrapper option I can add to the end of each JavaScript file the line //# sourceMappingURL=output.min.js.map. But I couldn’t find how I can add the line //# sourceMappingURL={current_file}.min.js.map where {current_file} is the name of a current file without the extension. I couldn’t find how I can reference the source maps generated by CoffeeScript.

4.5. Use a bundler

  • Bad source maps caused by multiple transformations:

    If you’re using two or more JavaScript compilers invoked separately (e.g., Babel + UglifyJS), it’s possible to produce a source map that points to an intermediate transformed state of your code, rather than the original source code. This means that when you debug in the browser, the code you’re stepping through isn’t minified — an improvement for sure — but it’s still not a 1:1 match with your original source code. (…)

    Use a bundler like Webpack to manage all your transformations

    Instead of using Babel or UglifyJS separately, use them instead as Webpack plugins (e.g., babel-loader and uglifyjs-webpack-plugin). Webpack will produce a single source map that transforms from the final result back to your original source code, even though there are multiple transformations taking place under the hood. (…)

    If you have a choice in the matter, we’d recommend pursuing the first option — just use Webpack and save yourself some grief.

I couldn’t find how I can do it use Grunt + CoffeeScript + Closure Compiler.

4.6. External tools

I couldn’t find third-party Grunt plugins specifically for source maps generation.

5. Environment

(For preventing an XY problem)

I’m working with JavaScript with these tools:

  1. CoffeeScript: KiraSrc.coffeeKiraDest.js
  2. Closure Compiler (I migrated from UglifyJS that doesn’t support ES2015 and above): KiraDest.jsKiraDest.min.js
  3. grunt-cache-bust: Kira.min.jsKira.min.4147kira1447godd.js
  4. merge-source-maps: create Kira.min.4147kira1447godd.js.map file.

It would be nice to comply with all requirements described in the “4 Reasons Why Your Source Maps are Broken” article. It would be nice to debug a KiraSrc.coffee file in a browser when <script src="Kira.min.4147kira1447godd.js.map" defer></script> in a HTML file.

If it’s possible without any improvements, please tell me what should I do.

Thanks.

Another user here, but we're successfully using it in this way (except j2cl as the initial compiler, which produces .js and .js.map output).

  • Each foo.js file that we provide to closure-compiler has the //# sourceMappingURL=foo.js.map as its last line. No sourceURL is provided in each file - I don't think you need that unless you've packed each file into an eval or something (and even then beware that different browsers handle those paths differently)
  • Closure compiler is run in various modes, usually ADVANCED. Specific args passed:
    • All js files are passed via --js and --jszip, the js.map files are never directly specified
    • --create_source_map output.js.map is passed to specify the output file we would like to be created, alongside the output file
    • --source_map_location_mapping path/to/sources|. might make sense to ensure that the relative paths to find your original source files will show up where you expect
    • --output_wrapper takes a template arg %output% to have the original JS content - given that the name of the to-be-created .js.map file is included for the --create_source_map arg, you can also mention it here. Up until now I'd been specifying this as (function(){%output%}).call(this);\n//# sourceMappingURL=output.js.map and using --assume_function_wrapper true, but it appears that this doesn't matter in ADVANCED, you can probably get away with it without the IIFE.
    • --js_output_file output.js to specify the actual file.

In your case if I understand you correctly, your step 1 also emits a KiraDest.js.map, which you are also passing to closure-compiler - or is it inlined in KiraDest.js? I don't think that should make a difference, just be sure that either the original KiraSrc.coffee is packed as well, or use the --source_map_location_mapping correctly knows how to point at it. Based on step 2, I am not sure why you need to specify to create multiple output sourcemap files, since you only want roughly --js_output_file KiraDest.min.js and --create_source_map KiraDest.min.js.map (and an output wrapper that points to KiraDest.min.js.map). Then step 3 should stick a hash on the end of both files. Step 4 may not be necessary - for us, the closure-compiler emitted sourcemaps correctly consumed the many existing source maps and generated a new one that only included the required content in a single file.

This isn't grunt specific. Can you post this in the main compiler repo?

What's needed is for the output wrapper function to have placeholder expansion support for the output filename itself. That's not there today, but a worthwhile request.