Repository: web-infra-dev/rspress
Pull request #2015: feat(config)!: force successful SSG generation,  remove `ssg.strict` and add `ssg.fallback`
Author: login: SoonIter
Labels: name: change: feat
Created: 2025-03-28T07:50:30Z | Merged: 2025-03-28T09:47:26Z

## Summary

Rspress now requires ssg to be successful

It means rspress would emit error if ssg generation fails. The process will be directly terminated, rather than fallback to the csr products

Remove `ssg.strict` and add `ssg.fallback` in Rspress v2, see https://github.com/web-infra-dev/rspress/discussions/1105#discussioncomment-10324815


## Related Issue

https://github.com/web-infra-dev/rspress/issues/1317

<!--- Provide link of related issues -->

## Checklist

<!--- Check and mark with an "x" -->

- [ ] Tests updated (or not required).
- [ ] Documentation updated (or not required).



Diff:
diff --git a/e2e/fixtures/ssg-fail-strict/rspress.config.ts b/e2e/fixtures/ssg-fail-strict/rspress.config.ts
index 77f0b35112..dc4461c46e 100644
--- a/e2e/fixtures/ssg-fail-strict/rspress.config.ts
+++ b/e2e/fixtures/ssg-fail-strict/rspress.config.ts
@@ -4,6 +4,6 @@ import { defineConfig } from 'rspress/config';
 export default defineConfig({
   root: path.join(__dirname, 'doc'),
   ssg: {
-    strict: true,
+    fallback: false,
   },
 });
diff --git a/packages/core/src/node/build.ts b/packages/core/src/node/build.ts
index aaacd83cc1..c8b3c2ed7f 100644
--- a/packages/core/src/node/build.ts
+++ b/packages/core/src/node/build.ts
@@ -36,6 +36,10 @@ interface BuildOptions {
   config: UserConfig;
 }
 
+function isCSRFallback(ssgConfig: SSGConfig) {
+  return typeof ssgConfig === 'object' && ssgConfig.fallback === 'csr';
+}
+
 export async function bundle(
   docDirectory: string,
   config: UserConfig,
@@ -95,21 +99,18 @@ export async function renderPages(
         );
         ({ render } = ssrExports as SSRBundleExports);
       } catch (e) {
-        // skip fallback to CSR if ssg config is strict
-        // TODO: strict by default in v2
-        // see: https://github.com/web-infra-dev/rspress/issues/1317
-        if (typeof ssgConfig === 'object' && ssgConfig.strict) {
+        if (isCSRFallback(ssgConfig)) {
+          // fallback to CSR
+          logger.error(e);
+          logger.warn(
+            `Failed to load SSG bundle: ${picocolors.yellow(ssrBundlePath)}, fallback to CSR.`,
+          );
+        } else {
           logger.error(
             `Failed to load SSG bundle: ${picocolors.yellow(ssrBundlePath)}.`,
           );
           throw e;
         }
-
-        // fallback to CSR
-        logger.error(e);
-        logger.warn(
-          `Failed to load SSG bundle: ${picocolors.yellow(ssrBundlePath)}, fallback to CSR.`,
-        );
       }
     }
 
@@ -145,18 +146,18 @@ export async function renderPages(
             try {
               ({ appHtml } = await render(routePath, helmetContext.context));
             } catch (e) {
-              if (typeof ssgConfig === 'object' && ssgConfig.strict) {
+              if (isCSRFallback(ssgConfig)) {
+                // fallback to CSR
+                logger.warn(
+                  `Page "${picocolors.yellow(routePath)}" SSG rendering error, fallback to CSR.`,
+                  e,
+                );
+              } else {
                 logger.error(
                   `Page "${picocolors.yellow(routePath)}" SSG rendering failed.`,
                 );
                 throw e;
               }
-
-              // fallback to CSR
-              logger.warn(
-                `Page "${picocolors.yellow(routePath)}" SSG rendering error, fallback to CSR.`,
-                e,
-              );
             }
           }
 
diff --git a/packages/document/docs/en/api/config/config-basic.mdx b/packages/document/docs/en/api/config/config-basic.mdx
index 2ddcd324a1..a4ab14a4a9 100644
--- a/packages/document/docs/en/api/config/config-basic.mdx
+++ b/packages/document/docs/en/api/config/config-basic.mdx
@@ -468,10 +468,12 @@ export default defineConfig({
 
 ## ssg
 
-- Type: `boolean | { strict?: boolean }`
+- Type: `boolean | { fallback?: false | 'csr' }`
 - Default: `true`
 
-Determines whether to enable Static Site Generation. It is enabled by default, but you can disable it by setting `ssg` to `false`.
+Whether to enable static site generation. Rspress enable it by default to generate CSR outputs and SSG outputs.
+
+If your document site is only required to be used in CSR scenarios, you can set `ssg` to `false`, and Rspress will only generate CSR outputs.
 
 ```ts title="rspress.config.ts"
 import { defineConfig } from 'rspress/config';
@@ -481,12 +483,12 @@ export default defineConfig({
 });
 ```
 
-If SSG fails, it will fallback to CSR by default. You can set `ssg` to `{ strict: true }` to strictly require SSG to succeed, otherwise an error will be thrown.
+If you do not strictly require SSG generation in your scenario, you can set `ssg` to `{ fallback: 'csr' }`. When SSG fails, it will fallback to generate only CSR outputs.
 
 ```ts title="rspress.config.ts"
 export default {
   ssg: {
-    strict: true,
+    fallback: 'csr',
   },
 };
 ```
diff --git a/packages/document/docs/zh/api/config/config-basic.mdx b/packages/document/docs/zh/api/config/config-basic.mdx
index dcfb58eb5f..24641d2809 100644
--- a/packages/document/docs/zh/api/config/config-basic.mdx
+++ b/packages/document/docs/zh/api/config/config-basic.mdx
@@ -467,10 +467,12 @@ export default defineConfig({
 
 ## ssg
 
-- Type: `boolean | { strict?: boolean }`
+- Type: `boolean | { fallback?: false | 'csr' }`
 - Default: `true`
 
-是否开启静态站点生成。默认开启，你可以通过设置 `ssg` 为 `false` 来关闭。
+是否开启静态站点生成。Rspress 默认开启该功能，生成 CSR 产物和 SSG 产物。
+
+如果你的文档站只要求在 CSR 场景下使用，你可以设置 `ssg` 为 `false`，此时 Rspress 会仅生成 CSR 产物。
 
 ```ts title="rspress.config.ts"
 import { defineConfig } from 'rspress/config';
@@ -480,12 +482,12 @@ export default defineConfig({
 });
 ```
 
-当 SSG 失败时，默认会 fallback 到 CSR。你可以通过设置 `ssg` 为 `{ strict: true }` 来严格要求 SSG 必须成功，否则抛出错误。
+如果你的场景中不严格要求必须生成 SSG 产物，可以设置 `ssg` 为 `{ fallback: 'csr' }`。当 SSG 失败时，会 fallback 到仅生成 CSR 产物。
 
 ```ts title="rspress.config.ts"
 export default {
   ssg: {
-    strict: true,
+    fallback: 'csr',
   },
 };
 ```
diff --git a/packages/document/rspress.config.ts b/packages/document/rspress.config.ts
index f0559d4817..9fa5c83ff6 100644
--- a/packages/document/rspress.config.ts
+++ b/packages/document/rspress.config.ts
@@ -19,9 +19,6 @@ export default defineConfig({
   markdown: {
     checkDeadLinks: true,
   },
-  ssg: {
-    strict: true,
-  },
   plugins: [
     pluginFontOpenSans(),
     pluginSitemap({
diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts
index 358628998b..6874386028 100644
--- a/packages/shared/src/types/index.ts
+++ b/packages/shared/src/types/index.ts
@@ -51,7 +51,7 @@ export interface Locale {
   description?: string;
 }
 
-export type SSGConfig = boolean | { strict?: boolean };
+export type SSGConfig = boolean | { fallback?: false | 'csr' };
 
 export interface UserConfig<ThemeConfig = DefaultThemeConfig> {
   /**


Reviews:
user: login: Timeless0911
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T08:05:01Z
user: login: Timeless0911
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T08:06:30Z
user: login: Timeless0911
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:47:25Z

Review comments:
diff_hunk: @@ -468,9 +468,11 @@ export default defineConfig({
 ## ssg
 
 - Type: `boolean | { strict?: boolean }`
-- Default: `true`
+- Default: `{ strict: true }`
+
+是否开启静态站点生成，Rspress 默认开启，生成 CSR 产物和 SSG 产物。
path: packages/document/docs/zh/api/config/config-basic.mdx
user: login: Timeless0911
body: ```suggestion
是否开启静态站点生成。Rspress 默认开启该功能，生成 CSR 产物和 SSG 产物。
```
created_at: 2025-03-28T08:01:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -469,9 +469,11 @@ export default defineConfig({
 ## ssg
 
 - Type: `boolean | { strict?: boolean }`
-- Default: `true`
+- Default: `{ strict: true }`
+
+Whether to enable static site generation, Rspress is enabled by default to generate CSR outputs and SSG outputs.
path: packages/document/docs/en/api/config/config-basic.mdx
user: login: Timeless0911
body: ```suggestion
Whether to enable static site generation. Rspress enable it by default to generate CSR outputs and SSG outputs.
```
created_at: 2025-03-28T08:01:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -468,9 +468,11 @@ export default defineConfig({
 ## ssg
 
 - Type: `boolean | { strict?: boolean }`
-- Default: `true`
+- Default: `{ strict: true }`
+
+是否开启静态站点生成，Rspress 默认开启，生成 CSR 产物和 SSG 产物。
 
-是否开启静态站点生成。默认开启，你可以通过设置 `ssg` 为 `false` 来关闭。
+若你的文档站只要求在 CSR 场景下使用，你可以设置 `ssg` 为 `false`，此时 Rspress 会仅生成 CSR 产物。
path: packages/document/docs/zh/api/config/config-basic.mdx
user: login: Timeless0911
body: ```suggestion
如果你的文档站只要求在 CSR 场景下使用，你可以设置 `ssg` 为 `false`，此时 Rspress 会仅生成 CSR 产物。
```
created_at: 2025-03-28T08:03:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -480,12 +482,12 @@ export default defineConfig({
 });
 ```
 
-当 SSG 失败时，默认会 fallback 到 CSR。你可以通过设置 `ssg` 为 `{ strict: true }` 来严格要求 SSG 必须成功，否则抛出错误。
+如果你的场景中不严格要求必须生成 SSG，可以设置 `ssg` 为 `{ strict: false }`， SSG 失败时，会 fallback 到仅生成 CSR 产物。
path: packages/document/docs/zh/api/config/config-basic.mdx
user: login: Timeless0911
body: ```suggestion
如果你的场景中不严格要求必须生成 SSG，可以设置 `ssg` 为 `{ strict: false }`。当 SSG 失败时，会 fallback 到仅生成 CSR 产物。
```
created_at: 2025-03-28T08:04:26Z
author_association: CONTRIBUTOR

PR comments:
user: login: netlify[bot]
created_at: 2025-03-28T07:50:48Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *aquamarine-blini-95325f* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 9891c044f483b1d76d755f0968604e8153ac50f9 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/aquamarine-blini-95325f/deploys/67e66850219dab0008350442 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-2015--aquamarine-blini-95325f.netlify.app](https://deploy-preview-2015--aquamarine-blini-95325f.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTIwMTUtLWFxdWFtYXJpbmUtYmxpbmktOTUzMjVmLm5ldGxpZnkuYXBwIn0.RR2vZRkVzfgXlL5EOK--pVKJpQEPFkSwSktfIm150oU)<br /><br />_Use your smartphone camera to open QR code link._</details> |
|<span aria-hidden="true">![Lighthouse](https://app.netlify.com/public/external-usage/git-comments/lighthouse-sm.png)</span><br />Lighthouse | 1 paths audited<br />**Performance**: 68 (🔴 down 18 from production)<br />**Accessibility**: 97 (no change from production)<br />**Best Practices**: 92 (no change from production)<br />**SEO**: 100 (no change from production)<br />**PWA**: -<br />[View the detailed breakdown and full score reports](https://app.netlify.com/sites/aquamarine-blini-95325f/deploys/67e66850219dab0008350442) |
---
<!-- [aquamarine-blini-95325f Preview](https://deploy-preview-2015--aquamarine-blini-95325f.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/aquamarine-blini-95325f/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: netlify[bot]
created_at: 2025-03-28T07:50:48Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *rspress-v2* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 9891c044f483b1d76d755f0968604e8153ac50f9 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/rspress-v2/deploys/67e66850245a5b0008de7079 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-2015--rspress-v2.netlify.app](https://deploy-preview-2015--rspress-v2.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTIwMTUtLXJzcHJlc3MtdjIubmV0bGlmeS5hcHAifQ.tiaijQEwjN8YbhsXOCy0K5PAgI8HX4rVGAkxBWr-vRw)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [rspress-v2 Preview](https://deploy-preview-2015--rspress-v2.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/rspress-v2/configuration/notifications#deploy-webhooks)._
author_association: NONE