Search code examples
csssasssource-maps

How to interpret source map mappings?


Let's say I have this stylesheet:

.d1
    width: 10px
    .d2
        width: 20px

It results in the following css code (with nested output style):

.d1 {
  width: 10px; }
  .d1 .d2 {
    width: 20px; }

Source map (v3) contains the following mappings:

AAAA,AAAA,GAAG,CAAC;EACA,KAAK,EAAE,IAAK,GAES;EAHzB,AAEI,GAFD,CAEC,GAAG,CAAC;IACA,KAAK,EAAE,IAAK,GAAG

After decoding it with this service, I got:

([0,0](#0)=>[0,0]) | ([0,0](#0)=>[0,0]) | ([0,3](#0)=>[0,3]) | ([0,4](#0)=>[0,4])
([1,4](#0)=>[1,2]) | ([1,9](#0)=>[1,7]) | ([1,11](#0)=>[1,9]) | ([1,16](#0)=>[1,13]) | ([3,25](#0)=>[1,16])
([0,0](#0)=>[2,2]) | ([2,4](#0)=>[2,2]) | ([0,3](#0)=>[2,5]) | ([2,4](#0)=>[2,6]) | ([2,7](#0)=>[2,9]) | ([2,8](#0)=>[2,10])
([3,8](#0)=>[3,4]) | ([3,13](#0)=>[3,9]) | ([3,15](#0)=>[3,11]) | ([3,20](#0)=>[3,15]) | ([3,23](#0)=>[3,18])

Source was generated in a similar fashion with node-sass (libsass).

My understaning is that those are pairs of points from original and resulting file. But let's take for example last pair from the second line: ([3,25](#0)=>[1,16]). Row 3 column 25? That's kind of unexpected, don't you think?

Am I doing it wrong? Or source map is incorrect? Can you suggest the way to generate correct source map, if so?


Solution

  • There's a great tool, that you can use not only with libsass as explained here.

    Do note, you need a file with source map embedded as a multiline comment and with sourcesContent field in it, like this one:

    .d1 {
      width: 10px; }
      .d1 .d2 {
        width: 20px; }
    
    /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6IkFBQUEsR0FBSTtFQUNBLEtBQUssRUFBRSxJQUFJO0VBQ1gsT0FBSTtJQUNBLEtBQUssRUFBRSxJQUFJIiwic291cmNlcyI6WyIxLnNjc3MiXSwic291cmNlc0NvbnRlbnQiOlsiLmQxIHtcbiAgICB3aWR0aDogMTBweDtcbiAgICAuZDIge1xuICAgICAgICB3aWR0aDogMjBweDtcbiAgICB9XG59XG4iXSwibmFtZXMiOltdLCJmaWxlIjoiMS5jc3MifQ== */
    

    You just paste it into Output field, click Analyze, and you're all set. It doesn't matter what was in Input field before that. It gets replaced with content from source map. Use arrow keys to switch between mappings.

    Let's examine how you do it with ruby's sass gem:

    Gemfile:

    source 'https://rubygems.org'
    gem 'sass'
    

    package.json:

    {
      "dependencies": {
        "convert-source-map": "^1.3.0"
      }
    }
    

    1.scss:

    .d1 {
        width: 10px;
        .d2 {
            width: 20px;
        }
    }
    

    1.js:

    var convert = require('convert-source-map');
    var fs = require('fs');
    console.log(
        convert.fromJSON(
                fs.readFileSync('1.css.map')
        ).toComment()
        .replace(/^\/\//, '/*')
        .replace(/$/, ' */')
    );
    

    Then

    $ bundle install && npm i
    $ rm -f 1.css* && bundle exec sass --sourcemap=inline 1.scss 1.css
    $ cat 1.css | head -n -1 && node 1.js
    .d1 {
      width: 10px; }
      .d1 .d2 {
        width: 20px; }
    
    /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6IkFBQUEsR0FBSTtFQUNBLEtBQUssRUFBRSxJQUFJO0VBQ1gsT0FBSTtJQUNBLEtBQUssRUFBRSxJQUFJIiwic291cmNlcyI6WyIxLnNjc3MiXSwibmFtZXMiOltdLCJmaWxlIjoiMS5jc3MifQ== */
    

    Put it into Output field and that's it.

    The workflow is a bit involved. But that's far more painless way to inspect source maps, then doing it "by hand." I'm talking from my own experience here :)

    In case, you've got source map as json, like:

    { version: 3,
      sourceRoot: '/path/to/dir',
      sources: [ '1.css' ],
      sourcesContent: [ 'body {\n    background: #ddd;\n}\ndiv {\n    width: 100px;\n    height: 100px;\n    margin: auto;\n    background: #666;\n}\n' ],
      names: [],
      mappings: 'AAAA,AAAA,IAAI,AAAC,CACD,UAAU,CAAE,IAAI,CACnB,AACD,AAAA,GAAG,AAAC,CACA,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,KAAK,CACb,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,IAAI,CACnB' }
    

    You can convert it into a comment as follows:

    var convertSourceMap = require('convert-source-map')
    console.log(convertSourceMap.fromJSON(mapAsAString).toComment({multiline: true}));
    

    P.S. Here are some more tools. And introduction to source maps. Also, sourcemap-codec package may come in handy.