New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugging TypeScript Source Files? #240

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

Comments

Projects
None yet
7 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.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Jun 1, 2016

@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.

ghost commented Jun 1, 2016

@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.

@ghost ghost added help wanted question labels Jun 1, 2016

@joewood

This comment has been minimized.

Show comment
Hide comment
@joewood

joewood 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 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

This comment has been minimized.

Show comment
Hide comment
@joewood

joewood Jun 3, 2016

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 commented Jun 3, 2016

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

This comment has been minimized.

Show comment
Hide comment
@joewood

joewood 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

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

This comment has been minimized.

Show comment
Hide comment
@frogcjn

frogcjn Jun 4, 2016

Contributor

So recently we cannot debug in typescript?

Contributor

frogcjn commented Jun 4, 2016

So recently we cannot debug in typescript?

@frogcjn

This comment has been minimized.

Show comment
Hide comment
@frogcjn

frogcjn Jun 5, 2016

Contributor

@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

Contributor

frogcjn commented Jun 5, 2016

@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

This comment has been minimized.

Show comment
Hide comment
@frogcjn

frogcjn Jun 7, 2016

Contributor

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

Contributor

frogcjn commented Jun 7, 2016

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

@frogcjn

This comment has been minimized.

Show comment
Hide comment
@frogcjn

frogcjn Jun 7, 2016

Contributor

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

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

This comment has been minimized.

Show comment
Hide comment
@frogcjn

frogcjn Jun 9, 2016

Contributor

@joewood

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

Contributor

frogcjn commented Jun 9, 2016

@joewood

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

@MSLaguana

This comment has been minimized.

Show comment
Hide comment
@MSLaguana

MSLaguana Jun 9, 2016

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.

Member

MSLaguana commented Jun 9, 2016

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

This comment has been minimized.

Show comment
Hide comment
@MSLaguana

MSLaguana Jul 13, 2016

Member

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

Support will be in the next release.

Member

MSLaguana commented Jul 13, 2016

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

Support will be in the next release.

@forki

This comment has been minimized.

Show comment
Hide comment
@forki

forki Aug 6, 2016

when will we see the next release?

forki commented Aug 6, 2016

when will we see the next release?

@MSLaguana

This comment has been minimized.

Show comment
Hide comment
@MSLaguana

MSLaguana Aug 9, 2016

Member

Soon™

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

Member

MSLaguana commented Aug 9, 2016

Soon™

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

@forki

This comment has been minimized.

Show comment
Hide comment
@forki

forki 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
.

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

This comment has been minimized.

Show comment
Hide comment
@mbraude

mbraude Aug 23, 2016

Contributor

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

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

This comment has been minimized.

Show comment
Hide comment
@Flavien

Flavien 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?

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

This comment has been minimized.

Show comment
Hide comment
@vladimir-kotikov

vladimir-kotikov Jan 10, 2017

Contributor

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

Contributor

vladimir-kotikov commented Jan 10, 2017

@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