Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: always write manifest to disk #4074

Merged
merged 6 commits into from
Nov 27, 2024
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
35 changes: 34 additions & 1 deletion e2e/cases/output/manifest/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { build } from '@e2e/helper';
import { build, dev } from '@e2e/helper';
import { expect, test } from '@playwright/test';

const fixtures = __dirname;
Expand Down Expand Up @@ -108,3 +108,36 @@ test('output.manifest when target is node', async () => {
},
});
});

test('output.manifest should always write to disk when dev', async ({
page,
}) => {
const rsbuild = await dev({
cwd: fixtures,
page,
rsbuildConfig: {
output: {
distPath: {
root: 'dist-dev',
},
manifest: true,
legalComments: 'none',
filenameHash: false,
},
performance: {
chunkSplit: {
strategy: 'all-in-one',
},
},
},
});

const files = await rsbuild.unwrapOutputJSON();

const manifestContent =
files[Object.keys(files).find((file) => file.endsWith('manifest.json'))!];

expect(manifestContent).toBeDefined();

await rsbuild.close();
});
4 changes: 3 additions & 1 deletion packages/core/src/plugins/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,10 @@ export const pluginManifest = (): RsbuildPlugin => ({
name: 'rsbuild:manifest',

setup(api) {
api.modifyBundlerChain(async (chain, { CHAIN_ID, environment }) => {
api.modifyBundlerChain(async (chain, { CHAIN_ID, environment, isDev }) => {
const {
output: { manifest },
dev: { writeToDisk },
} = environment.config;

if (manifest === false) {
Expand All @@ -163,6 +164,7 @@ export const pluginManifest = (): RsbuildPlugin => ({
chain.plugin(CHAIN_ID.PLUGIN.MANIFEST).use(RspackManifestPlugin, [
{
fileName,
writeToFileEmit: isDev && writeToDisk !== true,
generate: generateManifest(htmlPaths),
},
]);
Expand Down
43 changes: 43 additions & 0 deletions website/docs/en/guide/advanced/ssr.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,49 @@ If you need to preview the online effect of SSR rendering, you also need to modi

Now, you can run the `npm run dev` command to start the dev server with SSR rendering function, and visit `http://localhost:3000/` to see that the SSR content has been rendered to the HTML page.

## Get Manifest

By default, scripts and links associated with the current page are automatically inserted into the HTML template. At this time, the compiled HTML template content can be obtained through [getTransformedHtml](/guide/advanced/environments#environment-api).

When you need to dynamically generate HTML on the server side, you'll need to inject the URLs of JavaScript and CSS assets into the HTML. By configuring [output.manifest](/config/output/manifest), you can easily obtain the manifest information of these assets. Here's an example:

```ts title=rsbuild.config.ts
export default {
output: {
manifest: true,
},
};
```

```ts title=server.ts
async function renderHtmlPage(): Promise<string> {
const manifest = await fs.promises.readFile('./dist/manifest.json', 'utf-8');
const { entries } = JSON.parse(manifest);

const { js, css } = entries['index'].initial;

const scriptTags = js
.map((url) => `<script src="${url}" defer></script>`)
.join('\n');
const styleTags = css
.map((file) => `<link rel="stylesheet" href="${file}">`)
.join('\n');

return `
<!DOCTYPE html>
<html>
<head>
${scriptTags}
${styleTags}
</head>
<body>
<div id="root"></div>
</body>
</html>`;
}
```

## Examples

- [SSR + Express Example](https://github.com/rspack-contrib/rspack-examples/blob/main/rsbuild/ssr-express)
- [SSR + Express + Manifest Example](https://github.com/rspack-contrib/rspack-examples/blob/main/rsbuild/ssr-express-with-manifest)
43 changes: 43 additions & 0 deletions website/docs/zh/guide/advanced/ssr.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,49 @@ startDevServer(process.cwd());

现在,执行 `npm run dev` 命令即可启动带有 SSR 渲染功能的开发服务器,访问 `http://localhost:3000/` 即可看到 SSR 内容已经渲染到了 HTML 页面上。

## 获取资源清单

默认情况下,和当前页面关联的 scripts 和 links 会自动插入到 HTML 模版中,此时通过 [getTransformedHtml](/guide/advanced/environments#environment-api) 即可获取编译后的 HTML 模版内容。

当需要在服务器端动态生成 HTML 时,你需要将 JavaScript 和 CSS 资源的 URL 注入到 HTML 中。通过配置 [output.manifest](/config/output/manifest),你可以方便地获取这些资源的清单信息。示例如下:

```ts title=rsbuild.config.ts
export default {
output: {
manifest: true,
},
};
```

```ts title=server.ts
async function renderHtmlPage(): Promise<string> {
const manifest = await fs.promises.readFile('./dist/manifest.json', 'utf-8');

const { entries } = JSON.parse(manifest);
const { js, css } = entries['index'].initial;

const scriptTags = js
.map((file) => `<script src="${file}" defer></script>`)
.join('\n');
const styleTags = css
.map((file) => `<link rel="stylesheet" href="${file}">`)
.join('\n');

return `
<!DOCTYPE html>
<html>
<head>
${scriptTags}
${styleTags}
</head>
<body>
<div id="root"></div>
</body>
</html>`;
}
```

## 示例项目

- [SSR + Express Example](https://github.com/rspack-contrib/rspack-examples/blob/main/rsbuild/ssr-express)
- [SSR + Express + Manifest Example](https://github.com/rspack-contrib/rspack-examples/blob/main/rsbuild/ssr-express-with-manifest)
Loading