Gajus
Gajus

Reputation: 73808

How to use sourcemaps to restore the original file?

I have a file that has been transpiled from ES6 to ES5 using Babel. I have sourcemap. I am assuming I can restore the original file (the way it looked when written in ES6) using these resources.

How is it done?

Is there a CLI tool to do this?

Upvotes: 30

Views: 33264

Answers (5)

1mike12
1mike12

Reputation: 3441

Although the question asks for restoring a single file, I think the original poster meant one minified file, with one sourcemap, which will almost certainly remap back to many individual files with possibly nested hierarchies as any webapp using webpack would be structured.

My use case is to extract the sources onto the filesystem so that I can view it in my IDE.

The only method I've found that can recreate the entire project structure is with this plugin: https://chromewebstore.google.com/detail/save-all-resources/abpdnfjocnmdomablahdcfnoggeeiedb?hl=en

It ends up saving a zip file with all resources, not just js /ts but it's easy enough to ignore those.

Upvotes: 0

Benedikt Köppel
Benedikt Köppel

Reputation: 5109

There's a nice web service to do that: http://sokra.github.io/source-map-visualization/

  • Click on "Custom"
  • Select your *.js file
  • Select the corresponding *.js.map file
  • Browse the non-minified code on the right

There might be a lot of noise from webpack:///node_modules/ modules that you're probably not interested in. You can try to find the I found that simply searching for webpack:///src usually brings up the actual source code within the whole snippet.

Upvotes: 7

Amir Heshmati
Amir Heshmati

Reputation: 648

i wrote a script as well that came handy to me. I'll share it here it might come handy to someone this script assumes that the .map.(js|css) has a structure like

{
    "version": 3,
    "file": "static/js/15.80b7f5e4.chunk.js",
    "mappings": "iOAkCA,UAzBqB",
    "sources": [
        "path/to/afile.js"
    ],
    "sourcesContent": [
        "content of the file"
    ],
    "names": [
        "post",
        "useState"
    ],
    "sourceRoot": ""
}

thou i didn't make use of names and mapping entry on the map file i just mapped sources with sourceContent and recreated the file structure.

const fs = require("fs");
const path = require("path");

function parseIfMap(filePath, content) {
  console.log("working on:", filePath);
  if (filePath.includes(".map")) {
    const jsonContent = JSON.parse(content);
    jsonContent.sources.forEach(function (value, index) {
      const parsed = path.parse(value);
      if (parsed.dir) {
        fs.mkdirSync(parsed.dir, { recursive: true });
      }
      fs.writeFile(
        value,
        jsonContent.sourcesContent[index],
        (path) => path && console.log(value, path)
      );
    });
  }
}

function readFiles(dirname, onError) {
  fs.readdir(dirname, function (err, filenames) {
    if (err) {
      onError(dirname, err);
      return;
    }
    filenames.forEach(function (filename) {
      const filePath = dirname + path.sep + filename;
      if (fs.lstatSync(filePath).isFile()) {
        fs.readFile(filePath, "utf-8", function (err, content) {
          if (err) {
            onError(err);
            return;
          }
          parseIfMap(filePath, content);
        });
      } else {
        readFiles(filePath, parseIfMap, onError);
      }
    });
  });
}
// change with you own file path
readFiles("static", console.log);

Upvotes: 1

Dmitri
Dmitri

Reputation: 3561

Very simple NodeJS implementation which I wrote for my needs.

const fs = require('fs');
const { SourceMapConsumer } = require("source-map");

fs.readFile('./example.js', 'utf8' , (err, data) => {
  if (err) return console.error(err);

  const sourceMapData = data.split('//# sourceMappingURL=data:application/json;base64,')[1];
  let buff = new Buffer.from(sourceMapData, 'base64');
  let rawSourceMap = buff.toString('ascii');

  const parsed = SourceMapConsumer(rawSourceMap);

  fs.writeFile('example.ts', parsed.sourcesContent, function (err) {
    if (err) return console.log(err);
  });
});

Upvotes: 5

lydell
lydell

Reputation: 1137

Open up the source map in a text editor, and you’ll see that it’s mostly just a simple JSON object. The “sources” field contains an array of URLs/paths to all source files, which can help you to find them. There is also an optional “sourcesContent” field, which also is an array, where each item contains the contents of the file at the same index in the “sources” array; if so, you could find the original code right in the source map.

A CLI tool? Well, there’s source-map-visualize which tries to find all original sources and pre-loads them into this online source map visualization.

Upvotes: 17

Related Questions