diff --git a/e2e/cases/output/manifest/index.test.ts b/e2e/cases/output/manifest/index.test.ts index 61c65cc156..2af039acc9 100644 --- a/e2e/cases/output/manifest/index.test.ts +++ b/e2e/cases/output/manifest/index.test.ts @@ -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; @@ -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(); +}); diff --git a/packages/core/src/plugins/manifest.ts b/packages/core/src/plugins/manifest.ts index 29d86464fd..c76484213c 100644 --- a/packages/core/src/plugins/manifest.ts +++ b/packages/core/src/plugins/manifest.ts @@ -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) { @@ -163,6 +164,7 @@ export const pluginManifest = (): RsbuildPlugin => ({ chain.plugin(CHAIN_ID.PLUGIN.MANIFEST).use(RspackManifestPlugin, [ { fileName, + writeToFileEmit: isDev && writeToDisk !== true, generate: generateManifest(htmlPaths), }, ]); diff --git a/website/docs/en/guide/advanced/ssr.mdx b/website/docs/en/guide/advanced/ssr.mdx index fa774c6740..3f5706e9cc 100644 --- a/website/docs/en/guide/advanced/ssr.mdx +++ b/website/docs/en/guide/advanced/ssr.mdx @@ -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 { + 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) => ``) + .join('\n'); + const styleTags = css + .map((file) => ``) + .join('\n'); + + return ` + + + + ${scriptTags} + ${styleTags} + + +
+ + `; +} +``` + ## 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) diff --git a/website/docs/zh/guide/advanced/ssr.mdx b/website/docs/zh/guide/advanced/ssr.mdx index cca934d7b4..f59f33834a 100644 --- a/website/docs/zh/guide/advanced/ssr.mdx +++ b/website/docs/zh/guide/advanced/ssr.mdx @@ -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 { + 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) => ``) + .join('\n'); + const styleTags = css + .map((file) => ``) + .join('\n'); + + return ` + + + + ${scriptTags} + ${styleTags} + + +
+ + `; +} +``` + ## 示例项目 - [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)