Skip to content

[Packager] New asset dependency system in the works #1043

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

Closed
amasad opened this issue Apr 27, 2015 · 26 comments
Closed

[Packager] New asset dependency system in the works #1043

amasad opened this issue Apr 27, 2015 · 26 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@amasad
Copy link
Contributor

amasad commented Apr 27, 2015

The way we currently handle images is far from ideal. To get it working, you have to configure the packager to look in the right directory, you have to add the image to xcode, and then you have to require(image!image-name) where image-name is a global name, and finally you'll have to learn how to manage assets for every platform you want to target with React Native. Issues #521 and #282 are examples of how much of a hassle it can be.

I opened this issue to inform you that we're working on a replacement system that would be platform independent and mostly implemented in JS and the packager. Of course, we'll keep the current system running alongside the new one and give you time before we deprecate it. Here are our goals for this:

  • Images can exist alongside the JS code (no need for assetRoots) and be required via CommonJS-like module resolution require('./path/to/img.png') or require('packageName/img.png')
  • Images can have multiple scale versions and are expressed via the @nx notation currently used in iOS. So img.png could actually be img@0.5x.png img@3x.png or what have you and we'd automatically pick the most appropriate scale for the device.
  • This means you can publish React Native components to npm that have asset dependency and have them still work
  • In development you can edit/add/delete images and cmd+r and have it work!
  • We're still working on details on how will this work when shipping apps but hopefully will have some more details about this soon
@nicklockwood
Copy link
Contributor

Will this apply to sounds, html files, json, etc. as well?

@jaygarcia
Copy link
Contributor

I"m very much looking forward to this dude. I have asset requirements also, such as JSON files and potentially images that i'd like to pack in my app.

@wwwsevolod
Copy link
Contributor

it sounds so webpacky. may be just use webpack and use it's dependency graph to automatically inject it in xcode project (or where it need's to be injected). May be i don't understand something? webpack is so modular and flexible, so it could be possible to create loader that loads from local, or load it dynamically (to reduce result app size, to be allowed to download over cellular network).

@amasad
Copy link
Contributor Author

amasad commented Apr 28, 2015

@nicklockwood yes, I just mentioned images becuase of the special consideration to scales, but otherwise all other assets should just work.

@wwwsevolod there's been a few discussion about why we didn't go with webpack from the start but it boils down to performance (webpack is orders of magnitude slower), the problem that we have a proprietary module system that needs to interop with, and finally non of the current asset loader does what we want it to do. However, this shouldn't stop you from using webpack. Take a look at @mjohnston webpack integration project which works really well, I'm open to patches or whatever is needed to support that project.

@jaygarcia I already adressed the json loading thing, it now returns a parsed JS object, just like in node.

@ptmt
Copy link
Contributor

ptmt commented May 2, 2015

@amasad Would be awesome to have this kind of dependency system!

Is there any best practices to handle a lot of images right now? I'm not a fan of drag'n'droping something to XCode, so I wrote a little gist https://gist.github.com/unknownexception/91689d0f2bb8506cc9d9 which generate assets folders like imagename.imageset with Contents.json inside and three scaled images using GraphicsMagick.

https://facebook.github.io/react-native/docs/image.html says:

A React component for displaying different types of images, including network images, static resources, temporary local images, and images from local disk, such as the camera roll.

How could I insert "temporary local images" and "images from local disk" via <Image> component? What if I want to download and cache network images?

@yifeic
Copy link

yifeic commented May 10, 2015

@amasad The new asset system sounds great. +1 for not touching Xcode project file.
Currently Image component only supports static and network image. In my iOS project, I use font file to generate icons. Is there any way for me to plug in my own image provider for Image? For example, if I have some native code that generate image from font file and then in JS I want to have something like:

<Image source={{uri: 'font://people-icon?size=10&color=white'}}/>

In summary, I want to provide a custom uri(or any other way) to tell Image to use a custom image provider. Not sure if this is related to the new asset system.

@frantic
Copy link
Contributor

frantic commented May 11, 2015

Is there any way for me to plug in my own image provider for Image?

No, not yet. But I think it's a good idea. Note that currently we have 2 image component providers backing single <Image> - StaticImage and NetworkImage. Would be great to merge them on native side and add plugins support with custom URI schemas.

@nicklockwood
Copy link
Contributor

@yifeic I'm working on an improvement to the image loading pipeline that will make it possible to plug in new image loaders. For now though, the only option is to clone RCTStaticImageManager or RCTNetworkImageManager, modify it to use your own loader, then export it with the same name as the built-in module and inject it using the RCTBridge moduleProvider block so that it is used instead of the built-in version.

@felixkaiser
Copy link

Thanks. Can someone with access to the documentation please update it? Just spent an hour finding this. https://facebook.github.io/react-native/docs/image.html#static-assets

@lukasredev
Copy link

@nicklockwood What's your timeframe for the updates? If you pushed something I'd be happy to assist you, because image loading is crucial for my application ....

@nicklockwood
Copy link
Contributor

@lukasreichart if you need it urgently, I suggest forking the RCTImageManager module.

@brentvatne brentvatne changed the title New asset dependency system in the works [Packager] New asset dependency system in the works May 30, 2015
@ghost
Copy link

ghost commented Aug 4, 2015

Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.

@tadeuzagallo
Copy link
Contributor

@amasad can we close it?

@amasad
Copy link
Contributor Author

amasad commented Sep 8, 2015

Sure. Although, we'll probably ship and document this soon (we started using it internally) I don't want to make promises 😛

@amasad amasad closed this as completed Sep 8, 2015
@gnestor
Copy link
Contributor

gnestor commented Nov 9, 2015

I upgraded to React Native 0.14.1 and like in 0.13, when I create an offline bundle, the static images that I require using the new system are not resolved (blank). The images show up fine when using the dev server bundle. Do I need to set an "assets destination folder" when bundling? Is this documented anywhere?

@frantic
Copy link
Contributor

frantic commented Nov 9, 2015

@gnestor 0.14 introduced a new script which now runs as part of your Xcode build. This means you no longer need to run react-native bundle from the terminal before building your app. To upgrade, use http://facebook.github.io/react-native/docs/upgrading.html or follow this instructions:

screen shot 2015-11-09 at 3 32 37 pm

screen shot 2015-11-09 at 3 31 59 pm

Note that if you have main.jsbundle you'll have to remove it, since it now is generated automatically for you:

screen shot 2015-11-09 at 3 37 34 pm

Let us know if it works for you and we can add this to upgrading documentation.

@gnestor
Copy link
Contributor

gnestor commented Nov 10, 2015

@frantic Thanks for the instructions (I missed that part of the upgrading process because I migrated my existing Xcode project and didn't see that in the diffs). I added the new script to my Build Phases and it works fine as long as the packager is running and serving the assets. As soon as I stop the packager, the images don't show. How can I build an offline bundle?

@frantic
Copy link
Contributor

frantic commented Nov 11, 2015

@gnestor note that your need to change the URL you load your bundle from. Instead of devserver it should be local file. Let me know if this helps. Otherwise reach out to @frantic via #reactiflux on Discord.

@gnestor
Copy link
Contributor

gnestor commented Nov 11, 2015

@frantic Adding the main.jsbundle generated by the Xcode script solved the problem, images are showing up fine for offline bundles (duh!). I'm noticing that the Xcode script is being run every time I build in Xcode, whether for development or production, which adds another 10-20s to build time. However, the bundle isn't used when running the app against the dev server, correct? If so, what's the value in using this new bundle script from Xcode vs. the former method of running react-native bundle when an offline bundle is needed?

@frantic
Copy link
Contributor

frantic commented Nov 19, 2015

@gnestor (sorry for late reply) the value is in getting unified workflow and less room for errors by paying additional build cost. With react-native bundle you always have to think about offline vs dev, keep in mind that you need --dev false when before submitting your app, etc.

Now imagine you have Android app that also has it's own way of bundling, and a different bundle path, different set of options (e.g. images work differently in Xcode and Android SDK), etc.

You still have power and freedom of using the react-native bundle yourself. You can remove the Xcode integration script and Gradle build step, and have a different place where you'd put all these commands.

@gnestor
Copy link
Contributor

gnestor commented Nov 19, 2015

@frantic This makes sense to ease the pain of working across platforms. I have an idea to potentially improve the experience on iOS:

The new Xcode build script can inspect AppDelegate.m and if jsCodeLocation is of NSURL type, exit.

Good idea? If so I can bang it out and submit a pull request...

@frantic
Copy link
Contributor

frantic commented Nov 23, 2015

Very, very clever idea, but I'm afraid it can be too magical. Also how will it work on Android?

@gnestor
Copy link
Contributor

gnestor commented Nov 23, 2015

I haven't dug into React Native for Android yet, so this would just be an optimization for the react-native-xcode.sh. Here's what I'm thinking: gnestor@68116d5

# Find the app's AppDelegate.m file
app_delegate=$(find ./../../../iOS -name 'AppDelegate.m')

# Find the last jsCodeLocation assignment (that is not a comment)
type=$(awk '/jsCodeLocation =/ && !/\/\/ /' $app_delegate | tail -1)

# If the jsCodeLocation type is 'NSURL', then skip the bundle script
if [[ "$type" =~ "NSURL" ]]; then
  exit 1
fi

@ide
Copy link
Contributor

ide commented Nov 23, 2015

Xcode passes in CONFIGURATION as an environment variable to the script: https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW49

Assuming that Debug implies using the packager server and Release implies using the embedded bundle, this seems like a robust approach.

@gnestor
Copy link
Contributor

gnestor commented Nov 23, 2015

It could be as simple as that: if [[ $DEV == true ]] exit 1

The only use case that this ignores is testing on a device in dev mode (which would still be possible using react native bundle)...

@frantic
Copy link
Contributor

frantic commented Nov 23, 2015

Assuming that Debug implies using the packager server and Release implies using the embedded bundle, this seems like a robust approach.

Yeah that's what we used with at FB initially, however this special casing rules (skip bundle if Debug, unless building for device or if building on CI, etc.) only grew bigger and proved to be a nightmare to support. The other problem is that this bunch of ifs had to be duplicated in both building scripts and Objective-C code that specifies where to load the bundle from.

which would still be possible using react native bundle

This is true only for JS changes. If you are using the new asset system the images also have to be copied into the resulting app bundle, the location of which is harder to guess and a bit too much to manually type in the command line.

@facebook facebook locked as resolved and limited conversation to collaborators Jul 22, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests