Skip to content

Commit

Permalink
feat: support inline chunks in development mode (#2957)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thulof committed Jul 24, 2024
1 parent 695b38c commit 1c1b9b6
Show file tree
Hide file tree
Showing 7 changed files with 429 additions and 21 deletions.
203 changes: 202 additions & 1 deletion e2e/cases/inline-chunk/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'node:path';
import { build, gotoPage } from '@e2e/helper';
import { build, dev, gotoPage } from '@e2e/helper';
import { expect, test } from '@playwright/test';
import type { RspackChain } from '@rsbuild/core';

Expand Down Expand Up @@ -155,3 +155,204 @@ test('inline styles by filename and file size', async () => {
).length,
).toEqual(0);
});

test('styles are not inline by default in development mode', async ({
page,
}) => {
const rsbuild = await dev({
cwd: __dirname,
rsbuildConfig: {
tools: toolsConfig,
},
});

await gotoPage(page, rsbuild);

// index.css in page
await expect(
page.evaluate(
`document.querySelectorAll('link[href*="index.css"]').length`,
),
).resolves.toEqual(1);
});

test('using RegExp to inline styles in development mode', async ({ page }) => {
const rsbuild = await dev({
cwd: __dirname,
rsbuildConfig: {
output: {
inlineStyles: {
enable: true,
test: /\.css$/,
},
},
tools: toolsConfig,
},
});

await gotoPage(page, rsbuild);

// no index.css in page
await expect(
page.evaluate(
`document.querySelectorAll('link[href*="index.css"]').length`,
),
).resolves.toEqual(0);
});

test('inline styles by filename and file size in development mode', async ({
page,
}) => {
const rsbuild = await dev({
cwd: __dirname,
rsbuildConfig: {
output: {
inlineStyles: {
enable: true,
test({ size, name }: { size: number; name: string }) {
return name.includes('index') && size < 1000;
},
},
},
tools: toolsConfig,
},
});

await gotoPage(page, rsbuild);

// no index.css in page
await expect(
page.evaluate(
`document.querySelectorAll('link[href*="index.css"]').length`,
),
).resolves.toEqual(0);
});

test('inline scripts does not work when enable is false', async () => {
const rsbuild = await build({
cwd: __dirname,
rsbuildConfig: {
output: {
inlineScripts: {
enable: false,
test: /\.js$/,
},
},
tools: toolsConfig,
},
});
const files = await rsbuild.unwrapOutputJSON(false);

// all index.js in output
expect(
Object.keys(files).filter(
(fileName) => fileName.endsWith('.js') && fileName.includes('/index.'),
).length,
).toEqual(1);

// all source maps in output
expect(
Object.keys(files).filter((fileName) => fileName.endsWith('.js.map'))
.length,
).toBeGreaterThanOrEqual(2);
});

test('inline styles does not work when enable is false', async () => {
const rsbuild = await build({
cwd: __dirname,
rsbuildConfig: {
output: {
inlineStyles: {
enable: false,
test: /\.css$/,
},
},
tools: toolsConfig,
},
});
const files = await rsbuild.unwrapOutputJSON(false);

// all index.css in output
expect(
Object.keys(files).filter(
(fileName) => fileName.endsWith('.css') && fileName.includes('/index.'),
).length,
).toEqual(1);
});

test('inline chunk works in production mode when enable is auto', async () => {
const rsbuild = await build({
cwd: __dirname,
rsbuildConfig: {
output: {
inlineScripts: {
enable: 'auto',
test: /\.js$/,
},
inlineStyles: {
enable: 'auto',
test: /\.css$/,
},
},
tools: toolsConfig,
},
});
const files = await rsbuild.unwrapOutputJSON(false);

// no index.js in output
expect(
Object.keys(files).filter(
(fileName) => fileName.endsWith('.js') && fileName.includes('/index.'),
).length,
).toEqual(0);

// all source maps in output
expect(
Object.keys(files).filter((fileName) => fileName.endsWith('.js.map'))
.length,
).toBeGreaterThanOrEqual(2);

// no index.css in output
expect(
Object.keys(files).filter(
(fileName) => fileName.endsWith('.css') && fileName.includes('/index.'),
).length,
).toEqual(0);
});

test('inline does not work in development mode when enable is auto', async ({
page,
}) => {
const rsbuild = await dev({
cwd: __dirname,
rsbuildConfig: {
output: {
inlineScripts: {
enable: 'auto',
test: /\.js$/,
},
inlineStyles: {
enable: 'auto',
test: /\.css$/,
},
},
tools: toolsConfig,
},
});

await gotoPage(page, rsbuild);

// all index.js in page
await expect(
page.evaluate(
`document.querySelectorAll('script[src*="index.js"]').length`,
),
).resolves.toEqual(1);

// all index.css in page
await expect(
page.evaluate(
`document.querySelectorAll('link[href*="index.css"]').length`,
),
).resolves.toEqual(1);
});
34 changes: 30 additions & 4 deletions packages/core/src/plugins/inlineChunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { CSS_REGEX, JS_REGEX } from '../constants';
import {
addTrailingSlash,
getPublicPathFromCompiler,
isDev,
isFunction,
isProd,
} from '../helpers';
import type {
HtmlBasicTag,
Expand Down Expand Up @@ -228,7 +228,7 @@ export const pluginInlineChunk = (): RsbuildPlugin => ({
({ headTags, bodyTags }, { compiler, compilation, environment }) => {
const { htmlPaths, config } = environment;

if (isDev() || Object.keys(htmlPaths).length === 0) {
if (Object.keys(htmlPaths).length === 0) {
return { headTags, bodyTags };
}

Expand All @@ -238,11 +238,37 @@ export const pluginInlineChunk = (): RsbuildPlugin => ({
const styleTests: InlineChunkTest[] = [];

if (inlineScripts) {
scriptTests.push(inlineScripts === true ? JS_REGEX : inlineScripts);
if (inlineScripts === true) {
scriptTests.push(JS_REGEX);
} else if (
inlineScripts instanceof RegExp ||
inlineScripts instanceof Function
) {
scriptTests.push(inlineScripts);
} else {
const enable =
inlineScripts.enable === 'auto' ? isProd() : inlineScripts.enable;
if (enable) {
scriptTests.push(inlineScripts.test);
}
}
}

if (inlineStyles) {
styleTests.push(inlineStyles === true ? CSS_REGEX : inlineStyles);
if (inlineStyles === true) {
styleTests.push(CSS_REGEX);
} else if (
inlineStyles instanceof RegExp ||
inlineStyles instanceof Function
) {
styleTests.push(inlineStyles);
} else {
const enable =
inlineStyles.enable === 'auto' ? isProd() : inlineStyles.enable;
if (enable) {
styleTests.push(inlineStyles.test);
}
}
}

if (!scriptTests.length && !styleTests.length) {
Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/types/config/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ export type InlineChunkTestFunction = (params: {

export type InlineChunkTest = RegExp | InlineChunkTestFunction;

export type InlineChunkConfig =
| boolean
| InlineChunkTest
| { enable?: boolean | 'auto'; test: InlineChunkTest };

export interface OutputConfig {
/**
* Specify build target to run in specified environment.
Expand Down Expand Up @@ -265,11 +270,11 @@ export interface OutputConfig {
/**
* Whether to inline output scripts files (.js files) into HTML with `<script>` tags.
*/
inlineScripts?: boolean | InlineChunkTest;
inlineScripts?: InlineChunkConfig;
/**
* Whether to inline output style files (.css files) into html with `<style>` tags.
*/
inlineStyles?: boolean | InlineChunkTest;
inlineStyles?: InlineChunkConfig;
/**
* Whether to inject styles into the DOM via `style-loader`.
*/
Expand Down Expand Up @@ -309,8 +314,8 @@ export interface NormalizedOutputConfig extends OutputConfig {
assetPrefix: string;
dataUriLimit: number | NormalizedDataUriLimit;
minify: Minify;
inlineScripts: boolean | InlineChunkTest;
inlineStyles: boolean | InlineChunkTest;
inlineScripts: InlineChunkConfig;
inlineStyles: InlineChunkConfig;
injectStyles: boolean;
cssModules: {
auto: CSSModules['auto'];
Expand Down
50 changes: 47 additions & 3 deletions website/docs/en/config/output/inline-scripts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
- **Type:**

```ts
type InlineScripts =
| boolean
type InlineScriptsTest =
| RegExp
| ((params: { size: number; name: string }) => boolean);

type InlineScripts =
| boolean
| InlineScriptsTest
| {
enable?: boolean | 'auto';
test: InlineScriptsTest;
};
```

- **Default:** `false`

Whether to inline output scripts files (.js files) into HTML with `<script>` tags in production mode.
Whether to inline output scripts files (.js files) into HTML with `<script>` tags.

Note that, with this option on, the scripts files will no longer be written in dist directory, they will only exist inside the HTML file instead.

Expand Down Expand Up @@ -107,3 +114,40 @@ export default {
},
};
```

## Options

### enable

- **Type:** `boolean | 'auto'`
- **Default:** `false`

Whether to enable the inline scripts feature. If set to `'auto'`, it will be enabled when the `mode` is `'production'`.

```ts
export default {
output: {
inlineScripts: {
enable: 'auto',
test: /[\\/]main\.\w+\.js$/,
},
},
};
```

### test

- **Type:** `RegExp | ((params: { size: number; name: string }) => boolean)`

The regular expression or function to match the files that need to be inlined.

```ts
export default {
output: {
inlineScripts: {
enable: true,
test: /[\\/]main\.\w+\.js$/,
},
},
};
```
Loading

0 comments on commit 1c1b9b6

Please sign in to comment.