Sourcemapping TypeScript in Karma
Asked Answered
E

1

5

I'm trying to set up a build process for TypeScript using Webpack. Everything's working fine for most parts. However I can't get source-maps to work properly in the Karma test runner.

Problem description

Let's say I have a typescript file test.spec.ts (1). This file is transpiled by TypeScript to some ES5 source with inline source-maps (2). Finally that ES5 source is bundled by Webpack 4 using eval-source-maps (3) and served to Chrome by the Karma test runner.

By inspecting sources in the Karma Debug Runner in Chrome I can see that all three stages of transpilation are actually available to the browser:

  • (1) is source-mapped as webpack://test.spec.ts?c161
  • (2) is source-mapped as webpack-internal://test.spec.ts
  • (3) is available as localhost:9876/base/test.spec.ts

In the Chrome console I also get proper stack traces for all errors thrown during test execution. These include line numbers source-mapped to (1) as I would expect. For example:

Error: Oh no!
    at Function.MyClass.myBadMethod (test.spec.ts?c161:9)
    at UserContext.eval (test.spec.ts?c161:21)
    at <Jasmine>

However Karma itself logs errors with line numbers only source-mapped to (2). For example:

Error: Oh no!
    at Function.MyClass.myBadMethod (webpack-internal:///./src/test.spec.ts:8:15)
    at UserContext.eval (webpack-internal:///./src/test.spec.ts:17:17)
    at <Jasmine>

This is totally unhelpful, since (2) is just some intermediary source and never even written to disk. In fact I don't need source-maps for (2) and don't understand why they are included in the first place. If possible I would like to try and disable them (while keeping proper source-maps for (1), of course).

Anyways, the important thing is to get Karma to report stack traces with line numbers relative to the original files, just as it is done in the Chrome console. If necessary I'm also willing to trade execution speed for that

If you can't think of a full-fledged solution, but have some insights into TypeScript / TS-Loader / Webpack / Karma-Webpack / Karma: I'm also interested in any arguments that help pinpoint the problem along that toolchain.

Minimal test configuration

devDependencies from package.json

"devDependencies": {
    "@types/jasmine": "~2.8.7",
    "jasmine": "~3.1.0",
    "karma": "~2.0.2",
    "karma-chrome-launcher": "~2.2.0",
    "karma-jasmine": "~1.1.2",
    "karma-webpack": "~3.0.0",
    "ts-loader": "~4.3.0",
    "typescript": "~2.8.3",
    "webpack": "~4.8.3"
}

karma.conf.js

module.exports = function(config) {
    config.set({
        frameworks: ['jasmine'],
        browsers: ['Chrome'],
        files: [
            './test.spec.ts'
        ],
        mime: {
            'text/x-typescript': ['ts']
        },
        preprocessors: {
            '**/*.ts': ['webpack']
        },
        plugins: [
            'karma-chrome-launcher',
            'karma-jasmine',
            'karma-webpack'
        ],
        webpack: {
            devtool: 'eval-source-map',
            mode: 'development',
            module: {
                rules: [
                    {
                        test: /\.ts$/,
                        loader: 'ts-loader',
                    }
                ]
            },
            resolve: {
                extensions: [ '.ts' ]
            }
        },
        webpackMiddleware: {
            logLevel: 'error'
        }
    });
};

tsconfig.json

{
    "compileOnSave": false,
    "compilerOptions": {
        "module": "es2015",
        "moduleResolution": "node",
        "sourceMap": true,
        "target": "es5",
        "types": [
        "jasmine"
        ]
    }
}
Eugene answered 16/5, 2018 at 15:4 Comment(0)
E
11

Figuring this out was rather tedious. A couple of problems come together here:

  1. webpack-internal:// source maps were added as a workaround to an unnamed Chrome bug with eval-type source maps. It seems that other browsers like the Karma launcher (and also Firefox) are still unable to interpret the eval-type source maps and therefore fall back to webpack-internal://. In order to get proper source-map support in those browsers you need to use classic source maps like devtool: inline-source-map. This also eliminates the webpack-internal:// source maps altogether.
  2. When transpiling .ts files with karma-webpack no source-maps are generated still. That's because karma-webpack by default outputs files with their original file name. And devtool: inline-source-map sets a filter to only build source-maps for .css and .js output files. This can be salvaged by configuring the SourceMapDevToolPlugin explicitly and providing a test regex that includes .ts files.
  3. Once you replace the devtool setting by a SourceMapDevtoolPlugin only webpack:// source-maps are generated, but these are still wrong in development mode. That's because in this mode devtool: eval is added automatically to the config. To disable this behavior, you have to explicitly set devtool: false.
  4. In order for Karma to load inline source maps, you need to apply the karma-sourcemap-loader.

Putting all this together, the configuration from the question can be fixed as follows:

module.exports = function(config) {
    config.set({
        frameworks: ['jasmine'],
        browsers: ['Chrome'],
        files: [
            './test.spec.ts'
        ],
        mime: {
            'text/x-typescript': ['ts']
        },
        preprocessors: {
            '**/*.ts': ['webpack', 'sourcemap']
        },
        plugins: [
            'karma-chrome-launcher',
            'karma-jasmine',
            'karma-sourcemap-loader',
            'karma-webpack'
        ],
        webpack: {
            devtool: false,
            mode: 'development',
            module: {
                rules: [
                    {
                        test: /\.ts$/,
                        loader: 'ts-loader',
                    }
                ]
            },
            plugins: [
                new webpack.SourceMapDevToolPlugin({
                    test: /\.(ts|js|css)($|\?)/i
                })
            ],
            resolve: {
                extensions: [ '.ts' ]
            }
        },
        webpackMiddleware: {
            logLevel: 'error'
        }
    });
};
Eugene answered 16/7, 2018 at 15:44 Comment(1)
I have the same problem. It looks-wise. But it does not work. IN my case Karma reports stack of an error I see that the source maps work but the stack is not formatted correctly. I do not need webpack stack of messages.Favela

© 2022 - 2024 — McMap. All rights reserved.