40. Glorified cURL
String newBobAppPath = cURLToDisk(“https://expo.io/@bob/app”);
String bobAppPath = “file:///bob-app.js”;
if (newBobAppPath != null){
loadApp(newBobAppPath);
} else {
loadApp(bobAppPath);
}
JS Bundle
We don’t want to load the JS bundle unnecessarily.
We only want to load the JS bundle if there’s a new change available.
41. Let’s take a step back
And think about how the web
works for a sec
43. Taking a page out of the web book
{bundleUrl: ‘bundle.js’}
Big JS bundle
bundle.js
index.json
44. Taking a page out of the web book
{bundleUrl: ‘ios-1a2b3c.js’}
Big JS bundle
ios-1a2b3c.js
index.json
Bundle name is based off its md5 hash
45. Taking a page out of the web book
{bundleUrl: ‘ios-7a8b9c’}
Big JS bundle
ios-7a8b9c.js
index.json
Cache the bundleUrl
Only download bundleUrl
if we don’t have it cached
46. How do I use an OTA service in my app?
^ these are my app files
^ this is what my app looks like
47. How do I use an OTA service in my app?
dev tools GUI
^ push this button to upload app to expo server
48. How do I use an OTA service in my app?
Or use the cli if you prefer
> expo publish
Run this command in your project directory to upload to expo servers
49. How often is the server polled for updates?
The default behavior is to poll the server when the app starts up
50. What if I don’t like the default behavior?
You can use the Updates module to customize when you’d to update your app
^ from the docs page
52. I’m in a country where network latency
to your CDNs are really high
53. I’m in a country where network latency
to your CDNs are really high
How about hosting your own app then?
54. I’m in a country where network latency
to your CDNs are really high
How about hosting your own app then?*
* in our upcoming SDK release
55. How do I host my own app?
^ these are my app files
^ this is what my app looks like
56. > expo export
Run this command in your project directory
to dump your app to disk
How do I host my own app?
57. This is what gets dumped to disk
How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│ └── 1ecc2
└── bundles
├── android-01ee6.js
└── ios-ee820.js
58. How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│ └── 1ecc2
└── bundles
├── android-01ee6.js
└── ios-ee820.js
59. How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│ └── 1ecc2
└── bundles
├── android-01ee6.js
└── ios-ee820.js
{bundleUrl: ‘ios-ee820.js’}
Big JS bundle
ios-ee820.js
ios-index.json
60. How do I host my own app?
.
├── android-index.json
├── ios-index.json
├── assets
│ └── 1ecc2
└── bundles
├── android-01ee6.js
└── ios-ee820.js
git push master
61. I pushed to GitHub because it has free static hosting.
You can host your app from any server.
62. How do I build my app binary?
> expo build:ios
Run this command in your project directory
63. How do I build my app binary?
> expo build:ios —public-url https://quinlanj.github.io/self-hosting/ios-index.json
Run this command in your project directory
64. How do I build my app binary?
> expo build:ios —public-url https://quinlanj.github.io/self-hosting/ios-index.json
{bundleUrl: ‘ios-ee820.js’}
Big JS bundle
ios-ee820.js
ios-index.json
^ This file is served first
74. This is what my app looks like.
I’ve installed it on my phone.
75. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
76. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
Here is the server hosting my app
77. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
An update is ready!
78. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
79. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
JS Bundle
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
JS Bundle
80. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
82. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
dog.png is pulled down to filesystem?
86. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
dog.png is pulled down to filesystem?
87. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
dog.png is not on the filesystem
88. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
?
Let’s grab dog.png from server then!
89. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
90. This is what my app looks like.
I’ve installed it on my phone.
Currently on filesystem:
quinlanj.github.io
An update is ready!
Files to be served:
New
JS Bundle
Cached for future use
91. How come assets are stored by hash?
.
├── android-index.json
├── ios-index.json
├── assets
│ └── 1ecc2
└── bundles
├── android-01ee6.js
└── ios-ee820.js
95. JS Bundle
Module Logic:
Look for 1ecc2 in the filesystem
If it’s not there, look for 1ecc2 from the server
Actual Implementation
{assetName: ‘cat.png’, hash:’1ecc2’}
97. <Image source={require(‘cat1.png’} />
<Image source={require(‘crazy-cat.png’} />
<Image source={require(‘lime-cat.png’} />
…
This app displays the same cat picture
These cat pictures are all named something different
100. Announcements
We made a web application called Snack
Snack is like a JS Fiddle for react native apps
Snack is now open source, check it out at https://github.com/expo/snack-web