Debugging TypeScript Source Files? #240

Closed
joewood opened this Issue May 31, 2016 · 17 comments

Projects

None yet

8 participants

@joewood
joewood commented May 31, 2016

The source map issue has been discussed in the React Native repo a fair bit. The RN packager seems to consume source maps with a custom Transformer see here. My question is, is it possible to set-up the VS Code Extension so that TypeScript source files can be used through the debugger (e.g. set breakpoints etc.)?

If this is possible, could you describe what source map settings need to be used (e.g. inline source maps etc..)?

I'm using 0.1.4 of the React Native Extension with VS code 1.1.1.

@hamiltonia
Member

@joewood we don't currently have a solution for this, we'll need to spend some time looking at it. Currently the team is busy with some non-related work, we'll add this to our backlog and get back to it when we can.

@joewood
joewood commented Jun 1, 2016

Thanks for the response. It may be necessary to use a custom transformer for TypeScript. I'll keep investigating and post anything I find here.

@joewood
joewood commented Jun 3, 2016 edited

Hi @hamiltonia
I've had some limited success in getting this to work. The approach I'm looking at is to replace the react-native transformer with a version that supplies the babel option inputSourceMap. I patched the transform.js file from RN's packager in two places, one to set the option for Babel and the other to read in the map file:

/**
 * Copyright (c) 2015-present, Facebook, Inc.
  */
'use strict';

const babel = require('babel-core');
const externalHelpersPlugin = require('babel-plugin-external-helpers');
const fs = require('fs');
const makeHMRConfig = require('babel-preset-react-native/configs/hmr');
const resolvePlugins = require('babel-preset-react-native/lib/resolvePlugins');
const inlineRequiresPlugin = require('fbjs-scripts/babel-6/inline-requires');
const json5 = require('json5');
const path = require('path');

const getBabelRC = (function () {
  let babelRC = null;

  return function _getBabelRC(projectRoots) {
    if (babelRC !== null) {
      return babelRC;
    }

    babelRC = { plugins: [] }; // empty babelrc

    let projectBabelRCPath;
    if (projectRoots && projectRoots.length > 0) {
      projectBabelRCPath = path.resolve(projectRoots[0], '.babelrc');
    }

    if (!projectBabelRCPath || !fs.existsSync(projectBabelRCPath)) {
      babelRC = json5.parse(
        fs.readFileSync(
          path.resolve(__dirname, 'node_modules/react-native/packager/react-packager', 'rn-babelrc.json'))
      );

      // Require the babel-preset's listed in the default babel config
      babelRC.presets = babelRC.presets.map((preset) => require('babel-preset-' + preset));
      babelRC.plugins = resolvePlugins(babelRC.plugins);
    }

    return babelRC;
  };
})();

/**
 * Given a filename and options, build a Babel
 * config object with the appropriate plugins.
 */
function buildBabelConfig(filename, options) {
  const babelRC = getBabelRC(options.projectRoots);

  const extraConfig = {
    filename,
    sourceFileName: filename,
    // ADDED PATCH FOR INPUT SOURCE MAPS
    inputSourceMap: options.inputSourceMap
  };
  let config = Object.assign({}, babelRC, extraConfig);

  // Add extra plugins
  const extraPlugins = [externalHelpersPlugin];

  var inlineRequires = options.inlineRequires;
  var blacklist = inlineRequires && inlineRequires.blacklist;
  if (inlineRequires && !(blacklist && filename in blacklist)) {
    extraPlugins.push(inlineRequiresPlugin);
  }

  config.plugins = extraPlugins.concat(config.plugins);

  if (options.hot) {
    const hmrConfig = makeHMRConfig(options, filename);
    config = Object.assign({}, config, hmrConfig);
  }

  return Object.assign({}, babelRC, config);
}

function transform(src, filename, options) {
  options = options || {};

  const babelConfig = buildBabelConfig(filename, options);

  const result = babel.transform(src, babelConfig);

  return {
    ast: result.ast,
    code: result.code,
    map: result.map,
    filename: filename,
  };
}

module.exports = function (data, callback) {
  // ADDED PATCH FOR INPUT SOURCE MAPS
  if (fs.existsSync(data.filename + ".map")) {
    console.log("Adding Map for " + data.filename);
    data.options = data.options || {};
    data.options.inputSourceMap = JSON.parse(fs.readFileSync(data.filename + ".map").toString());
    data.options.sourceMaps = true;
  }
  // END PATCH
  let result;
  try {
    result = transform(data.sourceCode, data.filename, data.options);
  } catch (e) {
    callback(e);
    return;
  }

  callback(null, result);
};

// export for use in jest
module.exports.transform = transform;

All this is doing is sending the mapfile data to babel if it exists as a .js.map file (bit of an assumption, but this is just for testing). I can use this transform with VSCode if I change the RN Native Extension's Packager.start function. I simply add the arguments for the command line:

    .then(function () {
        var args = ["--port", Packager.PORT,"--transformer","c:\\code\\app\\transform.js"];
        var childEnvForDebugging = Object.assign({}, process.env, { REACT_DEBUGGER: "echo A debugger is not needed: " });

Note, there's a bug in RN where the transform module needs to specified with a full path.

This all seems to work OK, in that when I browse to look at the .map file in the browser the TypeScript source files are referenced correctly. However, the problem is that VSCode doesn't seem to be picking them up and loading the source files. Injecting a "debugger" statement just opens up the main bundle file. I've tried using sourceRoot and relative paths, but without success. So, it seems to be failing at the last step.

Any suggestions would be appreciated. Thanks.

@joewood
joewood commented Jun 3, 2016

FYI - I tried debugging in DevTools, but I see the error "Failed to Parse SourceMap". However, this error could be related to the Chrome 51 bug logged here: https://bugs.chromium.org/p/chromium/issues/detail?id=611328

@frogcjn
Contributor
frogcjn commented Jun 4, 2016

So recently we cannot debug in typescript?

@frogcjn
Contributor
frogcjn commented Jun 5, 2016 edited

@joewood
Here is my post to explain how to deal with this debugger problem with typescript:
make_VSCode_debug_RN_TS.md

Also refer to these two issues
facebook/react-native#393
facebook/react-native#7083

@frogcjn
Contributor
frogcjn commented Jun 7, 2016

I have make some progress on debugging typescript in vscode
2016-06-07 16 43 04

@frogcjn
Contributor
frogcjn commented Jun 7, 2016

Success! I'll write a post to explain how to debug typescript file with react native in vscode.
2016-06-07 19 31 45

@frogcjn
Contributor
frogcjn commented Jun 9, 2016 edited

@joewood

Here is my post to explain how to debug ReactNative project in VSCode with typescript:
make_VSCode_debug_RN_TS.md

@MSLaguana
Member

Thanks a lot for looking into that and providing a detailed explanation @frogcjn!
We've been a bit busy on other projects so we haven't had a chance to look over your PR closely yet, but we'll try to get to that soon. We definitely want to get this working.

@MSLaguana
Member

Thanks to @frogcjn for his PR implementing this: #259

Support will be in the next release.

@alfonsogarciacaro alfonsogarciacaro referenced this issue in fable-compiler/fable-react_native-demo Aug 6, 2016
Merged

Load core-js polyfill #5

@forki
forki commented Aug 6, 2016

when will we see the next release?

@MSLaguana
Member

Soon™

While you wait for the official release, you can check out this repo and build it yourself.

@forki
forki commented Aug 9, 2016

Thanks that's good enough for me. I'm way to deep down the wrong rabbit
hole already ;-)

On Aug 9, 2016 8:07 PM, "Jimmy Thomson" notifications@github.com wrote:

Soon™

While you wait for the official release, you can check out this repo and
build it yourself.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#240 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADgNBjffQiAqErR92LgPodAOFr9zpl8ks5qeMHVgaJpZM4Iqn0T
.

@mbraude
Contributor
mbraude commented Aug 23, 2016

Thanks @joewood - this change is in the repo and will go out in the next release.

@mbraude mbraude closed this Aug 23, 2016
@Flavien
Flavien commented Dec 23, 2016

I'm still struggling to get breakpoints to light up in VS Code with TypeScript on a react-native project. I followed the instructions and set sourceMap to true in .babelrc.

Am I missing something?

@vladimir-kotikov
Member

@Flavien, what instructions are you referring to? Could you please describe exact steps you have tried?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment