Open ythy opened 6 years ago
One way to create a source map would be to simply store the source location (line, column) that corresponds to each output character’s location.
“feel the force” ⇒ Yoda ⇒ “the force feel”
Output location | Input | Input location | Character |
---|---|---|---|
Line 1, Column 0 | Yoda_input.txt | Line 1, Column 5 | t |
Line 1, Column 1 | Yoda_input.txt | Line 1, Column 6 | h |
Line 1, Column 2 | Yoda_input.txt | Line 1, Column 7 | e |
Line 1, Column 4 | Yoda_input.txt | Line 1, Column 9 | f |
Mappings (283 chars length): 1|0|Yoda_input.txt|1|5, 1|1|Yoda_input.txt|1|6, 1|2|Yoda_input.txt|1|7, 1|4|Yoda_input.txt|1|9, 1|5|Yoda_input.txt|1|10, 1|6|Yoda_input.txt|1|11, 1|7|Yoda_input.txt|1|12, 1|8|Yoda_input.txt|1|13, 1|10|Yoda_input.txt|1|0, 1|11|Yoda_input.txt|1|1, 1|12|Yoda_input.txt|1|2, 1|13|Yoda_input.txt|1|3
1. Improvement: Don’t write output line number each time. Use ‘;’ to indicate a line change
Because in many cases the output is condensed into fewer lines than the input (minified JavaScript for example), not having to write the output line location for each entry results in great space savings. The same table we had before can now be encoded as follows:
Mappings (245 chars length): 0|Yoda_input.txt|1|5, 1|Yoda_input.txt|1|6, 2|Yoda_input.txt|1|7, 4|Yoda_input.txt|1|9, 5|Yoda_input.txt|1|10, 6|Yoda_input.txt|1|11, 7|Yoda_input.txt|1|12, 8|Yoda_input.txt|1|13, 10|Yoda_input.txt|1|0, 11|Yoda_input.txt|1|1, 12|Yoda_input.txt|1|2, 13|Yoda_input.txt|1|3;
2. Improvement: Table of names and inputs, referencing by indexes
Index | Input |
---|---|
0 | Yoda_input.txt |
Index | Name |
---|---|
0 | the |
1 | force |
2 | feel |
Output location | Input index | Input location | Name index |
---|---|---|---|
Line 1, Column 0 | 0 | Line 1, Column 5 | 0 |
Line 1, Column 4 | 0 | Line 1, Column 9 | 1 |
Line 1, Column 10 | 0 | Line 1, Column 0 | 2 |
Now this can be encoded as:
Inputs: Yoda_input.txt Names: the,force,feel Mappings (31 chars length): 0|0|1|5|0, 4|0|1|9|1, 10|0|1|0|2;
The way we try to make most of the numbers smaller is by using relative offsets. Looking at the first column of the previous table, here’s what relative offsets mean:
Output location | Input index | Input location | Name index |
---|---|---|---|
Line 1, Column 0 | 0 | Line 1, Column 5 | 0 |
Line 1, Column +4 | +0 | Line 1, Column +4 | +1 |
Line 1, Column +6 | +0 | Line 1, Column -9 | +1 |
And this can now be encoded as:
Inputs: Yoda_input.txt Names: the,force,feel Mappings (31 chars length): 0|0|1|5|0, 4|0|1|4|1, 6|0|1|-9|1;
with VLQ all you have to do is add an indicator to digits to indicate that the number still has more digits. Let’s encode the following numbers using VLQ:
1|23|456|7
Using an underline as our indicator that a number has more digits (the continuation indicator):
12_34_5_67
Here’s how to read this:
we will use binary groups made of 6 bits (for a total of 64 possible values),
First binary group (4 bits for value):
B5 B4 B3 B2 B1 B0
B5: continuation indicator
B0: sign indicator
B1 - B4: value
Continuation binary group (5 bits for value): B5 B4 B3 B2 B1 B0 B5: continuation indicator B0 - B4: value
###### example
Encoding decimal 456:
The corresponding binary value takes up 9 bits (111001000), so it doesn’t fit in the first binary group and therefore requires a continuation. We will put the 4 least-significant bits in the first group (1000) and leave the rest (11100) for the continuation group.
B5 B4 B3 B2 B1 B0 B5 B4 B3 B2 B1 B0 1 1 0 0 0 0 0 1 1 1 0 0
###### The final binary result
Now all we have to do is concatenate the results we have so far:
000010 101110 000001 110000 011100 001110
###### Base64 encoding
As it turns out, traditional base64 encoding defines an alphabet of 64 characters. Values from 0 – 63 can be encoded as a single character. Well, the initial choice to use 6 bits per binary group was not arbitrary. By using 6 bits per group we can now encode each group as a single character as per the base 64 alphabet. Here’s what we get for the bits above:
CuBwcO
##### Applying VLQ + base64 to the Yoda example
>Inputs: Yoda_input.txt
Names: the,force,feel
Mappings (18 chars length): AACKA, IACIC, MACTC;
[参考](https://blogs.msdn.microsoft.com/davidni/2016/03/14/source-maps-under-the-hood-vlq-base64-and-yoda/)
One of the easiest performance wins you can gain for your website is to combine and compress your JavaScript and CSS files. But what happens when you need to debug the code within those compressed files? It can be a nightmare. Fear not however, there is a solution on the horizon and it goes by the name of source maps.
A source map provides a way of mapping code within a compressed file back to it’s original position in a source file. This means that – with the help of a bit of software – you can easily debug your applications even after your assets have been optimized.
When your source code has gone through transformations, debugging becomes a problem. When debugging in a browser, how to tell where the original code is? Source maps solve this problem by providing a mapping between the original and the transformed source code. In addition to source compiling to JavaScript, this works for styling as well.
How Source Maps Work
As the name suggests, a source map consists of a whole bunch of information that can be used to map the code within a compressed file back to it’s original source. You can specify a different source map for each of your compressed files.
You indicate to the browser that a source map is available by adding a special comment to the bottom of your optimised file.
You can also specify a source map is available by sending the X-SourceMap HTTP header in the response for the compressed JavaScript file. X-SourceMap: /path/to/script.js.map
The source map file contains a JSON object with information about the map itself and the original JavaScript files. Here is a simple example:
Lets take a closer look at each of these properties.
Inline Source Maps and Separate Source Maps
Thanks to their speed, inline source maps are ideal for development. Given they make the bundles big, separate source maps are the preferred solution for production. Separate source maps work during development as well if the performance overhead is acceptable.