Skip to content
Open
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/add-max-inline-size-option.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack": minor
---

Add `maxInlineSize` option to assets loader for size-based asset inlining. Assets whose largest variant is within the threshold are inlined as base64 URIs; larger assets are extracted as separate files.
10 changes: 9 additions & 1 deletion packages/repack/src/loaders/assetsLoader/assetsLoader.ts
Comment thread
bartekkrok marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,16 @@ export default async function repackAssetsLoader(
})
);

const largestVariantSize = Math.max(
...assets.map((asset) => asset.data.length)
);
const shouldInlineAsset =
!!options.inline ||
(!!options.maxInlineSize &&
largestVariantSize <= options.maxInlineSize);
Comment thread
bartekkrok marked this conversation as resolved.

let result: string;
if (options.inline) {
if (shouldInlineAsset) {
logger.debug(`Inlining assets for request ${resourcePath}`);
result = inlineAssets({ assets, resourcePath });
} else {
Expand Down
2 changes: 2 additions & 0 deletions packages/repack/src/loaders/assetsLoader/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface AssetLoaderOptions {
scalableAssetExtensions?: string[];
scalableAssetResolutions?: string[];
inline?: boolean;
maxInlineSize?: number;
publicPath?: string;
remote?: AssetLoaderRemoteOptions;
}
Expand All @@ -39,6 +40,7 @@ export const optionsSchema: Schema = {
type: 'array',
},
inline: { type: 'boolean' },
maxInlineSize: { type: 'number' },
publicPath: { type: 'string' },
remote: {
type: 'object',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ exports[`getAssetTransformRules should add SVGR rule when svg="svgr" 1`] = `
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": undefined,
"remote": undefined,
},
},
Expand All @@ -32,6 +33,7 @@ exports[`getAssetTransformRules should add URI rule when svg="uri" 1`] = `
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": undefined,
"remote": undefined,
},
},
Expand All @@ -51,6 +53,7 @@ exports[`getAssetTransformRules should add XML rule when svg="xml" 1`] = `
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": undefined,
"remote": undefined,
},
},
Expand All @@ -70,6 +73,7 @@ exports[`getAssetTransformRules should include additional options for SVGR 1`] =
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": undefined,
"remote": undefined,
},
},
Expand All @@ -95,6 +99,7 @@ exports[`getAssetTransformRules should return default asset transform rules when
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": undefined,
"remote": undefined,
},
},
Expand All @@ -110,6 +115,23 @@ exports[`getAssetTransformRules should return rules with inline option when prov
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": true,
"maxInlineSize": undefined,
"remote": undefined,
},
},
},
]
`;

exports[`getAssetTransformRules should return rules with maxInlineSize option when provided 1`] = `
[
{
"test": /\\\\\\.\\(bmp\\|gif\\|jpg\\|jpeg\\|png\\|psd\\|svg\\|webp\\|tiff\\|m4v\\|mov\\|mp4\\|mpeg\\|mpg\\|webm\\|aac\\|aiff\\|caf\\|m4a\\|mp3\\|wav\\|html\\|pdf\\|yaml\\|yml\\|otf\\|ttf\\|zip\\|obj\\)\\$/,
"use": {
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": 1024,
"remote": undefined,
},
},
Expand All @@ -125,6 +147,7 @@ exports[`getAssetTransformRules should return rules with remote options when pro
"loader": "@callstack/repack/assets-loader",
"options": {
"inline": undefined,
"maxInlineSize": undefined,
"remote": {
"enabled": true,
"publicPath": "https://example.com/assets",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ describe('getAssetTransformRules', () => {
expect(rules).toMatchSnapshot();
});

it('should return rules with maxInlineSize option when provided', () => {
const rules = getAssetTransformRules({ maxInlineSize: 1024 });

// @ts-ignore
expect(rules[0]?.use?.options?.maxInlineSize).toEqual(1024);
expect(rules).toMatchSnapshot();
});

it('should return rules with remote options when provided', () => {
const remoteOptions = { publicPath: 'https://example.com/assets' };
const rules = getAssetTransformRules({ remote: remoteOptions });
Expand Down
13 changes: 11 additions & 2 deletions packages/repack/src/utils/getAssetTransformRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ interface GetAssetTransformRulesOptions {
*/
inline?: boolean;

/**
* Maximum asset file size in bytes to inline as base64 URIs.
* Assets larger than this threshold will be extracted as separate files.
* Mutually exclusive with `inline`.
*/
maxInlineSize?: number;

/**
* Configuration for remote asset loading.
*/
Expand All @@ -57,14 +64,16 @@ interface GetAssetTransformRulesOptions {
* Creates `module.rules` configuration for handling assets in React Native applications.
*
* @param options Configuration options
* @param options.inline Whether to inline assets as base64 URIs (defaults to false)
* @param options.inline Whether to inline all assets as base64 URIs (defaults to false)
* @param options.maxInlineSize Maximum asset file size in bytes to inline as base64 URIs; larger assets are extracted as separate files
* @param options.remote Configuration for remote asset loading with publicPath and optional assetPath function
* @param options.svg Determines how SVG files should be processed ('svgr', 'xml', or 'uri')
*
* @returns Array of webpack/rspack rules for transforming assets
*/
export function getAssetTransformRules({
inline,
maxInlineSize,
remote,
svg,
}: GetAssetTransformRulesOptions = {}) {
Expand All @@ -85,7 +94,7 @@ export function getAssetTransformRules({
test: getAssetExtensionsRegExp(extensions),
use: {
loader: '@callstack/repack/assets-loader',
options: { inline, remote: remoteOptions },
options: { inline, maxInlineSize, remote: remoteOptions },
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,78 @@ exports[`assetLoader > should inline asset > without scales 2`] = `
└─ out/
└─ main.js"
`;

exports[`assetLoader > should inline asset based on maxInlineSize > extracts asset when size exceeds threshold 1`] = `
{
"__packager_asset": true,
"hash": "373411381c08b2c5034c814c24c26b19",
"height": 51,
"httpServerLocation": "assets/__fixtures__/assets",
"name": "logo",
"scales": [
1,
],
"type": "png",
"width": 297,
}
`;

exports[`assetLoader > should inline asset based on maxInlineSize > extracts asset when size exceeds threshold 2`] = `
"/
└─ out/
├─ drawable-mdpi/
│ └─ __fixtures___assets_logo.png
└─ main.js"
`;

exports[`assetLoader > should inline asset based on maxInlineSize > inlines asset when size is within threshold 1`] = `
{
"__packager_asset": true,
"hash": "373411381c08b2c5034c814c24c26b19",
"height": 51,
"httpServerLocation": "assets/__fixtures__/assets",
"name": "logo",
"scales": [
1,
],
"type": "png",
"width": 297,
}
`;

exports[`assetLoader > should inline asset based on maxInlineSize > inlines asset when size is within threshold 2`] = `
"/
└─ out/
├─ drawable-mdpi/
│ └─ __fixtures___assets_logo.png
└─ main.js"
`;

exports[`assetLoader > should inline asset based on maxInlineSize > uses largest variant to determine threshold (multi-scale asset) 1`] = `
{
"__packager_asset": true,
"hash": "86abef08a42e972a96c958d6fa9d43da,02ad731a8881911e488b51c48a4cc6c1,d9f7c31eebb3a41cc180431867b04f38",
"height": 272,
"httpServerLocation": "assets/__fixtures__/assets",
"name": "star",
"scales": [
1,
2,
3,
],
"type": "png",
"width": 286,
}
`;

exports[`assetLoader > should inline asset based on maxInlineSize > uses largest variant to determine threshold (multi-scale asset) 2`] = `
"/
└─ out/
├─ drawable-mdpi/
│ └─ __fixtures___assets_star.png
├─ drawable-xhdpi/
│ └─ __fixtures___assets_star.png
├─ drawable-xxhdpi/
│ └─ __fixtures___assets_star.png
└─ main.js"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,78 @@ exports[`assetLoader > should inline asset > without scales 2`] = `
└─ out/
└─ main.js"
`;

exports[`assetLoader > should inline asset based on maxInlineSize > extracts asset when size exceeds threshold 1`] = `
{
"__packager_asset": true,
"hash": "373411381c08b2c5034c814c24c26b19",
"height": 51,
"httpServerLocation": "assets/__fixtures__/assets",
"name": "logo",
"scales": [
1,
],
"type": "png",
"width": 297,
}
`;

exports[`assetLoader > should inline asset based on maxInlineSize > extracts asset when size exceeds threshold 2`] = `
"/
└─ out/
├─ drawable-mdpi/
│ └─ __fixtures___assets_logo.png
└─ main.js"
`;

exports[`assetLoader > should inline asset based on maxInlineSize > inlines asset when size is within threshold 1`] = `
{
"__packager_asset": true,
"hash": "373411381c08b2c5034c814c24c26b19",
"height": 51,
"httpServerLocation": "assets/__fixtures__/assets",
"name": "logo",
"scales": [
1,
],
"type": "png",
"width": 297,
}
`;

exports[`assetLoader > should inline asset based on maxInlineSize > inlines asset when size is within threshold 2`] = `
"/
└─ out/
├─ drawable-mdpi/
│ └─ __fixtures___assets_logo.png
└─ main.js"
`;

exports[`assetLoader > should inline asset based on maxInlineSize > uses largest variant to determine threshold (multi-scale asset) 1`] = `
{
"__packager_asset": true,
"hash": "86abef08a42e972a96c958d6fa9d43da,02ad731a8881911e488b51c48a4cc6c1,d9f7c31eebb3a41cc180431867b04f38",
"height": 272,
"httpServerLocation": "assets/__fixtures__/assets",
"name": "star",
"scales": [
1,
2,
3,
],
"type": "png",
"width": 286,
}
`;

exports[`assetLoader > should inline asset based on maxInlineSize > uses largest variant to determine threshold (multi-scale asset) 2`] = `
"/
└─ out/
├─ drawable-mdpi/
│ └─ __fixtures___assets_star.png
├─ drawable-xhdpi/
│ └─ __fixtures___assets_star.png
├─ drawable-xxhdpi/
│ └─ __fixtures___assets_star.png
└─ main.js"
`;
Loading
Loading