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/raw-json-assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack": minor
---

Add `enableRawJson` option to `getAssetTransformRules`. It is enabled by default and adds a `type: "json"` rule with `generator: { JSONParse: false }`, so `.json` files are bundled as raw text and parsed at runtime with `JSON.parse('...')` instead of being parsed into an object at build time. Pass `enableRawJson: false` to keep the previous behavior.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

exports[`getAssetTransformRules should add SVGR rule when svg="svgr" 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"test": /\\\\\\.\\(bmp\\|gif\\|jpg\\|jpeg\\|png\\|psd\\|webp\\|tiff\\|m4v\\|mov\\|mp4\\|mpeg\\|mpg\\|webm\\|aac\\|aiff\\|caf\\|m4a\\|mp3\\|wav\\|html\\|pdf\\|yaml\\|yml\\|otf\\|ttf\\|zip\\|obj\\)\\$/,
"use": {
Expand All @@ -27,6 +34,13 @@ exports[`getAssetTransformRules should add SVGR rule when svg="svgr" 1`] = `

exports[`getAssetTransformRules should add URI rule when svg="uri" 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"test": /\\\\\\.\\(bmp\\|gif\\|jpg\\|jpeg\\|png\\|psd\\|webp\\|tiff\\|m4v\\|mov\\|mp4\\|mpeg\\|mpg\\|webm\\|aac\\|aiff\\|caf\\|m4a\\|mp3\\|wav\\|html\\|pdf\\|yaml\\|yml\\|otf\\|ttf\\|zip\\|obj\\)\\$/,
"use": {
Expand All @@ -47,6 +61,13 @@ exports[`getAssetTransformRules should add URI rule when svg="uri" 1`] = `

exports[`getAssetTransformRules should add XML rule when svg="xml" 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"test": /\\\\\\.\\(bmp\\|gif\\|jpg\\|jpeg\\|png\\|psd\\|webp\\|tiff\\|m4v\\|mov\\|mp4\\|mpeg\\|mpg\\|webm\\|aac\\|aiff\\|caf\\|m4a\\|mp3\\|wav\\|html\\|pdf\\|yaml\\|yml\\|otf\\|ttf\\|zip\\|obj\\)\\$/,
"use": {
Expand All @@ -67,6 +88,13 @@ exports[`getAssetTransformRules should add XML rule when svg="xml" 1`] = `

exports[`getAssetTransformRules should include additional options for SVGR 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"test": /\\\\\\.\\(bmp\\|gif\\|jpg\\|jpeg\\|png\\|psd\\|webp\\|tiff\\|m4v\\|mov\\|mp4\\|mpeg\\|mpg\\|webm\\|aac\\|aiff\\|caf\\|m4a\\|mp3\\|wav\\|html\\|pdf\\|yaml\\|yml\\|otf\\|ttf\\|zip\\|obj\\)\\$/,
"use": {
Expand All @@ -91,8 +119,31 @@ exports[`getAssetTransformRules should include additional options for SVGR 1`] =
]
`;

exports[`getAssetTransformRules should omit the raw JSON rule when enableRawJson is false 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": undefined,
"remote": undefined,
},
},
},
]
`;

exports[`getAssetTransformRules should return default asset transform rules when no options provided 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"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": {
Expand All @@ -109,6 +160,13 @@ exports[`getAssetTransformRules should return default asset transform rules when

exports[`getAssetTransformRules should return rules with inline option when provided 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"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": {
Expand All @@ -125,6 +183,13 @@ exports[`getAssetTransformRules should return rules with inline option when prov

exports[`getAssetTransformRules should return rules with maxInlineSize option when provided 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"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": {
Expand All @@ -141,6 +206,13 @@ exports[`getAssetTransformRules should return rules with maxInlineSize option wh

exports[`getAssetTransformRules should return rules with remote options when provided 1`] = `
[
{
"generator": {
"JSONParse": false,
},
"test": /\\\\\\.json\\$/,
"type": "json",
},
{
"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": {
Expand Down
42 changes: 30 additions & 12 deletions packages/repack/src/utils/__tests__/getAssetTransformRules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ describe('getAssetTransformRules', () => {
const rules = getAssetTransformRules({ inline: true });

// @ts-expect-error
expect(rules[0]?.use?.options?.inline).toEqual(true);
expect(rules[1]?.use?.options?.inline).toEqual(true);
expect(rules).toMatchSnapshot();
});

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

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

Expand All @@ -27,39 +27,39 @@ describe('getAssetTransformRules', () => {
const rules = getAssetTransformRules({ remote: remoteOptions });

// @ts-expect-error
expect(rules[0]?.use?.options?.remote).toHaveProperty('enabled', true);
expect(rules[1]?.use?.options?.remote).toHaveProperty('enabled', true);
expect(rules).toMatchSnapshot();
});

it('should add SVGR rule when svg="svgr"', () => {
const rules = getAssetTransformRules({ svg: 'svgr' });

expect(rules).toHaveLength(2);
expect(rules[1]?.use?.loader).toEqual('@svgr/webpack');
expect(rules).toHaveLength(3);
expect(rules[2]?.use?.loader).toEqual('@svgr/webpack');
expect(rules).toMatchSnapshot();
});

it('should add XML rule when svg="xml"', () => {
const rules = getAssetTransformRules({ svg: 'xml' });

expect(rules).toHaveLength(2);
expect(rules).toHaveLength(3);
// @ts-expect-error
expect(rules[1]?.type).toEqual('asset/source');
expect(rules[2]?.type).toEqual('asset/source');
expect(rules).toMatchSnapshot();
});

it('should add URI rule when svg="uri"', () => {
const rules = getAssetTransformRules({ svg: 'uri' });

expect(rules).toHaveLength(2);
expect(rules).toHaveLength(3);
// @ts-expect-error
expect(rules[1]?.type).toEqual('asset/inline');
expect(rules[2]?.type).toEqual('asset/inline');
expect(rules).toMatchSnapshot();
});

it('should exclude .svg from main asset extensions when svg option is provided', () => {
const rules = getAssetTransformRules({ svg: 'uri' });
const ruleTest = rules[0]?.test;
const ruleTest = rules[1]?.test;
expect(ruleTest.test('test.svg')).toEqual(false);
});

Expand All @@ -68,8 +68,26 @@ describe('getAssetTransformRules', () => {
svg: { type: 'svgr', options: { dimensions: false } },
});

expect(rules).toHaveLength(2);
expect(rules[1]?.use?.options).toHaveProperty('dimensions', false);
expect(rules).toHaveLength(3);
expect(rules[2]?.use?.options).toHaveProperty('dimensions', false);
expect(rules).toMatchSnapshot();
});

it('should add raw JSON rule by default', () => {
const rules = getAssetTransformRules();

expect(rules[0]).toEqual({
test: /\.json$/,
type: 'json',
generator: { JSONParse: false },
});
});

it('should omit the raw JSON rule when enableRawJson is false', () => {
const rules = getAssetTransformRules({ enableRawJson: false });

expect(rules).toHaveLength(1);
expect(rules[0]?.test.source).not.toContain('json');
expect(rules).toMatchSnapshot();
});
});
18 changes: 18 additions & 0 deletions packages/repack/src/utils/getAssetTransformRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ interface GetAssetTransformRulesOptions {
* - 'uri': Loads SVGs as inline URIs to be used with SvgUri from react-native-svg
*/
svg?: SvgType;

/**
* Whether to load `.json` files as raw text instead of parsing them at build time.
* When enabled, JSON files are emitted as a string and parsed at runtime with `JSON.parse('...')`.
*
* @defaultValue true
*/
enableRawJson?: boolean;
}

/**
Expand All @@ -68,6 +76,7 @@ interface GetAssetTransformRulesOptions {
* @param options.maxInlineSize Maximum asset file size in bytes to inline as base64 URIs (requires inline: true); 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')
* @param options.enableRawJson Whether to load `.json` files as raw text parsed at runtime with `JSON.parse` (defaults to true)
*
* @returns Array of webpack/rspack rules for transforming assets
*/
Expand All @@ -76,6 +85,7 @@ export function getAssetTransformRules({
maxInlineSize,
remote,
svg,
enableRawJson = true,
}: GetAssetTransformRulesOptions = {}) {
const extensions = svg
? ASSET_EXTENSIONS.filter((ext) => ext !== 'svg')
Expand All @@ -90,6 +100,14 @@ export function getAssetTransformRules({

const rules = [];

if (enableRawJson) {
rules.push({
test: /\.json$/,
type: 'json',
generator: { JSONParse: false },
});
}

rules.push({
test: getAssetExtensionsRegExp(extensions),
use: {
Expand Down
12 changes: 12 additions & 0 deletions website/src/latest/api/utils/get-asset-transform-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface GetAssetTransformRulesOptions {
}) => string;
};
svg?: "svgr" | "xml" | "uri" | { type: "svgr", options: Record<string, any> };
enableRawJson?: boolean;
}
```

Expand Down Expand Up @@ -97,6 +98,17 @@ Allows to configure additional options to `@svgr/webpack`. The full list of avai
Learn more about using SVG in the [SVG guide](/docs/guides/svg).
:::

### options.enableRawJson

- Type: `boolean`
- Default: `true`

Whether to load `.json` files as raw text instead of parsing them at build time.

When enabled (the default), a rule with `type: "json"` and `generator: { JSONParse: false }` is added, so the bundled JSON is emitted as a string and parsed at runtime with `JSON.parse('...')`. This keeps the bundle smaller for large JSON files, since the parsed object is not inlined into the bundle.

Set it to `false` to disable the rule and let the bundler parse `.json` files at build time.

## Example

```js title=rspack.config.cjs
Expand Down
Loading