metro: Asset paths (httpServerLocation) invalid when asset is in watchFolders
Do you want to request a feature or report a bug? Bug
What is the current behavior?
When I specify a directory in watchFolders from outside of my project root, the path reported via httpServerLocation is broken. For example, /symlinked-watch-folder/subdir/image@3x.png.
If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test.
- Create a React Native project in one directory.
- Create a sibling directory called
symlinked-watch-folderwith a Node module in it namedsymlinked-module. - Add assets to this module, specifically one in
subdir/image@3x.png. - In this module, reference the image like so:
<Image source={require('../subdir/image.png')} /> - Now from the RN project directory, use npm to install the module:
npm install ../symlinked-watch-folder. - Make a component in your project root that displays the module’s component with the image in it.
- Run the React Native project. The image will not appear and a request for the image will 404 because the path is invalid.
What is the expected behavior?
It looks like there are different valid locations, including:
/assets/symlinked-module/subdir/image@3x.png
/assets/subdir/image@3x.png
/subdir/image@3x.png
More info
Because this repo isn’t very publicly documented, I can’t tell exactly what’s going on. But it looks like getAssetData is trying to path.join these two paths:
/assets
../symlinked-watch-folder/subdir/image@3x.png
https://github.com/facebook/metro/blob/bba48f068c6e709187d36170d3e5d49b7e9f6169/packages/metro/src/Assets.js#L181
The ../ wipes out the /assets and we end up with a result that isn’t valid:
/symlinked-watch-folder/subdir/image@3x.png
I believe the relative path is coming from here: https://github.com/facebook/metro/blob/bba48f068c6e709187d36170d3e5d49b7e9f6169/packages/metro/src/DeltaBundler/Serializers/getAssets.js#L44
The asset is being served correctly, it’s just that the httpServerLocation that’s being generated is not correct.
I can access the asset just fine if I correct the path to one of these:
/assets/symlinked-module/subdir/image@3x.png
/assets/subdir/image@3x.png
/subdir/image@3x.png
If there is some way to handle this using the documented options, please let me know. (cc: @rafeca )
Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system. I’ve tried both Metro 0.47.1 and Metro 0.48.0 Node: 10.11.0 npm: 6.4.1 OS: macOS High Sierra
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 34
- Comments: 22 (1 by maintainers)
Commits related to this issue
- Encode ..'s in asset paths to fix #290 — committed to imownbey/metro by deleted user 4 years ago
FYI, I abstracted @vitramir fix in a module that I’m using in a monorepo:
get-metro-android-assets-resolution-fix.js.You can use it this way:
Wondering if we could just default to a huge
depth(e.g. 20) without drawbacks.Edit: I also published it in
react-native-monorepo-tools.I got this issue while using yarn workspaces and here is how I solved it:
1)Our first issue is resources destination path outside of
/assetsdirectory. It breaks both debug server and bundle.There is config
transformer.publicPathwhich default value is/assets. So, I changed it to/assets/dir1/dir2/dir3(because my watchDir is ‘…/…/…/’). Now it will generate valid destination path for resources outside of projectRoot. For example/assets/dir1/dir2/dir3/../../common/images/image.png.react-native bundlewill work too.2)The second issue with Metro Server. It should resolve requests for IOS (
http://localhost:8081/assets/dir1/dir2/dir3/../../common/images/image.png) and Android (http://localhost:8081/assets/dir1/common/images/image.png) the same way.I changed
server.enhanceMiddlewareconfig this way:I want to notice here two more things:
1)This code doesn’t use config value
transformer.publicPath. I think it is wrong. https://github.com/facebook/metro/blob/d9c556c04dc863b334720ab7eed9c94bc2841995/packages/metro/src/Server.js#L306-L3072)And another solution of this issue is to update code of assetUrlPath generation and replace
../into something like__/or_.._/.For example, this line https://github.com/facebook/metro/blob/d9c556c04dc863b334720ab7eed9c94bc2841995/packages/metro/src/Assets.js#L197-L199 may become:
Also we should add reverse operation at Server module. I can make PR with this changes if community approve the idea.
I am currently using this config and it works with yarn workspaces as expected:
I don’t provide babelTransformer. Nothing interesting there.
I created a simple repro for this using yarn workspaces: https://github.com/brentvatne/metro-issue-290
we’re running into this in the expo monorepo, only solution for us for now is to use
nohoist:\perhaps the path should be given a uri param? eg:
http://localhost:1234/assets?path=../lol/whatever.png&platform=android&so-on&so-forthI’m facing the same problem. I can’t display local images if they are on my watchFolders. I’m not familiar with metro but when I bundle my app it works, so I guess there is a problem in my metro config…
Here is my project stucture :
And here is my metro config, present in the native folder :
Do you see where is my problem here ? 😕 (I can import shared components, it only failed with assets)
React-Native : 0.57.4 Metro : 0.48.5
Thanks @vitramir & @mmazzarolo 🙏
FYI @mmazzarolo the link in your answer results in 404, it needs to be updated to this 😃
@papigers Actually, a nicer solution is to use an asset plugin.
I created
metro-asset-plugin.js:Then in
metro.config.jsI include it thus:I’m having the same issue: iOS not showing watchFolder images only on release build - debug build works fine.
I bumped into this problem too! Currently as a workaround I did what suggested in #322.
Also, for Androd I need the patch only in dev mode (using metro server) while for iOS I have to do the opposite (when I build the bundle). 😕
React-Native: 0.59.0 Metro: 0.51.1
Yep, I think changing the asset path to be given as a query param is the only way forward here.
Brief recap for others:
http://localhost:8081/assets/images/foo.pngwatchFoldersis used in Metro config, as is used in multi-repo or mono-repo projects, relative paths are used for assets (e.g.../../../common/assets/images/image.png) These may be way outside of the root.http://localhost:8081/assets/../../../common/assets/images/image.png. The Metro server handles it fine.okhttpto send requests, relative paths are stripped (per the URI spec section 5.2.4) before the request is made. That means the request ends up beinghttp://localhost:8081/images/image.pngwhich is invalid.Unless there’s some way to configure
okhttpto stop removing dot segments, the only way forward (and the more sane approach) would be to send asset paths off as query params.More info was posted in https://github.com/facebook/metro/issues/322#issuecomment-445642199 and a fix was supposed to be in https://github.com/facebook/metro/commit/0eaa741827bc3397ca7368105d62b1fa45fbbbe7 but looks like that didn’t fully solve it. Unfortunately, the author @rafeca left Facebook earlier this year, so probably won’t get much more attention from him.
Hi, I also encountered this issue when using symlink to resolve asset. Im using metro-with-symlinks to resolve symlink packages.
Here’s the repo to reproduce the issue: https://github.com/adrianha/metro-symlink - Works fine react-native: 0.57.1
https://github.com/adrianha/metro-symlink/tree/0.57.2 - Assets path incorrect react-native: 0.57.2
If you have a monorepo setup, and are experiencing issues resolving assets in
node_moduleson iOS release builds after updating to React Native 0.62, it is likely that you are experiencing https://github.com/react-native-community/upgrade-support/issues/26. The easiest solution is to patchreact-nativewith https://github.com/facebook/react-native/commit/7deeec73966d84140492c2a767819977318c4d2d.