Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/honest-glasses-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack": minor
---

Auto device scale resolution for inlined assets
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ async function compileBundle(
platform,
}),
new VirtualModulesPlugin({
...virtualModules,
'node_modules/react-native/Libraries/Image/AssetRegistry.js':
'module.exports = { registerAsset: (spec) => spec };',
'node_modules/react-native/Libraries/Utilities/PixelRatio.js':
'module.exports = { get: () => 1 };',
'node_modules/react-native/Libraries/Image/AssetSourceResolver.js':
'module.exports = { pickScale: (scales, pixelRatio) => scales[pixelRatio - 1] };',
...virtualModules,
}),
],
});
Expand Down Expand Up @@ -205,10 +209,15 @@ describe('assetLoader', () => {
});
});

it('with scales', async () => {
it.each([
{ prefferedScale: 1 },
{ prefferedScale: 2 },
{ prefferedScale: 3 },
])('with scales', async ({ prefferedScale }) => {
const { code } = await compileBundle(
'android',
{
'node_modules/react-native/Libraries/Utilities/PixelRatio.js': `module.exports = { get: () => ${prefferedScale} };`,
'./index.js': "export { default } from './__fixtures__/star.png';",
},
true
Expand All @@ -235,14 +244,12 @@ describe('assetLoader', () => {
).toString('base64'),
]);

expect(context.Export?.default).toEqual(
logos.map((logo, index) => ({
uri: `data:image/png;base64,${logo}`,
scale: index + 1,
height: 272,
width: 286,
}))
);
expect(context.Export?.default).toEqual({
uri: `data:image/png;base64,${logos[prefferedScale - 1]}`,
width: 286,
height: 272,
scale: prefferedScale,
});
});
});
});
23 changes: 18 additions & 5 deletions packages/repack/src/webpack/loaders/assetsLoader/inlineAssets.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dedent from 'dedent';
import mimeTypes from 'mime-types';
import type { Asset, ImageSize, URISource } from './types';
import { getImageSize } from './utils';
Expand All @@ -18,15 +19,27 @@ export function inlineAssets({

if (!mimeType) {
throw new Error(
`Cannot inline asset for request ${resourcePath} - unable to detect mime type`
`Cannot inline asset for request ${resourcePath} - unable to detect MIME type`
);
}

const sourceSet = assets.map((asset) => encodeAsset(asset, mimeType, size));
// keys are always converted to strings
const sourceSet = assets.reduce((sources, asset) => {
sources[asset.scale] = encodeAsset(asset, mimeType, size);
return sources;
}, {} as Record<string, URISource>);

return `module.exports = ${JSON.stringify(
sourceSet.length === 1 ? sourceSet[0] : sourceSet
)}`;
const scales = JSON.stringify(Object.keys(sourceSet).map(Number));

// we need to import PixelRatio to remain compatible
// with older versions of React-Native
return dedent`
var PixelRatio = require('react-native/Libraries/Utilities/PixelRatio');
var AssetSourceResolver = require('react-native/Libraries/Image/AssetSourceResolver');
var prefferedScale = AssetSourceResolver.pickScale(${scales}, PixelRatio.get());

module.exports = ${JSON.stringify(sourceSet)}[prefferedScale];
`;
}

function encodeAsset(
Expand Down