Skip to content

Commit

Permalink
Fix source mapping for codegenNativeCommands (facebook#46452)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#46452

`babel-plugin-codegen` transforms `codegenNativeComponent`s by expending it with a whole set of many commands (~40 lines) that don't have a good equivalent on the source file.

Currently these lines are pointing to random parts of the due to a bug that causes the source maps to be incorrect and confusing.

Instead, I point all these generated lines of code to the default export as the only line that can represent them.

This way, if an error is thrown from that generated code it would point to that export.

If the users are confused by how it works, there's a comment in the function that is used in the default export in these that explains it:
```
// If this function runs then that means the view configs were not
// generated at build time using `GenerateViewConfigJs.js`. Thus
// we need to `requireNativeComponent` to get the view configs from view managers.
// `requireNativeComponent` is not available in Bridgeless mode.
// e.g. This function runs at runtime if `codegenNativeComponent` was not called
// from a file suffixed with NativeComponent.js.
function codegenNativeComponent<Props>(
  componentName: string,
  options?: Options,
): NativeComponentType<Props> {
```

The transformation is from all the types and exports after the imports:
[`MyNativeViewNativeComponent` for example](https://github.com/facebook/react-native/blob/773a02ad5d3cc38e0f5837b42ba9a5e05a206bf9/packages/rn-tester/NativeComponentExample/js/MyNativeViewNativeComponent.js#L4)
Which is roughly (ignoring all typing):
```
// types and exports
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
  supportedCommands: [
    'callNativeMethodToChangeBackgroundColor',
    'callNativeMethodToAddOverlays',
    'callNativeMethodToRemoveOverlays',
    'fireLagacyStyleEvent',
  ],
});

export default (codegenNativeComponent<NativeProps>(
  'RNTMyNativeView',
): MyNativeViewType);

```
to roughly:
```
  var React = require('react');
  var nativeComponentName = 'RNTMyNativeView';
  var __INTERNAL_VIEW_CONFIG = {
    uiViewClassName: 'RNTMyNativeView',
    bubblingEventTypes: {
      topIntArrayChanged: { /* */ },
      topAlternativeLegacyName: { /* */ },
    },
    validAttributes: {
      opacity: true,
      values: true,
      ...require('ViewConfigIgnore').ConditionallyIgnoredEventHandlers({
        onIntArrayChanged: true,
        onLegacyStyleEvent: true
      })
    }
  };
  var _default = require('NativeComponentRegistry').get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);
  var Commands = {
    callNativeMethodToChangeBackgroundColor(ref, color) {
      require('RendererProxy').dispatchCommand(ref, "callNativeMethodToChangeBackgroundColor", [color]);
    },
    callNativeMethodToAddOverlays(ref, overlayColors) {
     require('RendererProxy').dispatchCommand(ref, "callNativeMethodToAddOverlays", [overlayColors]);
    },
    callNativeMethodToRemoveOverlays(ref) {
      require('RendererProxy').dispatchCommand(ref, "callNativeMethodToRemoveOverlays", []);
    },
    fireLagacyStyleEvent(ref) {
     require('RendererProxy').dispatchCommand(ref, "fireLagacyStyleEvent", []);
    }
  };
  exports.default = _default;
  exports.__INTERNAL_VIEW_CONFIG = __INTERNAL_VIEW_CONFIG;
  exports.Commands = Commands;
```

Changelog: [Fix] Fixed source maps in Native Components JS files that use codegenNativeComponent

Reviewed By: huntie

Differential Revision: D62443699
  • Loading branch information
vzaidman authored and facebook-github-bot committed Sep 16, 2024
1 parent 68a92aa commit fed3e31
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
31 changes: 24 additions & 7 deletions packages/babel-plugin-codegen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
let FlowParser, TypeScriptParser, RNCodegen;

const {basename} = require('path');
const {cheap: traverseCheap} = require('@babel/traverse').default;

try {
FlowParser =
Expand Down Expand Up @@ -168,16 +169,32 @@ module.exports = function ({parse, types: t}) {
exit(path) {
if (this.defaultExport) {
const viewConfig = generateViewConfig(this.filename, this.code);
this.defaultExport.replaceWithMultiple(
parse(viewConfig, {
babelrc: false,
browserslistConfigFile: false,
configFile: false,
}).program.body,
);

const ast = parse(viewConfig, {
babelrc: false,
browserslistConfigFile: false,
configFile: false,
});

// Almost the whole file is replaced with the viewConfig generated code that doesn't
// have a clear equivalent code on the source file when the user debugs, so we point
// it to the location of the default export that in that file, which is the closest
// to representing the code that is being generated.
// This is mostly useful when that generated code throws an error.
traverseCheap(ast, node => {
if (node?.loc) {
node.loc = this.defaultExport.node.loc;
node.start = this.defaultExport.node.start;
node.end = this.defaultExport.node.end;
}
});

this.defaultExport.replaceWithMultiple(ast.program.body);

if (this.commandsExport != null) {
this.commandsExport.remove();
}

this.codeInserted = true;
}
},
Expand Down
1 change: 1 addition & 0 deletions packages/babel-plugin-codegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"index.js"
],
"dependencies": {
"@babel/traverse": "^7.25.3",
"@react-native/codegen": "0.77.0-main"
},
"devDependencies": {
Expand Down

0 comments on commit fed3e31

Please sign in to comment.