Loading assets from a 'base' route (e.g. /somepath) works correctly, loading them from /assets/[path to assets].
When attempting to load assets such as fonts from a nested path (e.g. /nested/123), the page attempts to load them from /nested/assets/[path to assets] which is incorrect and leads to the page not rendering correctly. This only happens if you visit the page URL directly, or refresh the browser while on that page.
This happens with locally-sourced assets (e.g. those hosted inside the assets folder) but also with node_modules (e.g. the expo-google-fonts packages exhibit the same behaviour).
This test was done on the web platform - I haven't explicitly tested on mobile/native as there is no way to refresh the page to trigger the bug.
For clarification, I'm unsure if this is a router-specific issue or a bundler issue. Please move to the appropriate repo if this is not the correct one.
I have a fix but it may take a while to land. Here's the qualified patch:
expo-asset+8.6.2.patch
```
diff --git a/node_modules/expo-asset/.DS_Store b/node_modules/expo-asset/.DS_Store
new file mode 100644
index 0000000..7edf0a8
Binary files /dev/null and b/node_modules/expo-asset/.DS_Store differ
diff --git a/node_modules/expo-asset/build/AssetRegistry.d.ts b/node_modules/expo-asset/build/AssetRegistry.d.ts
index 8cb255c..146c620 100644
--- a/node_modules/expo-asset/build/AssetRegistry.d.ts
+++ b/node_modules/expo-asset/build/AssetRegistry.d.ts
@@ -1,2 +1,2 @@
-export * from 'react-native/Libraries/Image/AssetRegistry';
+export * from '@react-native/assets/registry';
//# sourceMappingURL=AssetRegistry.d.ts.map
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.d.ts.map b/node_modules/expo-asset/build/AssetRegistry.d.ts.map
index dd3811f..e88d205 100644
--- a/node_modules/expo-asset/build/AssetRegistry.d.ts.map
+++ b/node_modules/expo-asset/build/AssetRegistry.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"AssetRegistry.d.ts","sourceRoot":"","sources":["../src/AssetRegistry.ts"],"names":[],"mappings":"AAAA,cAAc,4CAA4C,CAAC"}
\ No newline at end of file
+{"version":3,"file":"AssetRegistry.d.ts","sourceRoot":"","sources":["../src/AssetRegistry.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC"}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.js b/node_modules/expo-asset/build/AssetRegistry.js
index 7bed4c5..0ced77f 100644
--- a/node_modules/expo-asset/build/AssetRegistry.js
+++ b/node_modules/expo-asset/build/AssetRegistry.js
@@ -1,2 +1,2 @@
-export * from 'react-native/Libraries/Image/AssetRegistry';
+export * from '@react-native/assets/registry';
//# sourceMappingURL=AssetRegistry.js.map
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.js.map b/node_modules/expo-asset/build/AssetRegistry.js.map
index 3bba715..c80bd2b 100644
--- a/node_modules/expo-asset/build/AssetRegistry.js.map
+++ b/node_modules/expo-asset/build/AssetRegistry.js.map
@@ -1 +1 @@
-{"version":3,"file":"AssetRegistry.js","sourceRoot":"","sources":["../src/AssetRegistry.ts"],"names":[],"mappings":"AAAA,cAAc,4CAA4C,CAAC","sourcesContent":["export * from 'react-native/Libraries/Image/AssetRegistry';\n"]}
\ No newline at end of file
+{"version":3,"file":"AssetRegistry.js","sourceRoot":"","sources":["../src/AssetRegistry.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC","sourcesContent":["export * from '@react-native/assets/registry';\n"]}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.web.d.ts b/node_modules/expo-asset/build/AssetRegistry.web.d.ts
deleted file mode 100644
index fcb49bf..0000000
--- a/node_modules/expo-asset/build/AssetRegistry.web.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from 'react-native-web/dist/modules/AssetRegistry';
-//# sourceMappingURL=AssetRegistry.web.d.ts.map
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.web.d.ts.map b/node_modules/expo-asset/build/AssetRegistry.web.d.ts.map
deleted file mode 100644
index 5f833af..0000000
--- a/node_modules/expo-asset/build/AssetRegistry.web.d.ts.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"AssetRegistry.web.d.ts","sourceRoot":"","sources":["../src/AssetRegistry.web.ts"],"names":[],"mappings":"AAAA,cAAc,6CAA6C,CAAC"}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.web.js b/node_modules/expo-asset/build/AssetRegistry.web.js
deleted file mode 100644
index 26d167c..0000000
--- a/node_modules/expo-asset/build/AssetRegistry.web.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from 'react-native-web/dist/modules/AssetRegistry';
-//# sourceMappingURL=AssetRegistry.web.js.map
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetRegistry.web.js.map b/node_modules/expo-asset/build/AssetRegistry.web.js.map
deleted file mode 100644
index 90fea65..0000000
--- a/node_modules/expo-asset/build/AssetRegistry.web.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"AssetRegistry.web.js","sourceRoot":"","sources":["../src/AssetRegistry.web.ts"],"names":[],"mappings":"AAAA,cAAc,6CAA6C,CAAC","sourcesContent":["export * from 'react-native-web/dist/modules/AssetRegistry';\n"]}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts b/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts
index 7803b29..ae6d3b6 100644
--- a/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts
+++ b/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts
@@ -1,14 +1,4 @@
-declare type PackagerAsset = {
- __packager_asset: boolean;
- fileSystemLocation: string;
- httpServerLocation: string;
- width?: number;
- height?: number;
- scales: number[];
- hash: string;
- name: string;
- type: string;
-};
+import { PackagerAsset } from '@react-native/assets/registry';
export declare type ResolvedAssetSource = {
__packager_asset: boolean;
width?: number;
@@ -17,20 +7,18 @@ export declare type ResolvedAssetSource = {
scale: number;
};
export default class AssetSourceResolver {
- serverUrl?: string | null;
+ serverUrl: string;
jsbundleUrl?: string | null;
asset: PackagerAsset;
constructor(serverUrl: string | undefined | null, jsbundleUrl: string | undefined | null, asset: PackagerAsset);
isLoadedFromServer(): boolean;
isLoadedFromFileSystem(): boolean;
defaultAsset(): ResolvedAssetSource;
+ /**
+ * @returns absolute remote URL for the hosted asset.
+ */
assetServerURL(): ResolvedAssetSource;
- scaledAssetPath(): ResolvedAssetSource;
- scaledAssetURLNearBundle(): ResolvedAssetSource;
- resourceIdentifierWithoutScale(): ResolvedAssetSource;
- drawableFolderInBundle(): ResolvedAssetSource;
fromSource(source: string): ResolvedAssetSource;
static pickScale(scales: number[], deviceScale: number): number;
}
-export {};
//# sourceMappingURL=AssetSourceResolver.web.d.ts.map
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts.map b/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts.map
index e3aa0cf..ec30d08 100644
--- a/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts.map
+++ b/node_modules/expo-asset/build/AssetSourceResolver.web.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"AssetSourceResolver.web.d.ts","sourceRoot":"","sources":["../src/AssetSourceResolver.web.ts"],"names":[],"mappings":"AAIA,aAAK,aAAa,GAAG;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AASF,oBAAY,mBAAmB,GAAG;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAaF,MAAM,CAAC,OAAO,OAAO,mBAAmB;IACtC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,KAAK,EAAE,aAAa,CAAC;gBAGnB,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACpC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,KAAK,EAAE,aAAa;IAMtB,kBAAkB,IAAI,OAAO;IAG7B,sBAAsB,IAAI,OAAO;IAGjC,YAAY,IAAI,mBAAmB;IAOnC,cAAc,IAAI,mBAAmB;IAWrC,eAAe,IAAI,mBAAmB;IAGtC,wBAAwB,IAAI,mBAAmB;IAI/C,8BAA8B,IAAI,mBAAmB;IAGrD,sBAAsB,IAAI,mBAAmB;IAG7C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB;IAU/C,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;CAQhE"}
\ No newline at end of file
+{"version":3,"file":"AssetSourceResolver.web.d.ts","sourceRoot":"","sources":["../src/AssetSourceResolver.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAI9D,oBAAY,mBAAmB,GAAG;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAgBF,MAAM,CAAC,OAAO,OAAO,mBAAmB;IACtC,SAAS,EAAE,MAAM,CAAC;IAGlB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,KAAK,EAAE,aAAa,CAAC;gBAGnB,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACpC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,KAAK,EAAE,aAAa;IAYtB,kBAAkB,IAAI,OAAO;IAK7B,sBAAsB,IAAI,OAAO;IAIjC,YAAY,IAAI,mBAAmB;IAInC;;OAEG;IACH,cAAc,IAAI,mBAAmB;IAQrC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB;IAU/C,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;CAQhE"}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetSourceResolver.web.js b/node_modules/expo-asset/build/AssetSourceResolver.web.js
index 4cc53f2..4ced1b2 100644
--- a/node_modules/expo-asset/build/AssetSourceResolver.web.js
+++ b/node_modules/expo-asset/build/AssetSourceResolver.web.js
@@ -1,71 +1,58 @@
-import { Platform, UnavailabilityError } from 'expo-modules-core';
-import invariant from 'invariant';
+import { Platform } from 'expo-modules-core';
import { Dimensions } from 'react-native';
-function getBasePath({ httpServerLocation }) {
- if (httpServerLocation[0] === '/') {
- return httpServerLocation.substr(1);
- }
- return httpServerLocation;
-}
+// TODO(EvanBacon): This seems like a bad practice on web.
+// The analogous system on web would be a CDN and/or the picture tag.
function getScale() {
return Dimensions.get('window').scale;
}
+// Returns the Metro dev server-specific asset location.
function getScaledAssetPath(asset) {
const scale = AssetSourceResolver.pickScale(asset.scales, getScale());
const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
- const assetDir = getBasePath(asset);
- return assetDir + '/' + asset.name + scaleSuffix + (asset.type ? `.${asset.type}` : '');
+ const type = !asset.type ? '' : `.${asset.type}`;
+ return asset.httpServerLocation + '/' + asset.name + scaleSuffix + type;
}
export default class AssetSourceResolver {
serverUrl;
// where the jsbundle is being run from
+ // NOTE(EvanBacon): Never defined on web.
jsbundleUrl;
// the asset to resolve
asset;
constructor(serverUrl, jsbundleUrl, asset) {
+ if (!serverUrl) {
+ throw new Error('Web assets require a server URL');
+ }
this.serverUrl = serverUrl;
- this.jsbundleUrl = jsbundleUrl;
+ this.jsbundleUrl = null;
this.asset = asset;
}
+ // Always true for web runtimes
isLoadedFromServer() {
- return !!this.serverUrl;
+ return true;
}
+ // Always false for web runtimes
isLoadedFromFileSystem() {
- return !!(this.jsbundleUrl && this.jsbundleUrl.startsWith('file://'));
+ return false;
}
defaultAsset() {
- if (this.isLoadedFromServer()) {
- return this.assetServerURL();
- }
- return this.scaledAssetURLNearBundle();
+ return this.assetServerURL();
}
+ /**
+ * @returns absolute remote URL for the hosted asset.
+ */
assetServerURL() {
- invariant(!!this.serverUrl, 'need server to load from');
- return this.fromSource(this.serverUrl +
- getScaledAssetPath(this.asset) +
- '?platform=' +
- Platform.OS +
- '&hash=' +
- this.asset.hash);
- }
- scaledAssetPath() {
- return this.fromSource(getScaledAssetPath(this.asset));
- }
- scaledAssetURLNearBundle() {
- const path = this.jsbundleUrl || '';
- return this.fromSource(path + getScaledAssetPath(this.asset));
- }
- resourceIdentifierWithoutScale() {
- throw new UnavailabilityError('react-native', 'resourceIdentifierWithoutScale()');
- }
- drawableFolderInBundle() {
- throw new UnavailabilityError('react-native', 'drawableFolderInBundle()');
+ const fromUrl = new URL(this.serverUrl);
+ fromUrl.pathname = getScaledAssetPath(this.asset);
+ fromUrl.searchParams.set('platform', Platform.OS);
+ fromUrl.searchParams.set('hash', this.asset.hash);
+ return this.fromSource(fromUrl.toString());
}
fromSource(source) {
return {
__packager_asset: true,
- width: this.asset.width,
- height: this.asset.height,
+ width: this.asset.width ?? undefined,
+ height: this.asset.height ?? undefined,
uri: source,
scale: AssetSourceResolver.pickScale(this.asset.scales, getScale()),
};
diff --git a/node_modules/expo-asset/build/AssetSourceResolver.web.js.map b/node_modules/expo-asset/build/AssetSourceResolver.web.js.map
index 05b0e6f..5317fb2 100644
--- a/node_modules/expo-asset/build/AssetSourceResolver.web.js.map
+++ b/node_modules/expo-asset/build/AssetSourceResolver.web.js.map
@@ -1 +1 @@
-{"version":3,"file":"AssetSourceResolver.web.js","sourceRoot":"","sources":["../src/AssetSourceResolver.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,SAAS,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAc1C,SAAS,WAAW,CAAC,EAAE,kBAAkB,EAAiB;IACxD,IAAI,kBAAkB,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;QACjC,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;KACrC;IACD,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAUD,SAAS,QAAQ;IACf,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;AACxC,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAK;IAC/B,MAAM,KAAK,GAAG,mBAAmB,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC;IACzD,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,GAAG,WAAW,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,CAAC,OAAO,OAAO,mBAAmB;IACtC,SAAS,CAAiB;IAC1B,uCAAuC;IACvC,WAAW,CAAiB;IAC5B,uBAAuB;IACvB,KAAK,CAAgB;IAErB,YACE,SAAoC,EACpC,WAAsC,EACtC,KAAoB;QAEpB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IACD,kBAAkB;QAChB,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IACD,sBAAsB;QACpB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,YAAY;QACV,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE;YAC7B,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;SAC9B;QAED,OAAO,IAAI,CAAC,wBAAwB,EAAE,CAAC;IACzC,CAAC;IACD,cAAc;QACZ,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,UAAU,CACpB,IAAI,CAAC,SAAS;YACZ,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC;YAC9B,YAAY;YACZ,QAAQ,CAAC,EAAE;YACX,QAAQ;YACR,IAAI,CAAC,KAAK,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;IACD,eAAe;QACb,OAAO,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,wBAAwB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,8BAA8B;QAC5B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,kCAAkC,CAAC,CAAC;IACpF,CAAC;IACD,sBAAsB;QACpB,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;IAC5E,CAAC;IACD,UAAU,CAAC,MAAc;QACvB,OAAO;YACL,gBAAgB,EAAE,IAAI;YACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;YACvB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;YACzB,GAAG,EAAE,MAAM;YACX,KAAK,EAAE,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;SACpE,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,MAAgB,EAAE,WAAmB;QACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE;gBAC5B,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;aAClB;SACF;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;CACF","sourcesContent":["import { Platform, UnavailabilityError } from 'expo-modules-core';\nimport invariant from 'invariant';\nimport { Dimensions } from 'react-native';\n\ntype PackagerAsset = {\n __packager_asset: boolean;\n fileSystemLocation: string;\n httpServerLocation: string;\n width?: number;\n height?: number;\n scales: number[];\n hash: string;\n name: string;\n type: string;\n};\n\nfunction getBasePath({ httpServerLocation }: PackagerAsset): string {\n if (httpServerLocation[0] === '/') {\n return httpServerLocation.substr(1);\n }\n return httpServerLocation;\n}\n\nexport type ResolvedAssetSource = {\n __packager_asset: boolean;\n width?: number;\n height?: number;\n uri: string;\n scale: number;\n};\n\nfunction getScale(): number {\n return Dimensions.get('window').scale;\n}\n\nfunction getScaledAssetPath(asset): string {\n const scale = AssetSourceResolver.pickScale(asset.scales, getScale());\n const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';\n const assetDir = getBasePath(asset);\n return assetDir + '/' + asset.name + scaleSuffix + (asset.type ? `.${asset.type}` : '');\n}\n\nexport default class AssetSourceResolver {\n serverUrl?: string | null;\n // where the jsbundle is being run from\n jsbundleUrl?: string | null;\n // the asset to resolve\n asset: PackagerAsset;\n\n constructor(\n serverUrl: string | undefined | null,\n jsbundleUrl: string | undefined | null,\n asset: PackagerAsset\n ) {\n this.serverUrl = serverUrl;\n this.jsbundleUrl = jsbundleUrl;\n this.asset = asset;\n }\n isLoadedFromServer(): boolean {\n return !!this.serverUrl;\n }\n isLoadedFromFileSystem(): boolean {\n return !!(this.jsbundleUrl && this.jsbundleUrl.startsWith('file://'));\n }\n defaultAsset(): ResolvedAssetSource {\n if (this.isLoadedFromServer()) {\n return this.assetServerURL();\n }\n\n return this.scaledAssetURLNearBundle();\n }\n assetServerURL(): ResolvedAssetSource {\n invariant(!!this.serverUrl, 'need server to load from');\n return this.fromSource(\n this.serverUrl +\n getScaledAssetPath(this.asset) +\n '?platform=' +\n Platform.OS +\n '&hash=' +\n this.asset.hash\n );\n }\n scaledAssetPath(): ResolvedAssetSource {\n return this.fromSource(getScaledAssetPath(this.asset));\n }\n scaledAssetURLNearBundle(): ResolvedAssetSource {\n const path = this.jsbundleUrl || '';\n return this.fromSource(path + getScaledAssetPath(this.asset));\n }\n resourceIdentifierWithoutScale(): ResolvedAssetSource {\n throw new UnavailabilityError('react-native', 'resourceIdentifierWithoutScale()');\n }\n drawableFolderInBundle(): ResolvedAssetSource {\n throw new UnavailabilityError('react-native', 'drawableFolderInBundle()');\n }\n fromSource(source: string): ResolvedAssetSource {\n return {\n __packager_asset: true,\n width: this.asset.width,\n height: this.asset.height,\n uri: source,\n scale: AssetSourceResolver.pickScale(this.asset.scales, getScale()),\n };\n }\n\n static pickScale(scales: number[], deviceScale: number): number {\n for (let i = 0; i < scales.length; i++) {\n if (scales[i] >= deviceScale) {\n return scales[i];\n }\n }\n return scales[scales.length - 1] || 1;\n }\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"AssetSourceResolver.web.js","sourceRoot":"","sources":["../src/AssetSourceResolver.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { PackagerAsset } from '@react-native/assets/registry';\nimport { Platform } from 'expo-modules-core';\nimport { Dimensions } from 'react-native';\n\nexport type ResolvedAssetSource = {\n __packager_asset: boolean;\n width?: number;\n height?: number;\n uri: string;\n scale: number;\n};\n\n// TODO(EvanBacon): This seems like a bad practice on web.\n// The analogous system on web would be a CDN and/or the picture tag.\nfunction getScale(): number {\n return Dimensions.get('window').scale;\n}\n\n// Returns the Metro dev server-specific asset location.\nfunction getScaledAssetPath(asset): string {\n const scale = AssetSourceResolver.pickScale(asset.scales, getScale());\n const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';\n const type = !asset.type ? '' : `.${asset.type}`;\n return asset.httpServerLocation + '/' + asset.name + scaleSuffix + type;\n}\n\nexport default class AssetSourceResolver {\n serverUrl: string;\n // where the jsbundle is being run from\n // NOTE(EvanBacon): Never defined on web.\n jsbundleUrl?: string | null;\n // the asset to resolve\n asset: PackagerAsset;\n\n constructor(\n serverUrl: string | undefined | null,\n jsbundleUrl: string | undefined | null,\n asset: PackagerAsset\n ) {\n if (!serverUrl) {\n throw new Error('Web assets require a server URL');\n }\n\n this.serverUrl = serverUrl;\n this.jsbundleUrl = null;\n this.asset = asset;\n }\n\n // Always true for web runtimes\n isLoadedFromServer(): boolean {\n return true;\n }\n\n // Always false for web runtimes\n isLoadedFromFileSystem(): boolean {\n return false;\n }\n\n defaultAsset(): ResolvedAssetSource {\n return this.assetServerURL();\n }\n\n /**\n * @returns absolute remote URL for the hosted asset.\n */\n assetServerURL(): ResolvedAssetSource {\n const fromUrl = new URL(this.serverUrl);\n fromUrl.pathname = getScaledAssetPath(this.asset);\n fromUrl.searchParams.set('platform', Platform.OS);\n fromUrl.searchParams.set('hash', this.asset.hash);\n return this.fromSource(fromUrl.toString());\n }\n\n fromSource(source: string): ResolvedAssetSource {\n return {\n __packager_asset: true,\n width: this.asset.width ?? undefined,\n height: this.asset.height ?? undefined,\n uri: source,\n scale: AssetSourceResolver.pickScale(this.asset.scales, getScale()),\n };\n }\n\n static pickScale(scales: number[], deviceScale: number): number {\n for (let i = 0; i < scales.length; i++) {\n if (scales[i] >= deviceScale) {\n return scales[i];\n }\n }\n return scales[scales.length - 1] || 1;\n }\n}\n"]}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetSources.d.ts b/node_modules/expo-asset/build/AssetSources.d.ts
index 19ee42c..67d5d5a 100644
--- a/node_modules/expo-asset/build/AssetSources.d.ts
+++ b/node_modules/expo-asset/build/AssetSources.d.ts
@@ -1,11 +1,5 @@
-export declare type AssetMetadata = {
- hash: string;
- name: string;
- type: string;
- width?: number;
- height?: number;
- scales: number[];
- httpServerLocation: string;
+import { PackagerAsset } from './AssetRegistry';
+export declare type AssetMetadata = Pick & {
uri?: string;
fileHashes?: string[];
fileUris?: string[];
diff --git a/node_modules/expo-asset/build/AssetSources.d.ts.map b/node_modules/expo-asset/build/AssetSources.d.ts.map
index 25167c6..965b6b6 100644
--- a/node_modules/expo-asset/build/AssetSources.d.ts.map
+++ b/node_modules/expo-asset/build/AssetSources.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"AssetSources.d.ts","sourceRoot":"","sources":["../src/AssetSources.ts"],"names":[],"mappings":"AASA,oBAAY,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,oBAAY,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,WAAW,CAiElE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAc9C"}
\ No newline at end of file
+{"version":3,"file":"AssetSources.d.ts","sourceRoot":"","sources":["../src/AssetSources.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKhD,oBAAY,aAAa,GAAG,IAAI,CAC9B,aAAa,EACb,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAChF,GAAG;IACF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,oBAAY,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,WAAW,CAiElE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAc9C"}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/AssetSources.js b/node_modules/expo-asset/build/AssetSources.js
index 4c39a6e..480a513 100644
--- a/node_modules/expo-asset/build/AssetSources.js
+++ b/node_modules/expo-asset/build/AssetSources.js
@@ -3,7 +3,7 @@ import path from 'path-browserify';
import { PixelRatio } from 'react-native';
import URL from 'url-parse';
import AssetSourceResolver from './AssetSourceResolver';
-import { manifestBaseUrl, getManifest, getManifest2 } from './PlatformUtils';
+import { getManifest, getManifest2, manifestBaseUrl } from './PlatformUtils';
// Fast lookup check if asset map has any overrides in the manifest
const assetMapOverride = getManifest().assetMapOverride;
/**
diff --git a/node_modules/expo-asset/build/AssetSources.js.map b/node_modules/expo-asset/build/AssetSources.js.map
index 8227354..ba5565c 100644
--- a/node_modules/expo-asset/build/AssetSources.js.map
+++ b/node_modules/expo-asset/build/AssetSources.js.map
@@ -1 +1 @@
-{"version":3,"file":"AssetSources.js","sourceRoot":"","sources":["../src/AssetSources.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'expo-modules-core';\nimport path from 'path-browserify';\nimport { PixelRatio } from 'react-native';\nimport URL from 'url-parse';\n\nimport AssetSourceResolver from './AssetSourceResolver';\nimport { manifestBaseUrl, getManifest, getManifest2 } from './PlatformUtils';\n\n// @docsMissing\nexport type AssetMetadata = {\n hash: string;\n name: string;\n type: string;\n width?: number;\n height?: number;\n scales: number[];\n httpServerLocation: string;\n uri?: string;\n fileHashes?: string[];\n fileUris?: string[];\n};\n\nexport type AssetSource = {\n uri: string;\n hash: string;\n};\n\n// Fast lookup check if asset map has any overrides in the manifest\nconst assetMapOverride = getManifest().assetMapOverride;\n\n/**\n * Selects the best file for the given asset (ex: choosing the best scale for images) and returns\n * a { uri, hash } pair for the specific asset file.\n *\n * If the asset isn't an image with multiple scales, the first file is selected.\n */\nexport function selectAssetSource(meta: AssetMetadata): AssetSource {\n // Override with the asset map in manifest if available\n if (assetMapOverride && assetMapOverride.hasOwnProperty(meta.hash)) {\n meta = { ...meta, ...assetMapOverride[meta.hash] };\n }\n\n // This logic is based on that of AssetSourceResolver, with additional support for file hashes and\n // explicitly provided URIs\n const scale = AssetSourceResolver.pickScale(meta.scales, PixelRatio.get());\n const index = meta.scales.findIndex((s) => s === scale);\n const hash = meta.fileHashes ? meta.fileHashes[index] || meta.fileHashes[0] : meta.hash;\n\n // Allow asset processors to directly provide the URL to load\n const uri = meta.fileUris ? meta.fileUris[index] || meta.fileUris[0] : meta.uri;\n if (uri) {\n return { uri: resolveUri(uri), hash };\n }\n\n // Check if the assetUrl was overridden in the manifest\n const assetUrlOverride = getManifest().assetUrlOverride;\n if (assetUrlOverride) {\n const uri = path.join(assetUrlOverride, hash);\n return { uri: resolveUri(uri), hash };\n }\n\n const fileScale = scale === 1 ? '' : `@${scale}x`;\n const fileExtension = meta.type ? `.${encodeURIComponent(meta.type)}` : '';\n const suffix = `/${encodeURIComponent(\n meta.name\n )}${fileScale}${fileExtension}?platform=${encodeURIComponent(\n Platform.OS\n )}&hash=${encodeURIComponent(meta.hash)}`;\n\n // For assets with a specified absolute URL, we use the existing origin instead of prepending the\n // development server or production CDN URL origin\n if (/^https?:\\/\\//.test(meta.httpServerLocation)) {\n const uri = meta.httpServerLocation + suffix;\n return { uri, hash };\n }\n\n // For assets during development using manifest2, we use the development server's URL origin\n const manifest2 = getManifest2();\n\n if (manifest2?.extra?.expoGo?.developer) {\n const baseUrl = new URL(`http://${manifest2.extra.expoGo.debuggerHost}`);\n baseUrl.set('pathname', meta.httpServerLocation + suffix);\n\n return {\n uri: baseUrl.href,\n hash,\n };\n }\n\n // For assets during development, we use the development server's URL origin\n if (getManifest().developer) {\n const baseUrl = new URL(getManifest().bundleUrl);\n baseUrl.set('pathname', meta.httpServerLocation + suffix);\n return { uri: baseUrl.href, hash };\n }\n\n // Production CDN URIs are based on each asset file hash\n return {\n uri: `https://classic-assets.eascdn.net/~assets/${encodeURIComponent(hash)}`,\n hash,\n };\n}\n\n/**\n * Resolves the given URI to an absolute URI. If the given URI is already an absolute URI, it is\n * simply returned. Otherwise, if it is a relative URI, it is resolved relative to the manifest's\n * base URI.\n */\nexport function resolveUri(uri: string): string {\n if (!manifestBaseUrl) {\n return uri;\n }\n\n const { protocol } = new URL(uri);\n if (protocol !== '') {\n return uri;\n }\n\n const baseUrl = new URL(manifestBaseUrl);\n const resolvedPath = uri.startsWith('/') ? uri : path.join(baseUrl.pathname, uri);\n baseUrl.set('pathname', resolvedPath);\n return baseUrl.href;\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"AssetSources.js","sourceRoot":"","sources":["../src/AssetSources.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'expo-modules-core';\nimport path from 'path-browserify';\nimport { PixelRatio } from 'react-native';\nimport URL from 'url-parse';\n\nimport { PackagerAsset } from './AssetRegistry';\nimport AssetSourceResolver from './AssetSourceResolver';\nimport { getManifest, getManifest2, manifestBaseUrl } from './PlatformUtils';\n\n// @docsMissing\nexport type AssetMetadata = Pick<\n PackagerAsset,\n 'httpServerLocation' | 'name' | 'hash' | 'type' | 'scales' | 'width' | 'height'\n> & {\n uri?: string;\n fileHashes?: string[];\n fileUris?: string[];\n};\n\nexport type AssetSource = {\n uri: string;\n hash: string;\n};\n\n// Fast lookup check if asset map has any overrides in the manifest\nconst assetMapOverride = getManifest().assetMapOverride;\n\n/**\n * Selects the best file for the given asset (ex: choosing the best scale for images) and returns\n * a { uri, hash } pair for the specific asset file.\n *\n * If the asset isn't an image with multiple scales, the first file is selected.\n */\nexport function selectAssetSource(meta: AssetMetadata): AssetSource {\n // Override with the asset map in manifest if available\n if (assetMapOverride && assetMapOverride.hasOwnProperty(meta.hash)) {\n meta = { ...meta, ...assetMapOverride[meta.hash] };\n }\n\n // This logic is based on that of AssetSourceResolver, with additional support for file hashes and\n // explicitly provided URIs\n const scale = AssetSourceResolver.pickScale(meta.scales, PixelRatio.get());\n const index = meta.scales.findIndex((s) => s === scale);\n const hash = meta.fileHashes ? meta.fileHashes[index] || meta.fileHashes[0] : meta.hash;\n\n // Allow asset processors to directly provide the URL to load\n const uri = meta.fileUris ? meta.fileUris[index] || meta.fileUris[0] : meta.uri;\n if (uri) {\n return { uri: resolveUri(uri), hash };\n }\n\n // Check if the assetUrl was overridden in the manifest\n const assetUrlOverride = getManifest().assetUrlOverride;\n if (assetUrlOverride) {\n const uri = path.join(assetUrlOverride, hash);\n return { uri: resolveUri(uri), hash };\n }\n\n const fileScale = scale === 1 ? '' : `@${scale}x`;\n const fileExtension = meta.type ? `.${encodeURIComponent(meta.type)}` : '';\n const suffix = `/${encodeURIComponent(\n meta.name\n )}${fileScale}${fileExtension}?platform=${encodeURIComponent(\n Platform.OS\n )}&hash=${encodeURIComponent(meta.hash)}`;\n\n // For assets with a specified absolute URL, we use the existing origin instead of prepending the\n // development server or production CDN URL origin\n if (/^https?:\\/\\//.test(meta.httpServerLocation)) {\n const uri = meta.httpServerLocation + suffix;\n return { uri, hash };\n }\n\n // For assets during development using manifest2, we use the development server's URL origin\n const manifest2 = getManifest2();\n\n if (manifest2?.extra?.expoGo?.developer) {\n const baseUrl = new URL(`http://${manifest2.extra.expoGo.debuggerHost}`);\n baseUrl.set('pathname', meta.httpServerLocation + suffix);\n\n return {\n uri: baseUrl.href,\n hash,\n };\n }\n\n // For assets during development, we use the development server's URL origin\n if (getManifest().developer) {\n const baseUrl = new URL(getManifest().bundleUrl);\n baseUrl.set('pathname', meta.httpServerLocation + suffix);\n return { uri: baseUrl.href, hash };\n }\n\n // Production CDN URIs are based on each asset file hash\n return {\n uri: `https://classic-assets.eascdn.net/~assets/${encodeURIComponent(hash)}`,\n hash,\n };\n}\n\n/**\n * Resolves the given URI to an absolute URI. If the given URI is already an absolute URI, it is\n * simply returned. Otherwise, if it is a relative URI, it is resolved relative to the manifest's\n * base URI.\n */\nexport function resolveUri(uri: string): string {\n if (!manifestBaseUrl) {\n return uri;\n }\n\n const { protocol } = new URL(uri);\n if (protocol !== '') {\n return uri;\n }\n\n const baseUrl = new URL(manifestBaseUrl);\n const resolvedPath = uri.startsWith('/') ? uri : path.join(baseUrl.pathname, uri);\n baseUrl.set('pathname', resolvedPath);\n return baseUrl.href;\n}\n"]}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/PlatformUtils.js b/node_modules/expo-asset/build/PlatformUtils.js
index 198d5d8..dfd9834 100644
--- a/node_modules/expo-asset/build/PlatformUtils.js
+++ b/node_modules/expo-asset/build/PlatformUtils.js
@@ -45,13 +45,13 @@ export async function downloadAsync(uri, hash, type, name) {
async function _downloadAsyncManagedEnv(uri, hash, type, name) {
const cacheFileId = hash || computeMd5(uri);
const localUri = `${FileSystem.cacheDirectory}ExponentAsset-${cacheFileId}.${type}`;
- let { exists, md5 } = await FileSystem.getInfoAsync(localUri, {
+ const fileInfo = await FileSystem.getInfoAsync(localUri, {
md5: true,
});
- if (!exists || (hash !== null && md5 !== hash)) {
- ({ md5 } = await FileSystem.downloadAsync(uri, localUri, {
+ if (!fileInfo.exists || (hash !== null && fileInfo.md5 !== hash)) {
+ const { md5 } = await FileSystem.downloadAsync(uri, localUri, {
md5: true,
- }));
+ });
if (hash !== null && md5 !== hash) {
throw new Error(`Downloaded file for asset '${name}.${type}' ` +
`Located at ${uri} ` +
diff --git a/node_modules/expo-asset/build/PlatformUtils.js.map b/node_modules/expo-asset/build/PlatformUtils.js.map
index 779d049..155ffa2 100644
--- a/node_modules/expo-asset/build/PlatformUtils.js.map
+++ b/node_modules/expo-asset/build/PlatformUtils.js.map
@@ -1 +1 @@
-{"version":3,"file":"PlatformUtils.js","sourceRoot":"","sources":["../src/PlatformUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import computeMd5 from 'blueimp-md5';\nimport Constants from 'expo-constants';\nimport { Manifest } from 'expo-constants/build/Constants.types';\nimport * as FileSystem from 'expo-file-system';\nimport { NativeModulesProxy } from 'expo-modules-core';\n\nimport { getManifestBaseUrl } from './AssetUris';\n\n// Constants.appOwnership is only available in managed apps (Expo client and standalone)\nexport const IS_MANAGED_ENV = !!Constants.appOwnership;\n\n// In the future (SDK38+) expo-updates is likely to be used in managed apps, so we decide\n// that you are in a bare app with updates if you're not in a managed app and you have\n// local assets available.\nexport const IS_BARE_ENV_WITH_UPDATES =\n !IS_MANAGED_ENV &&\n !!NativeModulesProxy.ExpoUpdates?.isEnabled &&\n // if expo-updates is installed but we're running directly from the embedded bundle, we don't want\n // to override the AssetSourceResolver\n !NativeModulesProxy.ExpoUpdates?.isUsingEmbeddedAssets;\n\nexport const IS_ENV_WITH_UPDATES_ENABLED = IS_MANAGED_ENV || IS_BARE_ENV_WITH_UPDATES;\n\n// If it's not managed or bare w/ updates, then it must be bare w/o updates!\nexport const IS_BARE_ENV_WITHOUT_UPDATES = !IS_MANAGED_ENV && !IS_BARE_ENV_WITH_UPDATES;\n\n// Get the localAssets property from the ExpoUpdates native module so that we do\n// not need to include expo-updates as a dependency of expo-asset\nexport function getLocalAssets() {\n return NativeModulesProxy.ExpoUpdates?.localAssets ?? {};\n}\n\nexport function getManifest(): { [key: string]: any } {\n return Constants.__unsafeNoWarnManifest ?? {};\n}\n\nexport function getManifest2(): Manifest | undefined {\n return Constants.__unsafeNoWarnManifest2;\n}\n\n// Compute manifest base URL if available\nexport const manifestBaseUrl = Constants.experienceUrl\n ? getManifestBaseUrl(Constants.experienceUrl)\n : null;\n\n// TODO: how should this behave in bare app with updates? re: hashAssetFiles\nexport async function downloadAsync(uri, hash, type, name): Promise {\n if (IS_MANAGED_ENV) {\n return _downloadAsyncManagedEnv(uri, hash, type, name);\n }\n\n return _downloadAsyncUnmanagedEnv(uri, hash, type);\n}\n\n/**\n * Check if the file exists on disk already, perform integrity check if so.\n * Otherwise, download it.\n */\nasync function _downloadAsyncManagedEnv(uri, hash, type, name): Promise {\n const cacheFileId = hash || computeMd5(uri);\n const localUri = `${FileSystem.cacheDirectory}ExponentAsset-${cacheFileId}.${type}`;\n let { exists, md5 } = await FileSystem.getInfoAsync(localUri, {\n md5: true,\n });\n if (!exists || (hash !== null && md5 !== hash)) {\n ({ md5 } = await FileSystem.downloadAsync(uri, localUri, {\n md5: true,\n }));\n if (hash !== null && md5 !== hash) {\n throw new Error(\n `Downloaded file for asset '${name}.${type}' ` +\n `Located at ${uri} ` +\n `failed MD5 integrity check`\n );\n }\n }\n return localUri;\n}\n\n/**\n * Just download the asset, don't perform integrity check because we don't have\n * the hash to compare it with (we don't have hashAssetFiles plugin). Hash is\n * only used for the file name.\n */\nasync function _downloadAsyncUnmanagedEnv(uri, hash, type): Promise {\n // TODO: does this make sense to bail out if it's already at a file URL\n // because it's already available locally?\n if (uri.startsWith('file://')) {\n return uri;\n }\n\n const cacheFileId = hash || computeMd5(uri);\n const localUri = `${FileSystem.cacheDirectory}ExponentAsset-${cacheFileId}.${type}`;\n\n // We don't check the FileSystem for an existing version of the asset and we\n // also don't perform an integrity check!\n await FileSystem.downloadAsync(uri, localUri);\n return localUri;\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"PlatformUtils.js","sourceRoot":"","sources":["../src/PlatformUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import computeMd5 from 'blueimp-md5';\nimport Constants from 'expo-constants';\nimport { Manifest } from 'expo-constants/build/Constants.types';\nimport * as FileSystem from 'expo-file-system';\nimport { NativeModulesProxy } from 'expo-modules-core';\n\nimport { getManifestBaseUrl } from './AssetUris';\n\n// Constants.appOwnership is only available in managed apps (Expo client and standalone)\nexport const IS_MANAGED_ENV = !!Constants.appOwnership;\n\n// In the future (SDK38+) expo-updates is likely to be used in managed apps, so we decide\n// that you are in a bare app with updates if you're not in a managed app and you have\n// local assets available.\nexport const IS_BARE_ENV_WITH_UPDATES =\n !IS_MANAGED_ENV &&\n !!NativeModulesProxy.ExpoUpdates?.isEnabled &&\n // if expo-updates is installed but we're running directly from the embedded bundle, we don't want\n // to override the AssetSourceResolver\n !NativeModulesProxy.ExpoUpdates?.isUsingEmbeddedAssets;\n\nexport const IS_ENV_WITH_UPDATES_ENABLED = IS_MANAGED_ENV || IS_BARE_ENV_WITH_UPDATES;\n\n// If it's not managed or bare w/ updates, then it must be bare w/o updates!\nexport const IS_BARE_ENV_WITHOUT_UPDATES = !IS_MANAGED_ENV && !IS_BARE_ENV_WITH_UPDATES;\n\n// Get the localAssets property from the ExpoUpdates native module so that we do\n// not need to include expo-updates as a dependency of expo-asset\nexport function getLocalAssets() {\n return NativeModulesProxy.ExpoUpdates?.localAssets ?? {};\n}\n\nexport function getManifest(): { [key: string]: any } {\n return Constants.__unsafeNoWarnManifest ?? {};\n}\n\nexport function getManifest2(): Manifest | undefined {\n return Constants.__unsafeNoWarnManifest2;\n}\n\n// Compute manifest base URL if available\nexport const manifestBaseUrl = Constants.experienceUrl\n ? getManifestBaseUrl(Constants.experienceUrl)\n : null;\n\n// TODO: how should this behave in bare app with updates? re: hashAssetFiles\nexport async function downloadAsync(uri, hash, type, name): Promise {\n if (IS_MANAGED_ENV) {\n return _downloadAsyncManagedEnv(uri, hash, type, name);\n }\n\n return _downloadAsyncUnmanagedEnv(uri, hash, type);\n}\n\n/**\n * Check if the file exists on disk already, perform integrity check if so.\n * Otherwise, download it.\n */\nasync function _downloadAsyncManagedEnv(uri, hash, type, name): Promise {\n const cacheFileId = hash || computeMd5(uri);\n const localUri = `${FileSystem.cacheDirectory}ExponentAsset-${cacheFileId}.${type}`;\n const fileInfo = await FileSystem.getInfoAsync(localUri, {\n md5: true,\n });\n if (!fileInfo.exists || (hash !== null && fileInfo.md5 !== hash)) {\n const { md5 } = await FileSystem.downloadAsync(uri, localUri, {\n md5: true,\n });\n if (hash !== null && md5 !== hash) {\n throw new Error(\n `Downloaded file for asset '${name}.${type}' ` +\n `Located at ${uri} ` +\n `failed MD5 integrity check`\n );\n }\n }\n return localUri;\n}\n\n/**\n * Just download the asset, don't perform integrity check because we don't have\n * the hash to compare it with (we don't have hashAssetFiles plugin). Hash is\n * only used for the file name.\n */\nasync function _downloadAsyncUnmanagedEnv(uri, hash, type): Promise {\n // TODO: does this make sense to bail out if it's already at a file URL\n // because it's already available locally?\n if (uri.startsWith('file://')) {\n return uri;\n }\n\n const cacheFileId = hash || computeMd5(uri);\n const localUri = `${FileSystem.cacheDirectory}ExponentAsset-${cacheFileId}.${type}`;\n\n // We don't check the FileSystem for an existing version of the asset and we\n // also don't perform an integrity check!\n await FileSystem.downloadAsync(uri, localUri);\n return localUri;\n}\n"]}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/resolveAssetSource.web.d.ts.map b/node_modules/expo-asset/build/resolveAssetSource.web.d.ts.map
index 449e86f..dfe9e30 100644
--- a/node_modules/expo-asset/build/resolveAssetSource.web.d.ts.map
+++ b/node_modules/expo-asset/build/resolveAssetSource.web.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"resolveAssetSource.web.d.ts","sourceRoot":"","sources":["../src/resolveAssetSource.web.ts"],"names":[],"mappings":"AAGA,OAAO,mBAAmB,EAAE,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAoCjF,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,mBAAmB,GAClE,IAAI,CAEN;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,MAAM,EAAE,GAAG,GAAG,mBAAmB,GAAG,SAAS,CAevF;AAQD,eAAO,MAAQ,SAAS,sCAAwB,CAAC"}
\ No newline at end of file
+{"version":3,"file":"resolveAssetSource.web.d.ts","sourceRoot":"","sources":["../src/resolveAssetSource.web.ts"],"names":[],"mappings":"AACA,OAAO,mBAAmB,EAAE,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAIjF,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,mBAAmB,GAClE,IAAI,CAEN;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,MAAM,EAAE,GAAG,GAAG,mBAAmB,GAAG,SAAS,CAevF;AAQD,eAAO,MAAQ,SAAS,sCAAwB,CAAC"}
\ No newline at end of file
diff --git a/node_modules/expo-asset/build/resolveAssetSource.web.js b/node_modules/expo-asset/build/resolveAssetSource.web.js
index e91b78a..98e7669 100644
--- a/node_modules/expo-asset/build/resolveAssetSource.web.js
+++ b/node_modules/expo-asset/build/resolveAssetSource.web.js
@@ -1,35 +1,6 @@
-import { NativeModules } from 'react-native';
import { getAssetByID } from './AssetRegistry';
import AssetSourceResolver from './AssetSourceResolver';
let _customSourceTransformer;
-let _serverURL;
-let _sourceCodeScriptURL;
-function getSourceCodeScriptURL() {
- if (_sourceCodeScriptURL) {
- return _sourceCodeScriptURL;
- }
- let sourceCode = typeof nativeExtensions !== 'undefined' ? nativeExtensions.SourceCode : null;
- if (!sourceCode) {
- sourceCode = NativeModules?.SourceCode;
- }
- _sourceCodeScriptURL = sourceCode?.scriptURL;
- return _sourceCodeScriptURL;
-}
-function getDevServerURL() {
- if (_serverURL === undefined) {
- const sourceCodeScriptURL = getSourceCodeScriptURL();
- const match = sourceCodeScriptURL && sourceCodeScriptURL.match(/^https?:\/\/.*?\//);
- if (match) {
- // jsBundle was loaded from network
- _serverURL = match[0];
- }
- else {
- // jsBundle was loaded from file
- _serverURL = null;
- }
- }
- return _serverURL;
-}
export function setCustomSourceTransformer(transformer) {
_customSourceTransformer = transformer;
}
@@ -45,7 +16,7 @@ export default function resolveAssetSource(source) {
if (!asset) {
return undefined;
}
- const resolver = new AssetSourceResolver(getDevServerURL(), null, asset);
+ const resolver = new AssetSourceResolver(location.origin, null, asset);
if (_customSourceTransformer) {
return _customSourceTransformer(resolver);
}
diff --git a/node_modules/expo-asset/build/resolveAssetSource.web.js.map b/node_modules/expo-asset/build/resolveAssetSource.web.js.map
index ac6c56d..ba384b1 100644
--- a/node_modules/expo-asset/build/resolveAssetSource.web.js.map
+++ b/node_modules/expo-asset/build/resolveAssetSource.web.js.map
@@ -1 +1 @@
-{"version":3,"file":"resolveAssetSource.web.js","sourceRoot":"","sources":["../src/resolveAssetSource.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,mBAA4C,MAAM,uBAAuB,CAAC;AAIjF,IAAI,wBAAwB,CAAC;AAC7B,IAAI,UAAqC,CAAC;AAC1C,IAAI,oBAA+C,CAAC;AAEpD,SAAS,sBAAsB;IAC7B,IAAI,oBAAoB,EAAE;QACxB,OAAO,oBAAoB,CAAC;KAC7B;IAED,IAAI,UAAU,GAAG,OAAO,gBAAgB,KAAK,WAAW,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9F,IAAI,CAAC,UAAU,EAAE;QACf,UAAU,GAAG,aAAa,EAAE,UAAU,CAAC;KACxC;IACD,oBAAoB,GAAG,UAAU,EAAE,SAAS,CAAC;IAC7C,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,UAAU,KAAK,SAAS,EAAE;QAC5B,MAAM,mBAAmB,GAAG,sBAAsB,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,mBAAmB,IAAI,mBAAmB,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACpF,IAAI,KAAK,EAAE;YACT,mCAAmC;YACnC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;SACvB;aAAM;YACL,gCAAgC;YAChC,UAAU,GAAG,IAAI,CAAC;SACnB;KACF;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,WAAmE;IAEnE,wBAAwB,GAAG,WAAW,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,MAAW;IACpD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,OAAO,MAAM,CAAC;KACf;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,SAAS,CAAC;KAClB;IAED,MAAM,QAAQ,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACzE,IAAI,wBAAwB,EAAE;QAC5B,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAC;KAC3C;IACD,OAAO,QAAQ,CAAC,YAAY,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,cAAc,CAAC,kBAAkB,EAAE,4BAA4B,EAAE;IACtE,GAAG;QACD,OAAO,0BAA0B,CAAC;IACpC,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,mBAAmB,CAAC","sourcesContent":["import { NativeModules } from 'react-native';\n\nimport { getAssetByID } from './AssetRegistry';\nimport AssetSourceResolver, { ResolvedAssetSource } from './AssetSourceResolver';\n\ndeclare let nativeExtensions: { SourceCode?: { scriptURL: string } } | undefined;\n\nlet _customSourceTransformer;\nlet _serverURL: string | undefined | null;\nlet _sourceCodeScriptURL: string | undefined | null;\n\nfunction getSourceCodeScriptURL(): string | undefined | null {\n if (_sourceCodeScriptURL) {\n return _sourceCodeScriptURL;\n }\n\n let sourceCode = typeof nativeExtensions !== 'undefined' ? nativeExtensions.SourceCode : null;\n if (!sourceCode) {\n sourceCode = NativeModules?.SourceCode;\n }\n _sourceCodeScriptURL = sourceCode?.scriptURL;\n return _sourceCodeScriptURL;\n}\n\nfunction getDevServerURL(): string | null {\n if (_serverURL === undefined) {\n const sourceCodeScriptURL = getSourceCodeScriptURL();\n const match = sourceCodeScriptURL && sourceCodeScriptURL.match(/^https?:\\/\\/.*?\\//);\n if (match) {\n // jsBundle was loaded from network\n _serverURL = match[0];\n } else {\n // jsBundle was loaded from file\n _serverURL = null;\n }\n }\n return _serverURL;\n}\n\nexport function setCustomSourceTransformer(\n transformer: (resolver: AssetSourceResolver) => ResolvedAssetSource\n): void {\n _customSourceTransformer = transformer;\n}\n\n/**\n * `source` is either a number (opaque type returned by require('./foo.png'))\n * or an `ImageSource` like { uri: '' }\n */\nexport default function resolveAssetSource(source: any): ResolvedAssetSource | undefined {\n if (typeof source === 'object') {\n return source;\n }\n\n const asset = getAssetByID(source);\n if (!asset) {\n return undefined;\n }\n\n const resolver = new AssetSourceResolver(getDevServerURL(), null, asset);\n if (_customSourceTransformer) {\n return _customSourceTransformer(resolver);\n }\n return resolver.defaultAsset();\n}\n\nObject.defineProperty(resolveAssetSource, 'setCustomSourceTransformer', {\n get() {\n return setCustomSourceTransformer;\n },\n});\n\nexport const { pickScale } = AssetSourceResolver;\n"]}
\ No newline at end of file
+{"version":3,"file":"resolveAssetSource.web.js","sourceRoot":"","sources":["../src/resolveAssetSource.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,mBAA4C,MAAM,uBAAuB,CAAC;AAEjF,IAAI,wBAAwB,CAAC;AAE7B,MAAM,UAAU,0BAA0B,CACxC,WAAmE;IAEnE,wBAAwB,GAAG,WAAW,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,MAAW;IACpD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,OAAO,MAAM,CAAC;KACf;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,SAAS,CAAC;KAClB;IAED,MAAM,QAAQ,GAAG,IAAI,mBAAmB,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACvE,IAAI,wBAAwB,EAAE;QAC5B,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAC;KAC3C;IACD,OAAO,QAAQ,CAAC,YAAY,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,cAAc,CAAC,kBAAkB,EAAE,4BAA4B,EAAE;IACtE,GAAG;QACD,OAAO,0BAA0B,CAAC;IACpC,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,mBAAmB,CAAC","sourcesContent":["import { getAssetByID } from './AssetRegistry';\nimport AssetSourceResolver, { ResolvedAssetSource } from './AssetSourceResolver';\n\nlet _customSourceTransformer;\n\nexport function setCustomSourceTransformer(\n transformer: (resolver: AssetSourceResolver) => ResolvedAssetSource\n): void {\n _customSourceTransformer = transformer;\n}\n\n/**\n * `source` is either a number (opaque type returned by require('./foo.png'))\n * or an `ImageSource` like { uri: '' }\n */\nexport default function resolveAssetSource(source: any): ResolvedAssetSource | undefined {\n if (typeof source === 'object') {\n return source;\n }\n\n const asset = getAssetByID(source);\n if (!asset) {\n return undefined;\n }\n\n const resolver = new AssetSourceResolver(location.origin, null, asset);\n if (_customSourceTransformer) {\n return _customSourceTransformer(resolver);\n }\n return resolver.defaultAsset();\n}\n\nObject.defineProperty(resolveAssetSource, 'setCustomSourceTransformer', {\n get() {\n return setCustomSourceTransformer;\n },\n});\n\nexport const { pickScale } = AssetSourceResolver;\n"]}
\ No newline at end of file
```
Summary
Loading assets from a 'base' route (e.g.
/somepath
) works correctly, loading them from/assets/[path to assets]
.When attempting to load assets such as fonts from a nested path (e.g.
/nested/123
), the page attempts to load them from/nested/assets/[path to assets]
which is incorrect and leads to the page not rendering correctly. This only happens if you visit the page URL directly, or refresh the browser while on that page.This happens with locally-sourced assets (e.g. those hosted inside the
assets
folder) but also with node_modules (e.g. theexpo-google-fonts
packages exhibit the same behaviour).This test was done on the web platform - I haven't explicitly tested on mobile/native as there is no way to refresh the page to trigger the bug.
For clarification, I'm unsure if this is a router-specific issue or a bundler issue. Please move to the appropriate repo if this is not the correct one.
Minimal reproducible example
https://github.com/ChronSyn/expo-router_bug-report-assetpath