How to use sourcemaps to restore the original file?
Asked Answered
W

4

29

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?

Wills answered 3/9, 2015 at 19:23 Comment(0)
L
17

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.

Lastex answered 3/9, 2015 at 19:38 Comment(3)
I think the most basic way is to use Mozilla source-map package, github.com/mozilla/source-map/#consuming-a-source-map, e.g. sourcemap.SourceMapConsumer(map).sourcesContent[0]. Consider adding that to your answer .Wills
@GajusKuizinas there is absolutely no need to use the source-map package for this task. JSON.parse(map).sourcesContent[0] would do the same thing.Lastex
Did not realise that. Thank you.Wills
R
7

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.

Rate answered 18/6, 2022 at 11:48 Comment(0)
P
5

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);
  });
});
Piggery answered 31/3, 2021 at 16:30 Comment(0)
S
0

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);

Speight answered 11/3, 2022 at 11:26 Comment(1)
working on: /root/app/service.js.map /root/index.js:15 jsonContent.sourcesContent[index], ^ TypeError: Cannot read properties of undefined (reading '0') at /root/index.js:15:35 ` at Array.forEach (<anonymous>)` ` at parseIfMap (/root/index.js:8:25)` ` at /root/index.js:36:11 at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3)Zulemazullo

© 2022 - 2024 — McMap. All rights reserved.