@expo/metro-config
Advanced tools
Comparing version 0.20.0-canary-20241211-61c49bd to 0.20.0-canary-20250122-166c2cb
@@ -53,13 +53,2 @@ "use strict"; | ||
const debug = require('debug')('expo:metro:config'); | ||
function getAssetPlugins(projectRoot) { | ||
const hashAssetFilesPath = resolve_from_1.default.silent(projectRoot, 'expo-asset/tools/hashAssetFiles'); | ||
if (!hashAssetFilesPath) { | ||
throw new Error(`The required package \`expo-asset\` cannot be found`); | ||
} | ||
return [ | ||
// Use relative path to ensure maximum cache hits. | ||
// This is resolved here https://github.com/facebook/metro/blob/ec584b9cc2b8356356a4deacb7e1d5c83f243c3a/packages/metro/src/Assets.js#L271 | ||
'expo-asset/tools/hashAssetFiles', | ||
]; | ||
} | ||
let hasWarnedAboutExotic = false; | ||
@@ -318,3 +307,2 @@ // Patch Metro's graph to support always parsing certain modules. This enables | ||
assetRegistryPath: '@react-native/assets-registry/registry', | ||
assetPlugins: getAssetPlugins(projectRoot), | ||
// hermesParser: true, | ||
@@ -321,0 +309,0 @@ getTransformOptions: async () => ({ |
@@ -8,3 +8,3 @@ /** | ||
*/ | ||
import { AssetData, Module } from 'metro'; | ||
import type { AssetData, Module } from 'metro'; | ||
import { ReadOnlyDependencies } from '../serializer/getCssDeps'; | ||
@@ -11,0 +11,0 @@ type Options = { |
@@ -9,6 +9,7 @@ "use strict"; | ||
const js_1 = require("metro/src/DeltaBundler/Serializers/helpers/js"); | ||
const node_assert_1 = __importDefault(require("node:assert")); | ||
const node_crypto_1 = __importDefault(require("node:crypto")); | ||
const node_fs_1 = __importDefault(require("node:fs")); | ||
const node_path_1 = __importDefault(require("node:path")); | ||
function md5Hash(data) { | ||
const debug = require('debug')('expo:metro-config:assets'); | ||
function getMD5ForData(data) { | ||
if (data.length === 1) | ||
@@ -20,8 +21,49 @@ return data[0]; | ||
} | ||
function assertHashedAssetData(data) { | ||
(0, node_assert_1.default)('fileHashes' in data, 'Assets must have hashed files. Ensure the expo-asset plugin is installed.'); | ||
function getMD5ForFilePathAsync(path) { | ||
return new Promise((resolve, reject) => { | ||
const output = node_crypto_1.default.createHash('md5'); | ||
const input = node_fs_1.default.createReadStream(path); | ||
input.on('error', (err) => reject(err)); | ||
output.on('error', (err) => reject(err)); | ||
output.once('readable', () => resolve(output.read().toString('hex'))); | ||
input.pipe(output); | ||
}); | ||
} | ||
function isHashedAssetData(asset) { | ||
if ('fileHashes' in asset && Array.isArray(asset.fileHashes)) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
async function ensureOtaAssetHashesAsync(asset) { | ||
// Legacy cases where people have the `expo-asset/tools/hashAssetFiles` set still. | ||
if (isHashedAssetData(asset)) { | ||
debug('fileHashes already added, skipping injection for: ' + asset.name); | ||
return asset; | ||
} | ||
const hashes = await Promise.all(asset.files.map(getMD5ForFilePathAsync)); | ||
// New version where we run the asset plugin every time. | ||
asset.fileHashes = hashes; | ||
// Convert the `../` segments of the server URL to `_` to support monorepos. | ||
// This same transformation takes place in `AssetSourceResolver.web` (expo-assets, expo-image) and `persistMetroAssets` of Expo CLI, | ||
// this originally came from the Metro opinion https://github.com/react-native-community/cli/blob/2204d357379e2067cebe2791e90388f7e97fc5f5/packages/cli-plugin-metro/src/commands/bundle/getAssetDestPathIOS.ts#L19C5-L19C10 | ||
if (asset.httpServerLocation.includes('?export_path=')) { | ||
// @ts-expect-error: marked as read-only | ||
asset.httpServerLocation = asset.httpServerLocation | ||
.match(/\?export_path=(.*)/)[1] | ||
.replace(/\.\.\//g, '_'); | ||
} | ||
// URL encode asset paths defined as `?export_path` or `?unstable_path` query parameters. | ||
// Decoding should be done automatically when parsing the URL through Node or the browser. | ||
const assetPathQueryParameter = asset.httpServerLocation.match(/\?(export_path|unstable_path)=(.*)/); | ||
if (assetPathQueryParameter && assetPathQueryParameter[2]) { | ||
const assetPath = assetPathQueryParameter[2]; | ||
// @ts-expect-error: marked as read-only | ||
asset.httpServerLocation = asset.httpServerLocation.replace(assetPath, encodeURIComponent(assetPath)); | ||
} | ||
return asset; | ||
} | ||
async function getUniversalAssetData(assetPath, localPath, assetDataPlugins, platform, publicPath) { | ||
const data = await (0, Assets_1.getAssetData)(assetPath, localPath, assetDataPlugins, platform, publicPath); | ||
assertHashedAssetData(data); | ||
const metroAssetData = await (0, Assets_1.getAssetData)(assetPath, localPath, assetDataPlugins, platform, publicPath); | ||
const data = await ensureOtaAssetHashesAsync(metroAssetData); | ||
// NOTE(EvanBacon): This is where we modify the asset to include a hash in the name for web cache invalidation. | ||
@@ -32,3 +74,3 @@ if (platform === 'web' && publicPath.includes('?export_path=')) { | ||
// @ts-expect-error: name is typed as readonly. | ||
data.name = `${data.name}.${md5Hash(data.fileHashes)}`; | ||
data.name = `${data.name}.${getMD5ForData(data.fileHashes)}`; | ||
} | ||
@@ -35,0 +77,0 @@ return data; |
{ | ||
"name": "@expo/metro-config", | ||
"version": "0.20.0-canary-20241211-61c49bd", | ||
"version": "0.20.0-canary-20250122-166c2cb", | ||
"description": "A Metro config for running React Native projects with the Metro bundler", | ||
@@ -41,5 +41,5 @@ "main": "build/ExpoMetroConfig.js", | ||
"@babel/types": "^7.20.0", | ||
"@expo/config": "11.0.0-canary-20241211-61c49bd", | ||
"@expo/env": "0.4.1-canary-20241211-61c49bd", | ||
"@expo/json-file": "9.0.1-canary-20241211-61c49bd", | ||
"@expo/config": "11.0.0-canary-20250122-166c2cb", | ||
"@expo/env": "1.0.1-canary-20250122-166c2cb", | ||
"@expo/json-file": "9.0.2-canary-20250122-166c2cb", | ||
"@expo/spawn-async": "^1.7.2", | ||
@@ -60,3 +60,3 @@ "chalk": "^4.1.0", | ||
"dedent": "^1.5.3", | ||
"expo-module-scripts": "4.0.3-canary-20241211-61c49bd", | ||
"expo-module-scripts": "4.0.4-canary-20250122-166c2cb", | ||
"sass": "^1.60.0" | ||
@@ -63,0 +63,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Unstable ownership
Supply chain riskA new collaborator has begun publishing package versions. Package stability and security risk may be elevated.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
468603
6601
1
2
+ Added@expo/config@11.0.0-canary-20250122-166c2cb(transitive)
+ Added@expo/config-plugins@9.0.15-canary-20250122-166c2cb(transitive)
+ Added@expo/config-types@53.0.0-canary-20250122-166c2cb(transitive)
+ Added@expo/env@1.0.1-canary-20250122-166c2cb(transitive)
+ Added@expo/json-file@9.0.2-canary-20250122-166c2cb(transitive)
+ Added@expo/plist@0.2.2-canary-20250122-166c2cb(transitive)
- Removed@expo/config@11.0.0-canary-20241211-61c49bd(transitive)
- Removed@expo/config-plugins@9.0.13-canary-20241211-61c49bd(transitive)
- Removed@expo/config-types@53.0.0-canary-20241211-61c49bd(transitive)
- Removed@expo/env@0.4.1-canary-20241211-61c49bd(transitive)
- Removed@expo/json-file@9.0.1-canary-20241211-61c49bd(transitive)
- Removed@expo/plist@0.2.1-canary-20241211-61c49bd(transitive)