What do I want:
I have a react-native typescript application, and during the build process, with the help of metro-bundler I wanted to inject a code snippet like trackCall({functionName: Foo}) into every function's body, that is residing inside the application's /src directory.
So Ideally, all components, utils, helpers, and every function should have the above-mentioned snippet injected! (Atleast this would be a good start for my more specific objectives)
What have I tried:
As per my research, I found that its transformer specifically through babelTransformerPath I can traverse through each function and do necessary modifications.
The metro.config.js looks as follows
module.exports = (async () => {
// This is my experiment config
const customConfig = {
transformer: {
babelTransformerPath: require.resolve('./debug/custom-plugin.js'),
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
return mergeConfig(
{ // This is the original/default config of my application
resolver: { extraNodeModules },
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
},
customConfig
);
})();
And, the target custom plugin that I have created./debug/custom-plugin.js looks as follows. After many trials and error I was able to successfully create "get some result" without error. I might be using the wrong plugins here, but I don't know any better atm. (Open for improvements)
NOTE: In the plugin, I have tried to inject a very basic console.log to start with.
const obfuscatingTransformer = require('react-native-obfuscating-transformer-fix');
const typescriptTransformer = require('react-native-typescript-transformer');
const ts = require('typescript');
// I probably dont need this "obfuscatingTransformer" at all.
// the "typescriptTransformer" should be enough
const filter = filename => filename.startsWith('node_modules');
const obfuscating = obfuscatingTransformer({
upstreamTransformer: typescriptTransformer,
emitObfuscatedFiles: false,
enableInDevelopment: true,
filter: filter,
trace: true,
});
module.exports.transform = function (file) {
if (file.filename.startsWith('src/')) {
console.log('[BUILD-file-detection-log: ] ', file.filename);
const updatedFile = visitNode(file);
return typescriptTransformer.transform(updatedFile);
}
return obfuscating.transform(file);
};
function visitNode(node) {
if (
ts.isFunctionDeclaration(node) ||
ts.isArrowFunction(node) ||
ts.isFunctionExpression(node)
) {
// Get the name of the function
let functionName = '';
if (node.name && ts.isIdentifier(node.name)) {
functionName = node.name.text;
}
// Create a console.log statement
const logStatement = ts.createExpressionStatement(
ts.createCall(
ts.createPropertyAccess(
ts.createIdentifier('console'),
ts.createIdentifier('log')
),
undefined,
[
ts.createStringLiteral(
`[Test-log: RESULT] >> ${functionName}`
),
]
)
);
// Create a new body that includes the console.log statement followed by the existing body
const newBody = ts.createBlock(
[logStatement, ...node.body.statements],
true
);
// Update the function node with the new body
return ts.updateFunctionDeclaration(
node,
node.decorators,
node.modifiers,
node.asteriskToken,
node.name,
node.typeParameters,
node.parameters,
node.type,
newBody
);
}
return ts.visitEachChild(node, visitNode, null);
}
Result:
During this whole experiment I was expecting to update the transformed *.js files and somehow understand how and where babel is contributing to the building process, but unfortunately, I failed find a clue. In the end, I had to work with only typescript files.
Final result:
- During the build process I can see the
[BUILD-file-detection-log: ] <filename>logs getting executed. - When I run the app,
[Test-log: RESULT] >> ${functionName}never appeared!
So, traversing through the files in src/ happened, but the injections didn't succeed!
Need of help
Tbh, I dont care if it's a js or a typescript transformer. In the end, I want to inject code snippets (let's say console.count) into every function inside my app's /src directory.