Source maps in Node.js

Supporting the many flavors of JavaScript

Contributed by Benjamin Coe, who works on JavaScript client libraries at Google, is a collaborator on Node.js, and was the third engineer at npm, Inc.

Photo by Soloman Soh from Pexels
enum HttpStatusCode {
NOT_FOUND = 404,
ERROR = 500
}
class MyHttpError extends Error {
code: HttpStatusCode;
constructor(msg: string, code: HttpStatusCode) {
super(msg);
Error.captureStackTrace(this, MyHttpError);
this.code = code;
}
}
throw new MyHttpError('not found', HttpStatusCode.NOT_FOUND);
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var HttpStatusCode;
(function (HttpStatusCode) {
HttpStatusCode[HttpStatusCode["NOT_FOUND"] = 404] = "NOT_FOUND";
HttpStatusCode[HttpStatusCode["ERROR"] = 500] = "ERROR";
})(HttpStatusCode || (HttpStatusCode = {}));
var MyHttpError = /** @class */ (function (_super) {
__extends(MyHttpError, _super);
function MyHttpError(msg, code) {
var _this = _super.call(this, msg) || this;
Error.captureStackTrace(_this, MyHttpError);
_this.code = code;
return _this;
}
return MyHttpError;
}(Error));
throw new MyHttpError('not found', HttpStatusCode.NOT_FOUND);
//# sourceMappingURL=test.js.map

The Source Map V3 specification

Source maps provide a method for translating from generated source back to the original, via meta-information attached to the generated source; In JavaScript and CSS Source Map Revision 3 has become the de facto standard. Here are some key facts about the specification:

  • The format trades simplicity and flexibility for a reduced overall size, making it more practical to use source maps in real-world environments, e.g., loading them over a network when DevTools are opened.
  • The format allows for 1 to 1 mappings, e.g., a .ts file mapping to its compiled .js version, and for 1 to many mappings, e.g., many sources being minified into a single source file.
  • Source maps are embedded in the generated source using a special comment. These comments may contain the entire source map, using a Data URI, or may reference an external URL or file.
//# sourceMappingURL=test.js.map

Caching source maps for code coverage

In v12.11.0, the behavior of the environment variable NODE_V8_COVERAGE was updated, such that when a program is run with this variable set, and a require or import observes a special source map comment, the corresponding source map is loaded and cached.

Applying source maps to stack traces

In v12.12.0, Node.js introduced the flag --enable-source-maps. When a program is run with this flag set, source maps will be cached, and used to provide an actionable stack trace when an exception occurs. Let's look at what happens when we execute the TypeScript example in the first section of this article:

Error: not found
at Object.<anonymous> (/Users/bencoe/oss/source-map-testing/test.js:29:7)
-> /Users/bencoe/oss/source-map-testing/test.ts:13:7
at Module._compile (internal/modules/cjs/loader.js:1151:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1171:10)
at Module.load (internal/modules/cjs/loader.js:1000:32)
at Function.Module._load (internal/modules/cjs/loader.js:893:16)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47 {
code: 404
}

How can I use this feature?

You can start using Node.js’ source map functionality today: make sure you have an up-to-date version of Node.js installed, and run your programs with the flag --enable-source-maps.

{
"enable-source-maps": true
}

What’s next

Applying source maps more extensively in Node.js

There are still parts of the Node.js runtime that don’t take into account source-maps, for instance, the logic applied to show an error in its original context:

/Users/bencoe/oss/source-map-testing/test.js:30
throw new MyHttpError('not found', HttpStatusCode.NOT_FOUND);
^

Applying source maps to userland tooling

In v13.7.0 a public API was introduced for interacting with source maps. It's my hope that this can be leveraged by userland tooling, like stack-trace and winston, to provide better support for transpiled code.

Node.js is a collaborative open source project dedicated to building and supporting the Node.js platform. https://nodejs.org/en/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store