Everyone is familiar with Source Map. Most of the code on the line is compressed, so if there is an error on the line and you can only debug that code, it is probably a nightmare. So we need a bridge between the source code and the compressed code, and the Source Map does that.

Here is MDN’s explanation of source map:

It is easier to debug the original source code than the converted code downloaded by the browser. A source map is a file mapped from transformed code to the original source, enabling the browser to refactor the original source and display the reconstructed source in the debugger.

But have you had any questions about how source Map works? I have listed four questions, I do not know whether you have such questions:

These questions will be answered step by step in the following sections.

Whether the source map file affects web page performance

The answer is no, otherwise the optimizations associated with building the source map would definitely involve handling the source Map file, which is not a small file.

Source Map can only be downloaded if dev Tools is opened, which is probably not a problem for most users.

The reader might be thinking: hey, but I never see the Source map file load in the Network? This is hidden from the browser, but if you use the package capture tool you will see that the source map starts downloading when you open dev Tools.

Is there a standard for source map?

Source Map is a standard document address for Google and Mozilla engineers. Because of this standard, packers and browsers can generate and use source maps that would otherwise be out of order.

Each packer basically generates the source map based on this library. Of course, there are some magic schemes, but the standard is the same.

The format of the source map generated from the above library is roughly as follows, and you can also compare the products of each packer. The format and content are mostly the same:

{
  version: 3,
  file: "min.js",
  names: ["bar"."baz"."n"],
  sources: ["one.js"."two.js"],
  sourceRoot: "http://example.com/www/js/",
  mappings: "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID; CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA"
}
Copy the code

Next, I will introduce the functions of important fields:

  • Version: as the name implies, refers to the version number. The current version of the Source Map standard is 3, which means that this source map is produced using the third version of the standard
  • File: indicates the compiled file name
  • Names: An optimized field that will be used later in mappings
  • Sources: multiple source file names
  • Mappings: This is the most important thing and represents the relationship between source and compiled code, but skip this for now and will be explained in more detail below

In addition, most applications are packaged by WebPack, and some readers may notice that the fields produced by WebPack’s Source map are slightly inconsistent with those above.

This is because WebPack has changed some things, but the bottom is still based on the library implementation, just changed some fields that do not involve the core, specific code.

How does the browser know the relationship between source files and source maps?

Here we use Webpack as an experiment, using Webpack5 to package the following code:

// index.js
const a = 1
console.log(a);
Copy the code

When we enable the Source map option, the output should be two files, bundle.js and bundle.js.map.

When we look at the bundle.js file, we’ll find this comment in the code:

console.log(1);
//# sourceMappingURL=bundle.js.map
Copy the code

SourceMappingURL is the sourceMap address that marks the file.

Of course, there are other ways, which can also be indicated by the SourceMap: < URL > field of the Response Header by consulting the MDN documentation.

How does the Source map correspond to the source code?

This is the core function of The Source Map, and it is also the most knowledge blind area.

You may remember the mapping field that we didn’t cover above, but let’s look at its use in more detail.

Using the example of the file we just packed, let’s see what the resulting source map looks like (minus the irrelevant ones) :

{
  sources:["webpack://webpack-source-demo/./src/index.js"],
  names: ['console', 'log'],
  mappings: 'AACAA,QAAQC,IADE',
}
Copy the code

First, the “mappings” content is actually an encoded representation of Base64 VLQ.

The content consists of three parts:

  • Location association of source code and compressed code
  • Comma, which separates the contents of a line of code. For instanceconsole.log(a)Just byconsolelogaThree parts, so there are two commas.
  • A semicolon represents a line break

Commas and semicolons are no problem, but they should be confusing.

In fact, this is a way to compress the digital content of the code, after all, the source can be very large, the number of lines and columns in the source map file will be very large, so Base 64 is chosen to represent the number to reduce the size of the file.

For example, A represents the number 0, C represents the number 1, etc. Interested readers can learn about the mapping through the website.

Now that we know the mapping of this code, let’s talk about what this string of English really stands for.

Each string of letters in English actually represents a position:

  1. The number of columns in the compressed code
  2. Which source code file, after all, can be multiple files packaged into one, correspondingsourcesfield
  3. Line of the source code
  4. Source code column
  5. namesThe index in the field

At this point, the reader may be wondering why the code is not compressed lines of representation. This is because the compressed code is one line, so you only need to represent the columns.


Update: A reader asked if Base64 has an upper limit on the number it can represent, and what to do if the number you need to represent is large. In fact, except for the fact that the first string of each semicolon is used to indicate the absolute position of the line and column of the code, the rest of the semicolon is added and subtracted relative to the previous position.


AACAA corresponds to [0,0,1,0,0], which needs to be noted is that the number starts from 0, the author will automatically add one when the expression, after all, the code line zero sounds strange.

  1. Compress the first column of the code
  2. The first source code file, which isindex.jsThe file
  3. Second line of source code
  4. The first column of the source code
  5. namesThe first index in the array, which isconsole

With the above parsing, we can see where the console is in the source code and the zip file.

But why does the Source Map know exactly where the compiled code is? This is where the AST comes in. Let’s go to the website and type console.log(a) and look at what’s on the right. You should see something like this:

Since the Source map is produced by the AST, we can use this data in the AST.

Source Map application

Generally speaking, the source Map application is in the monitoring system. After the developer builds the application, the source code and Source Map are uploaded to the platform through the plug-in. Once an error is reported by the client, we can restore the error location of the source code through the library (see the documentation for the specific API), so that developers can quickly locate online problems.

The last

Source Map is something we often use in our daily life, but we didn’t realize there were so many blind spots involved until we learned this content.

If you have any questions, please feel free to share them in the comments section.