Skip to content

Conversation

eleith
Copy link

@eleith eleith commented Oct 24, 2013

when generating source maps by using the fromString=true in the Uglify.minify options, the source map contains a problematic array for the sources field

...
sources: ["?"],
...

thus, the source map can't be used because i can't point it at the original source. however, if i do not use a string directly but the filename itself, the source map feature works.

this pull request adds a fromFile option that can either be an array of filenames or just a single string filename to properly match up if just a single string of source code is passed in, or an array of source code.

so the following approaches now produce good source maps

Uglifyjs.minify(
  "function() { alert('yes');", 
  {fromString:true, fromFile:"yes.js"});

and

Uglifyjs.minify(
  ["function() { alert('yes');", "function() { alert('no');"], 
  {fromString:true, fromFile:["yes.js", "no.js"]});

@eleith
Copy link
Author

eleith commented Nov 1, 2013

@mishoo would you mind taking a look at this PR?

@guybedford
Copy link

+1

Note this is a duplicate of #294

Happy for either one to be included. Just really need this functionality.

@eleith
Copy link
Author

eleith commented Nov 15, 2013

we too are using a fork, but would much rather use the mainline branch here. @mishoo if there are any iterations i could do on this PR, please let me know. i'm happy to work on this and see it through.

@eleith
Copy link
Author

eleith commented Feb 13, 2014

ping

@ksmithut
Copy link

Without reading through all of the pull requests, I made my own, but I'm impartial as to which one gets merged in. Seems like it's been a while since anyone has looked at this. Many task runners could really take advantage of this functionality. Since uglify is one of the more common build tasks in web development, I recommend this become a priority.

Let me know how I can help.

@eleith
Copy link
Author

eleith commented Mar 20, 2014

what we ended up doing is just not calling minify directly from uglify and instead used the custom minify function that is inside this PR.

luckily the function is small, so we can maintain it for now. but yes, it would be nice to just have this in the library itself.

@ksmithut
Copy link

Sounds like a good idea. Did you have to account for all of the other options that can affect the output after that as well?

@ksmithut
Copy link

Something else I've had to do is be able to take in a source map as a string (coffeescript generated source map). I've got it on my fork. When I see @mishoo spend a bit more time here on uglify, I'll send a PR. He seems to be pretty occupied with angular-kendo (understandably).

@eleith
Copy link
Author

eleith commented Mar 23, 2014

yes, we do have to account for other options that we may want to pass in that affect output.

so instead of calling

compressed = uglify.minify(piece.data, options)

we now call

 // use the patch version of minify call
      // so we have greater control over file naming
      // especially for source maps
      // we also allow user to configure options of uglify directly
      compressed = UglifyMinifyPatch(piece.data, {
        fromString: true,
        mangle: this.config.uglify.mangle || false,
        outSourceMap: this.config.uglify.sourceMaps ? path.basename(piece.filename): null,
        fromFile: path.basename(piece.filename) + '.src',
        compress: _.isObject(this.config.uglify.compress) ? this.config.uglify.compress
          : {conditionals: false, unused: false}
      });

and this is what UglifyMinifyPatch looks like

/****************
* START UGLIFY PATCH
*
* Uglify2 doesn't have support for controlling the name of source maps
* when we are passing strings to be minified. there is a patch submitted on github
*
* https://github.com/mishoo/UglifyJS2/pull/324/files#diff-29c0119b6a96bae34223c40f1c7f774bR102
*
*************/

var UglifyMinifyPatch = function(files, options) {
  options = uglify.defaults(options, {
      outSourceMap : null,
      sourceRoot   : null,
      inSourceMap  : null,
      fromString   : false,
      fromFile     : null,
      warnings     : false,
      mangle       : {},
      output       : null,
      compress     : {}
  });

  if (typeof files == "string") {
      files = [ files ];
      options.fromFile = options.fromFile ? [options.fromFile] : ["?"];
  }

  uglify.base54.reset();

  // 1. parse
  var toplevel = null;
  files.forEach(function(file, index){
      var code = options.fromString ? file
          : fs.readFileSync(file, "utf8");
      toplevel = uglify.parse(code, {
          filename: options.fromString ? options.fromFile[index] : file,
          toplevel: toplevel
      });
  });

  // 2. compress
  if (options.compress) {
      var compress = { warnings: options.warnings };
      uglify.merge(compress, options.compress);
      toplevel.figure_out_scope();
      var sq = uglify.Compressor(compress);
      toplevel = toplevel.transform(sq);
  }

  // 3. mangle
  if (options.mangle) {
      toplevel.figure_out_scope();
      toplevel.compute_char_frequency();
      toplevel.mangle_names(options.mangle);
  }

  // 4. output
  var inMap = options.inSourceMap;
  var output = {};
  if (typeof options.inSourceMap == "string") {
      inMap = fs.readFileSync(options.inSourceMap, "utf8");
  }
  if (options.outSourceMap) {
      output.source_map = uglify.SourceMap({
          file: options.outSourceMap,
          orig: inMap,
          root: options.sourceRoot
      });
  }
  if (options.output) {
      uglify.merge(output, options.output);
  }
  var stream = uglify.OutputStream(output);
  toplevel.print(stream);
  return {
      code : stream + "",
      map  : output.source_map + ""
  };
};
/****************
* END UGLIFY PATCH
******************/

@mishoo
Copy link
Owner

mishoo commented Mar 26, 2014

Sorry for ignoring this for so long. However, I don't like what this API becomes.

What if we support an array of objects as first argument to UglifyJS.minify? Then we can ditch fromString, fromFile and perhaps even inSourceMap, and support them as options per each file, i.e.

UglifyJS.minify([
    { filename: "...",
      content: "...", // optional
      inSourceMap: "..." }
]);

@eleith
Copy link
Author

eleith commented Mar 26, 2014

i like that API as well

@ksmithut
Copy link

+1 on that. Anyone planning on implementing? I would be more than happy to, I just don't want to open up a pull request if someone is already going to work on it.

@eleith
Copy link
Author

eleith commented Apr 1, 2014

i won't be working on it, so i'll close this PR to indicate that.

@eleith eleith closed this Apr 1, 2014
@eleith eleith deleted the specify-file-when-passing-in-string branch April 1, 2014 12:25
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.

4 participants