Cannot find documentation for metro.config.js > resolver > resolveRequest
I cannot find any docs for the resolveRequest function listed at https://facebook.github.io/metro/docs/configuration#resolverequest
I implemented the function and inspected it with console.log(arguments), but when I return a string, it throws a type error.
resolveRequest(context, module, platform){
let res = require.resolve(path.resolve(context.originModulePath, module));
console.log(res);
return res;
}
return {
filePath: <path_to_source>,
type: 'sourceFile',
};
Docs have been updated with an example.
I get the following @benjaminhr
metro.config.js (part of it)
resolveRequest: (context, realModuleName, platform, moduleName) => {
return {
filePath: resolve(context.originModulePath, module),
type: 'sourceFile'
}
}
output
Error: Unable to resolve module `./index` from ``: ./index could not be found within the project.
There isn't any useful docs for how to use the resolveRequest prop for module aliasing, so I played around with it and this is what I came up with:
resolveRequest: (context, realModuleName, platform, moduleName) => {
let module = realModuleName;
if(realModuleName.includes('bla') || moduleName.includes('bla')) {
module = module.replace('bla', 'blamos');
}
const { resolveRequest: removed, ...restContext } = context;
return require("metro-resolver").resolve(restContext, module, platform);
},
I get the following @benjaminhr
metro.config.js(part of it)resolveRequest: (context, realModuleName, platform, moduleName) => { return { filePath: resolve(context.originModulePath, module), type: 'sourceFile' } }output
Error: Unable to resolve module `./index` from ``: ./index could not be found within the project.
I have this exact same problem. I just wonder where is the original implementation of resolveRequest() call that handles this kind of situation? All I want right now I to ignore the path module.
Note that this API changed in 0.68
@VictorQueiroz - your use case sounds similar to the one mentioned in the docs - the crucial point is to chain to the default resolver via context.resolveRequest for anything you’re not handling yourself.
resolveRequest: (context, moduleName, platform) => {
if (moduleName.startsWith('my-custom-resolver:')) {
// Resolve file path logic...
// NOTE: Throw an error if there is no resolution.
return {
filePath: "path/to/file",
type: 'sourceFile',
};
}
// Optionally, chain to the standard Metro resolver.
return context.resolveRequest(context, moduleName, platform);
}
Note that this API changed in 0.68
@VictorQueiroz - your use case sounds similar to the one mentioned in the docs - the crucial point is to chain to the default resolver via
context.resolveRequestfor anything you’re not handling yourself.resolveRequest: (context, moduleName, platform) => { if (moduleName.startsWith('my-custom-resolver:')) { // Resolve file path logic... // NOTE: Throw an error if there is no resolution. return { filePath: "path/to/file", type: 'sourceFile', }; } // Optionally, chain to the standard Metro resolver. return context.resolveRequest(context, moduleName, platform); }
I saw this on the docs, but when I try to replicate it I get this problem I described. I'm wondering how can I fix this since it's a huge blocker for me.
Note that this API changed in 0.68
@VictorQueiroz - your use case sounds similar to the one mentioned in the docs - the crucial point is to chain to the default resolver via
context.resolveRequestfor anything you’re not handling yourself.resolveRequest: (context, moduleName, platform) => { if (moduleName.startsWith('my-custom-resolver:')) { // Resolve file path logic... // NOTE: Throw an error if there is no resolution. return { filePath: "path/to/file", type: 'sourceFile', }; } // Optionally, chain to the standard Metro resolver. return context.resolveRequest(context, moduleName, platform); }
The following configuration did it, but still, resolveRequest can be useful so it'd be nice to have it fixed.
module.exports = {
resolver: {
extraNodeModules:{
path: path.resolve(__dirname,'null-module.js'),
fs: path.resolve(__dirname,'null-module.js')
}
}
//...
};
Thank you.
Hi @VictorQueiroz - glad you found a solution for your use case. I'm not exactly sure what problem you're seeing - are you saying context.resolveRequest isn't defined within your custom resolveRequest? Would you be able to post a snippet of what you tried?
@rh389 If you create a new React Native project using the TypeScript template and set the resolver.resolveRequest property on metro.config.js to the following:
function resolveRequest(context, moduleName, platform) {
if (moduleName.startsWith('my-custom-resolver:')) {
// Resolve file path logic...
// NOTE: Throw an error if there is no resolution.
return {
filePath: "path/to/file",
type: 'sourceFile',
};
}
// Optionally, chain to the standard Metro resolver.
return context.resolveRequest(context, moduleName, platform);
}
Should be enough to reproduce this problem I'm relating. So what it seems like is, whatever is the default implementation of resolver.resolveRequest (metro.config.js), it isn't available in require('metro-resolver').resolve nor context.resolveRequest. I even tried the followinng, but still get the same:
return require('metro-resolver').resolve({
...context,
resolveRequest:undefined
},moduleName,platform);
Maybe I'm doing something wrong on my side. I hope this helps clarify, though.
Ah I see - if you init a new React Native app today you'll get [email protected] (latest stable) which includes [email protected], so the metro docs prior to 0.68 apply. Unfortunately, we don't yet have a versioned docs website for metro, but you can access the raw docs at that point from github - https://github.com/facebook/metro/tree/v0.66.2/docs.
Prior to metro 0.68, context.resolveRequest points directly back to your own custom resolver, rather than the default resolver - so calling it from your own resolver creates a recursive loop which eventually throws, gets caught internally and manifests as a failed resolution. To access the default resolver you do need to use metro-resolver and ensure that you unset resolveRequest when passing the context, so the last thing you try is almost correct. The critical difference is that, in <0.68, the resolver takes a fourth argument, "realModuleName".
So in summary, these are equivalent:
For Metro >=0.68
// metro.config.js
module.exports = {
resolver: {
resolveRequest: (context, moduleName, platform) => {
// For example: redirecting `require('path')` to your own mock
if (moduleName === 'path') {
return {
filePath: __dirname + '/my-mock-path.js',
type: 'sourceFile',
};
}
// Forward everything else to the default resolver
return context.resolveRequest(
context,
moduleName,
platform,
);
},
},
};
For Metro < 0.68
// metro.config.js
const defaultResolver = require('metro-resolver').resolve;
module.exports = {
resolver: {
resolveRequest: (context, moduleName, platform, realModuleName) => {
// For example: redirecting `require('path')` to your own mock
if (moduleName === 'path') {
return {
filePath: __dirname + '/my-mock-path.js',
type: 'sourceFile',
};
}
// Forward everything else to the default resolver
return defaultResolver(
{
...context,
resolveRequest: null,
},
moduleName,
platform,
realModuleName,
);
},
},
};
Hope that helps, and sorry for the docs confusion.
Just hit same issue, still using v0.64 and was wondering why it doesn't work when following https://facebook.github.io/metro/docs/configuration#resolverequest
Atleast now it's documented here 😂