TypeScript is a great language choice when you're writing a large server-side Node.js project such as a universal React+Redux web application. However, debugging errors is challenging if you're not set up for it properly.
Take an error call stack, for example...
An Insane Call Stack
This is what TypeScript server-side errors can look like (without source map support):
Error: Big scary error message
at Object.defineProperty.value (D:\BitBucket\Project\dist\server.js:2:8875)
at t (D:\BitBucket\Project\dist\server.js:1:163)
at Object.defineProperty.value (D:\BitBucket\Project\dist\server.js:22:2851)
at t (D:\BitBucket\Project\dist\server.js:1:163)
at Object.e.exports (D:\BitBucket\Project\dist\server.js:30:27387)
at t (D:\BitBucket\Project\dist\server.js:1:163)
at Object.anonymous (D:\BitBucket\Project\dist\server.js:21:29025)
at t (D:\BitBucket\Project\dist\server.js:1:163)
Oh, I have an error on line 2... at column 8875 of a minified JavaScript bundle.
Thanks, log file.
A Sane Call Stack
Once you have source map support enabled, the stack traces show you real line and column numbers from your actual source files. It's almost like being back in C#. Almost.
This is what TypeScript server-side errors look like with source map support enabled:
Error: Big scary error message
at Object.defineProperty.value (...\src\app\reducers\sessionReducer.ts:9:37)
at __webpack_require__ (...\webpack\bootstrap af0efb5a57f02f296438:19:1)
at Object.defineProperty.value (...\src\app\reducers\appReducer.ts:4:26)
at __webpack_require__ (...\webpack\bootstrap af0efb5a57f02f296438:19:1)
at Object.module.exports (...\src\server\webRequestHandler.ts:5:22)
at __webpack_require__ (...\webpack\bootstrap af0efb5a57f02f296438:19:1)
at Object. (...\src\server\webServer.ts:8:29)
at __webpack_require__ (...\webpack\bootstrap af0efb5a57f02f296438:19:1)
Oh, okay. Hello… error on line 9 of sessionReducer.ts
.
FIXED
How do we do it? Simple, with webpack.BannerPlugin
.
Banner Plugin to the Rescue
Webpack includes a plugin called BannerPlugin that allows you to insert content at the beginning of a bundle. I think it's intended for things like copyright and license statements (you'd never know, though, because the documentation is... sparse).
Fortunately, we can also use it to inject a require statement to setup source map support.
First, add the source-map-support package to your project
npm install --save source-map-support
Then update the webpack configuration for your server bundle to include the BannerPlugin as follows:
Webpack v1.x
module.exports = { devtool: 'source-map', plugins: [ new webpack.BannerPlugin( 'require("source-map-support").install();', { raw: true, entryOnly: false } ), ],};
Webpack v2.x
(BannerPlugin had a breaking change from v1 to v2)
module.exports = { devtool: 'source-map', plugins: [ new webpack.BannerPlugin({ banner: 'require("source-map-support").install();', raw: true, entryOnly: false }), ],};
Good luck with your debugging!