Giới thiệu về Source Maps

Giới thiệu về Source Maps
Photo by Pankaj Patel from Unsplash

Trong quá trình phát triển Web, với các công việc liên quan đến front-end, ví dụ như code CSS, JS, có thể bạn sẽ dùng đến một số preprocessor như SASS, CoffeeScript,… cũng như các công cụ để gộp và nén file. Nhưng khi bạn muốn debug code của những file kết quả đã được biên dịch đó, bạn sẽ phải làm thế nào đây? Nó có thể sẽ là một thảm họa nếu không có sự giúp đỡ của source map.

Source map cung cấp cho chúng ta một ánh xạ của code đã biên dịch với mã nguồn ban đầu của nó. Có nghĩa là, với source map (cùng sự giúp đỡ của các công cụ hỗ trợ), chúng ta sẽ dễ dàng debug ứng dụng ngay cả khi CSS, JS của nó đã được biên dịch và tối ưu hóa. Hiện nay, phần lớn các trình duyệt hiện đại như Chrome và Firefox đều tích hợp sẵn công cụ để làm việc với source map.

Trong bài viết này, chúng ta sẽ tìm hiểu cách thức làm việc của source map và cách để thêm chúng vào dự án của chúng ta. Trong nội dung bài viết này, tôi sẽ tập trung vào source map cho CSS, source map cho JavaScript cũng tương tự như vậy.

Source maps giúp chúng ta như thế nào?

Giả sử bạn dùng SASS (SCSS) cho dự án của mình, và dùng các công cụ tương ứng để biên dịch và tối ưu hóa code CSS. Bạn có một file chính và file này import các file khác. Kết quả sau khi biên dịch bạn có một file css và đương nhiên là nó hoạt động tốt. Nhưng nếu bạn kiểm tra các phần tử HTML để xem code CSS nào được áp dụng cho phần tử đó thì bạn sẽ thu được kết quả như dưới đây:

inspect without source map

Như bạn thấy đó, tất cả CSS được áp dụng cho phần tử hiện tại đều được chỉ ra là đến từ một file duy nhất (app.css), đây là file sau khi biên dịch rồi. Và với thông tin như vậy, bạn không thể nào biết được, code SCSS tương ứng là ở đâu và nếu cần sửa thì việc tìm ra vị trí mã nguồn để sửa cũng là một công việc chẳng dễ dàng gì.

Tuy nhiên, nếu thêm source map vào trong quá trình biên dịch, chúng ta sẽ có thêm một số thông tin mà khi kiểm tra phần tử sẽ được như thế này:

inspect with source map

Việc debug đã dễ hơn rất nhiều, chúng ta thấy được rằng, một số CSS áp dụng cho phần tử hiện tại đến từ file _countdown.scss trong khi một số khác đến từ _basics.scss. Thậm chí, chúng ta còn có thể xem cả mã nguồn SCSS của chính những file này:

source file content

Vậy đó, rõ ràng source map đã giúp công việc debug của chúng ta trở nên rất dễ dàng và nhàn hạ.

Source maps làm việc như thế nào?

Như tên của chính nó, source map có chứa một số thông tin dùng để ánh xạ code đã biên dịch và mã nguồn gốc của nó. Bạn có thể chỉ định source map cho từng file. Bạn có thể chỉ cho trình duyệt biết source map của một file ở đâu bằng cách thêm một comment đặc biệt như sau vào cuối file:

/*# sourceMappingURL=app.css.map */

Thông thường, các công cụ hỗ trợ tạo source map sẽ giúp chúng ta thêm comment như trên. Các trình duyệt với công cụ hỗ trợ source map được tích hợp sẵn sẽ load dữ liệu từ file source map tương ứng và hiển thị kết quả giúp chúng ta.

Ngoài ra, bạn cũng có thể chỉ source map bằng cách sử dụng HTTP header X-SourceMap trong kết quả trả về khi request các file:

X-SourceMap: /path/to/app.css.map

File source map thực ra một file JSON có chứa một vài metadata về chính file source map đó và các dữ liệu để ánh xạ code biên dịch với mã nguồn của nó. Dưới đây là một ví dụ về file source map:

{
    "version": 3,
    "sources": [
      "app.scss",
      "_normalize.scss",
      "app.css",
      "_basics.scss",
      "_countdown.scss",
      "_others.scss",
    ],
    "names": [],
    "mappings": "AAAA;;;;;;GAMG;ACFH;EACI,wBAAwB;EACxB,2BAA2B;...",
    "file": "app.css",
    "sourcesContent":["// normalize.css v4.0.0 |..."],
    "sourceRoot": "/source/"
}

Source map sẽ có một số thông tin như sau:

  • version: đây là thông tin về phiên bản dùng để định dạng file source map
  • sources: một danh sách các URL của các file mã nguồn
  • names: một danh sách các biến và tên hàm trong mã nguồn
  • mappings: xâu đã mã hóa Base64 VLQ. Đây chính là dữ liệu dùng để ánh xạ code đã biên dịch với mã nguồn của nó. Và đây cũng chính là nơi mà mọi điều kỳ diệu bắt đầu.
  • file: tên của file source map
  • sourceRoot (có thể có hoặc không) chứa thông tin về nơi lưu trữ các file sources
  • sourceContent (có thể có hoặc không) lưu trữ mã nguồn của chính các file gốc. Đây là nội dung rất cần thiết khi chúng ta không upload các file mã nguồn (do đó trình duyệt không thể load được)

Để hiểu rõ hơn về đặc tả kỹ thuật của source map, bạn có thể tham khảo thêm tài liệu này

Thêm source map cho dự án

Nếu bạn sử dụng grunt, thì các task dùng để biên dịch SASS như grunt-contrib-sass đã tích hợp sẵn công cụ tạo source map, bạn chỉ cần cấu hình nó cho phù hợp với nhu cầu là đủ:

sass: {
    dist: {
        options: {
            sourcemap: 'inline'
        },
        files: {
            'app.css': 'app.scss'
        }
    }
}

Tương tự, các công cụ tối ưu hóa JavaScript cũng tích hợp sẵn công cụ tạo source map. Ví dụ với grunt-contrib-uglify:

uglify: {
    dist: {
        options: {
            sourceMap: true
        },
        files: {
            'dest/output.min.js': ['src/input.js'],
        }
    }
}

Nếu bạn sử dụng gulp, công cụ biên dịch SCSS chưa tích hợp công cụ tạo source map, nên bạn cần thêm gulp-sourcemap để sử dụng:

var sourcemaps = require('gulp-sourcemaps');

gulp.task('stylesheet', () => {
    return gulp
        .src(config.src.css)
        .pipe(sourcemaps.init())
        .pipe(sass())
        .pipe(autoprefixer(config.autoprefixer))
        .pipe(cssmin())
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(config.dest.css));
});

Một vài lưu ý rằng, có những công cụ để tối ưu hóa code CSS như gulp-shorthand, gulp-combine-mq không tương thích với source map và sẽ phá vỡ ánh xạ mà source map cung cấp.

Kết luận

Sử dụng source map cho phép các nhà phát triển dễ dàng debug và maintain ứng dụng trong khi vẫn có thể tối ưu hóa code CSS, JS để nâng cao hiệu suất của trang Web. Trong bài viết này, chúng ta đã tìm hiểu cách source map làm việc và lợi ích của nó, cũng như cách thêm source map vào dự án. Thực sự, việc tích hợp source map vào dự án là một việc không mất nhiều thời gian nhưng rất có giá trị.

Tôi xin lỗi nếu bài viết có bất kỳ typo nào. Nếu bạn nhận thấy điều gì bất thường, xin hãy cho tôi biết.

Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.