typescriptwebpackvisual-studio-codesource-maps

Debugger breakpoint incorrect line. Webpack configuration typescript


I finally got typescript working in my project, but the breakpoints do not stop in the correct line, and the variable values are not available until you step into some more lines of code in the step by step execution. There seems to be some ttype if mismatch in the source map. I tried to solve this adding tje SourceMapDevToolPlugin to the webpack config file as intructed here. But doesn't solve the problem.

Below screenshots of what I mean:

enter image description here

myString is undefine, although the line has supposedly beed executed.

enter image description here

After it jumps directly to the function (not to the const myNumber = myFunc(5); where the function is called) and the value of the string is availabe, so this is so weird.

Below my webpack config, launch.json and tsconfig.

webpack config:

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const SourceMapDevToolPlugin = require('');

const modulesPath = path.resolve(__dirname, 'node_modules');
const srcPath = path.resolve(__dirname, 'src');
const outputPath = path.resolve(__dirname, 'dist');

const basename = process.env.BASENAME || '/';
const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development';

module.exports = {
  mode,
  devtool: 'inline-source-map',
  devServer: {
    hot: true,
    historyApiFallback: true,
    port: 3000,
    stats: 'minimal',
  },
  entry: [
    path.join(srcPath, 'index.css'),
    path.join(srcPath, './trial.ts'),
  ],
  output: {
    path: outputPath,
    publicPath: basename,
  },
  resolve: {
    alias: {
      '@': srcPath,
    },
    extensions: ['.tsx', '.ts', '.js', '.js', '.json'],
  },
  module: {
    rules: [
      ...(mode === 'development' ? [
        {
          test: /\.(js)$/,
          enforce: 'pre',
          loader: 'eslint-loader',
          options: {
            emitWarning: true,
          },
          include: srcPath,
          exclude: modulesPath,
        },
      ] : []),
      {
        test: /\.(js)$/,
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', { modules: false }],
          ],
        },
        include: srcPath,
        exclude: modulesPath,
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: { sourceMap: true },
          },
        ],
        include: [srcPath, modulesPath],
      },
      {
        test: /\.(vert|frag)$/,
        loader: 'raw-loader',
        include: srcPath,
        exclude: modulesPath,
      },
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: modulesPath,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(srcPath, 'index.ejs'),
      title: 'WebGL boilerplate',
      favicon: './favicon.ico',
    }),
    new MiniCssExtractPlugin(),
    ...(mode !== 'production' ? [
      new webpack.NamedModulesPlugin(),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.EvalSourceMapDevToolPlugin({
        moduleFilenameTemplate: (info) => (
          `file:///${info.absoluteResourcePath}`
        ),
      }),
    ] : []),
    new webpack.SourceMapDevToolPlugin({
      filename: null,
      exclude: [/node_modules/],
      test: /\.ts($|\?)/i,
    }),
  ],
};

launch.json:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome",
            "url": "http://localhost:3000",
            "webRoot": "${workspaceFolder}/src",
            // "preLaunchTask": "tsc",
            "sourceMaps": true,
            "sourceMapPathOverrides":{
                "webpack:///./*": "${webRoot}/*",
                "webpack:///src/*": "${webRoot}/*",
                "webpack:///*": "*",
                "webpack:///./~/*": "${webRoot}/node_modules/*",
                "meteor://💻app/*": "${webRoot}/*"
            }
        }
    ]
}

tsconfig:

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Basic Options */
    // "incremental": true,                   /* Enable incremental compilation */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "inlineSourceMap": true,                  /* Emit a single file with source maps instead of having a separate file. */
    "inlineSources": true,                    /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Advanced Options */
    "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
    "outDir": "./src/ts-built/",
    "rootDir": "./src/"
  }
}

Note that // "preLaunchTask": "tsc"; is commented. That is the prelaunch task that compiles the typescript files, however, onced I configured webpack and tsc to work with the 'inline-source-map' mode, even the .js compiled file the prelaunchtask commented, the app will run, with brakpoints in the typescript file (with weird behaviour an line mismatch).

So I dont know what I am missing in the inline-source-map mode configuration, or if It should be used the normal 'souceMAps': true mode, where sourcemaps are generated on the typescript files compilation.

Many thanks in advance for any help.


Solution

  • I changed my tsconfig to sourceMap: true; mode and that fixed the issue. Below the corrected tsconfig:

    {
      "compilerOptions": {
        /* Visit https://aka.ms/tsconfig.json to read more about this file */
    
        /* Basic Options */
        // "incremental": true,                   /* Enable incremental compilation */
        "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
        "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
        "strict": true,                           /* Enable all strict type-checking options. */
        "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
        //"inlineSourceMap": true,                  /* Emit a single file with source maps instead of having a separate file. */
        //"inlineSources": true,                    /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
        "sourceMap": true,
        /* Advanced Options */
        "skipLibCheck": true,                     /* Skip type checking of declaration files. */
        "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
        "outDir": "./src/ts-built",
        "rootDir": "./src"
      }
    }
    

    As far as I researched, I think I get how the "sourceMap": true mode works.

    1. The .map generated file by the tsc compiler is used to map the compiled .js to the .ts file on debugging.
    2. It seems that the //"inlineSourceMap": true, and //"inlineSources": true, get the source map from the text generated at the end of the .js file instead of the separted .map file, and that mode is the one I expected to work as the name of the devtool in the webpack config is 'inline-source-map'.

    I don't know if both modes can be used in webpack, as long as one of the two works that is fine. However if only the NO inline mode works, and the devtool name is 'inline-source-map', I find that quite misleading.

    Thanks for any explanatory comments on this regard.