diff --git a/packages/create-docusaurus/package.json b/packages/create-docusaurus/package.json
index faca98e88eb3..90c3fed483a5 100755
--- a/packages/create-docusaurus/package.json
+++ b/packages/create-docusaurus/package.json
@@ -22,8 +22,8 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
"commander": "^5.1.0",
"fs-extra": "^11.1.0",
"lodash": "^4.17.21",
diff --git a/packages/create-docusaurus/templates/classic-typescript/package.json b/packages/create-docusaurus/templates/classic-typescript/package.json
index fa98589daaa4..3f03ca17b7a2 100644
--- a/packages/create-docusaurus/templates/classic-typescript/package.json
+++ b/packages/create-docusaurus/templates/classic-typescript/package.json
@@ -15,8 +15,8 @@
"typecheck": "tsc"
},
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/preset-classic": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/preset-classic": "3.0.0-alpha.0",
"@mdx-js/react": "^2.3.0",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
@@ -24,8 +24,8 @@
"react-dom": "^18.0.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
- "@docusaurus/tsconfig": "^3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
+ "@docusaurus/tsconfig": "3.0.0-alpha.0",
"typescript": "^5.0.4"
},
"browserslist": {
diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json
index 73111842fe12..a7e8136cd594 100644
--- a/packages/create-docusaurus/templates/classic/package.json
+++ b/packages/create-docusaurus/templates/classic/package.json
@@ -14,8 +14,8 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/preset-classic": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/preset-classic": "3.0.0-alpha.0",
"@mdx-js/react": "^2.3.0",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
@@ -23,7 +23,7 @@
"react-dom": "^18.0.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0"
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0"
},
"browserslist": {
"production": [
diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json
index 01e7abc64f0b..94e6235631ad 100644
--- a/packages/docusaurus-mdx-loader/package.json
+++ b/packages/docusaurus-mdx-loader/package.json
@@ -20,9 +20,9 @@
"dependencies": {
"@babel/parser": "^7.21.2",
"@babel/traverse": "^7.21.2",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@mdx-js/mdx": "^2.1.5",
"escape-html": "^1.0.3",
"estree-util-value-to-estree": "^2.1.0",
@@ -30,13 +30,13 @@
"fs-extra": "^11.1.0",
"hastscript": "^7.1.0",
"image-size": "^1.0.2",
- "mdast-util-to-string": "^3.0.0",
"mdast-util-mdx": "^2.0.0",
+ "mdast-util-to-string": "^3.0.0",
"rehype-raw": "^6.1.1",
"remark-comment": "^1.0.0",
- "remark-gfm": "^3.0.1",
"remark-directive": "^2.0.1",
"remark-emoji": "^2.2.0",
+ "remark-gfm": "^3.0.1",
"stringify-object": "^3.3.0",
"tslib": "^2.5.0",
"unified": "^10.1.2",
@@ -45,7 +45,7 @@
"webpack": "^5.76.0"
},
"devDependencies": {
- "@docusaurus/types": "^3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
"@types/escape-html": "^1.0.2",
"@types/mdast": "^3.0.10",
"@types/stringify-object": "^3.3.1",
diff --git a/packages/docusaurus-migrate/package.json b/packages/docusaurus-migrate/package.json
index 260f99276219..60e97e854877 100644
--- a/packages/docusaurus-migrate/package.json
+++ b/packages/docusaurus-migrate/package.json
@@ -24,8 +24,8 @@
"dependencies": {
"@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
"@mapbox/hast-util-to-jsx": "^2.0.0",
"color": "^4.2.3",
"commander": "^5.1.0",
diff --git a/packages/docusaurus-module-type-aliases/package.json b/packages/docusaurus-module-type-aliases/package.json
index 01208d334611..1b1b60cd7cc7 100644
--- a/packages/docusaurus-module-type-aliases/package.json
+++ b/packages/docusaurus-module-type-aliases/package.json
@@ -13,7 +13,7 @@
},
"dependencies": {
"@docusaurus/react-loadable": "5.5.2",
- "@docusaurus/types": "^3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
diff --git a/packages/docusaurus-plugin-client-redirects/package.json b/packages/docusaurus-plugin-client-redirects/package.json
index f62eca571eaf..9f2ee7f23bea 100644
--- a/packages/docusaurus-plugin-client-redirects/package.json
+++ b/packages/docusaurus-plugin-client-redirects/package.json
@@ -18,18 +18,18 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"eta": "^2.0.1",
"fs-extra": "^11.1.0",
"lodash": "^4.17.21",
"tslib": "^2.5.0"
},
"devDependencies": {
- "@docusaurus/types": "^3.0.0-alpha.0"
+ "@docusaurus/types": "3.0.0-alpha.0"
},
"peerDependencies": {
"react": "^18.0.0",
diff --git a/packages/docusaurus-plugin-content-blog/package.json b/packages/docusaurus-plugin-content-blog/package.json
index 5855868fcad1..1248c15f22c4 100644
--- a/packages/docusaurus-plugin-content-blog/package.json
+++ b/packages/docusaurus-plugin-content-blog/package.json
@@ -18,13 +18,13 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/mdx-loader": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/mdx-loader": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"cheerio": "^1.0.0-rc.12",
"feed": "^4.2.2",
"fs-extra": "^11.1.0",
diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json
index 41def9e00e9f..5c2bf83fea7e 100644
--- a/packages/docusaurus-plugin-content-docs/package.json
+++ b/packages/docusaurus-plugin-content-docs/package.json
@@ -35,13 +35,13 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/mdx-loader": "^3.0.0-alpha.0",
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/mdx-loader": "3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@types/react-router-config": "^5.0.6",
"combine-promises": "^1.1.0",
"fs-extra": "^11.1.0",
diff --git a/packages/docusaurus-plugin-content-pages/package.json b/packages/docusaurus-plugin-content-pages/package.json
index 79c4da3cb2e1..88bf08101dfb 100644
--- a/packages/docusaurus-plugin-content-pages/package.json
+++ b/packages/docusaurus-plugin-content-pages/package.json
@@ -18,11 +18,11 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/mdx-loader": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/mdx-loader": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"fs-extra": "^11.1.0",
"tslib": "^2.5.0",
"webpack": "^5.76.0"
diff --git a/packages/docusaurus-plugin-debug/package.json b/packages/docusaurus-plugin-debug/package.json
index 245af03bd75d..a60e26e8154e 100644
--- a/packages/docusaurus-plugin-debug/package.json
+++ b/packages/docusaurus-plugin-debug/package.json
@@ -20,9 +20,9 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
"fs-extra": "^11.1.0",
"react-json-view": "^1.21.3",
"tslib": "^2.5.0"
diff --git a/packages/docusaurus-plugin-google-analytics/package.json b/packages/docusaurus-plugin-google-analytics/package.json
index 034ad4b90d07..58d59271a615 100644
--- a/packages/docusaurus-plugin-google-analytics/package.json
+++ b/packages/docusaurus-plugin-google-analytics/package.json
@@ -18,9 +18,9 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"tslib": "^2.5.0"
},
"peerDependencies": {
diff --git a/packages/docusaurus-plugin-google-gtag/package.json b/packages/docusaurus-plugin-google-gtag/package.json
index f60ab109314b..c1b03727be00 100644
--- a/packages/docusaurus-plugin-google-gtag/package.json
+++ b/packages/docusaurus-plugin-google-gtag/package.json
@@ -18,9 +18,9 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@types/gtag.js": "^0.0.12",
"tslib": "^2.5.0"
},
diff --git a/packages/docusaurus-plugin-google-tag-manager/package.json b/packages/docusaurus-plugin-google-tag-manager/package.json
index a410ca665a61..49b0617fa579 100644
--- a/packages/docusaurus-plugin-google-tag-manager/package.json
+++ b/packages/docusaurus-plugin-google-tag-manager/package.json
@@ -18,9 +18,9 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"tslib": "^2.5.0"
},
"peerDependencies": {
diff --git a/packages/docusaurus-plugin-ideal-image/package.json b/packages/docusaurus-plugin-ideal-image/package.json
index 60289970cb66..38700cd0b596 100644
--- a/packages/docusaurus-plugin-ideal-image/package.json
+++ b/packages/docusaurus-plugin-ideal-image/package.json
@@ -20,12 +20,12 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/lqip-loader": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/lqip-loader": "3.0.0-alpha.0",
"@docusaurus/responsive-loader": "^1.7.0",
- "@docusaurus/theme-translations": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/theme-translations": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@slorber/react-ideal-image": "^0.0.12",
"react-waypoint": "^10.3.0",
"sharp": "^0.31.3",
@@ -33,7 +33,7 @@
"webpack": "^5.76.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
"fs-extra": "^11.1.0"
},
"peerDependencies": {
diff --git a/packages/docusaurus-plugin-pwa/package.json b/packages/docusaurus-plugin-pwa/package.json
index c87add241d49..0455f80c3415 100644
--- a/packages/docusaurus-plugin-pwa/package.json
+++ b/packages/docusaurus-plugin-pwa/package.json
@@ -22,12 +22,12 @@
"dependencies": {
"@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2",
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/theme-translations": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/theme-translations": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"babel-loader": "^9.1.2",
"clsx": "^1.2.1",
"core-js": "^3.29.0",
@@ -41,7 +41,7 @@
"workbox-window": "^6.5.4"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
"fs-extra": "^11.1.0"
},
"peerDependencies": {
diff --git a/packages/docusaurus-plugin-sitemap/package.json b/packages/docusaurus-plugin-sitemap/package.json
index 7fd1e25d06d1..b1d45d1fdd9c 100644
--- a/packages/docusaurus-plugin-sitemap/package.json
+++ b/packages/docusaurus-plugin-sitemap/package.json
@@ -18,12 +18,12 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"fs-extra": "^11.1.0",
"sitemap": "^7.1.1",
"tslib": "^2.5.0"
diff --git a/packages/docusaurus-preset-classic/package.json b/packages/docusaurus-preset-classic/package.json
index e882bcccbe27..347cc67f4358 100644
--- a/packages/docusaurus-preset-classic/package.json
+++ b/packages/docusaurus-preset-classic/package.json
@@ -18,19 +18,19 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-blog": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-docs": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-pages": "^3.0.0-alpha.0",
- "@docusaurus/plugin-debug": "^3.0.0-alpha.0",
- "@docusaurus/plugin-google-analytics": "^3.0.0-alpha.0",
- "@docusaurus/plugin-google-gtag": "^3.0.0-alpha.0",
- "@docusaurus/plugin-google-tag-manager": "^3.0.0-alpha.0",
- "@docusaurus/plugin-sitemap": "^3.0.0-alpha.0",
- "@docusaurus/theme-classic": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/theme-search-algolia": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0"
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-blog": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-docs": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-pages": "3.0.0-alpha.0",
+ "@docusaurus/plugin-debug": "3.0.0-alpha.0",
+ "@docusaurus/plugin-google-analytics": "3.0.0-alpha.0",
+ "@docusaurus/plugin-google-gtag": "3.0.0-alpha.0",
+ "@docusaurus/plugin-google-tag-manager": "3.0.0-alpha.0",
+ "@docusaurus/plugin-sitemap": "3.0.0-alpha.0",
+ "@docusaurus/theme-classic": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/theme-search-algolia": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0"
},
"peerDependencies": {
"react": "^18.0.0",
diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json
index 850be79b9e68..1e504b04586f 100644
--- a/packages/docusaurus-theme-classic/package.json
+++ b/packages/docusaurus-theme-classic/package.json
@@ -20,18 +20,18 @@
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
},
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/mdx-loader": "^3.0.0-alpha.0",
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-blog": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-docs": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-pages": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/theme-translations": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/mdx-loader": "3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-blog": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-docs": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-pages": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/theme-translations": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@mdx-js/react": "^2.1.5",
"clsx": "^1.2.1",
"copy-text-to-clipboard": "^3.0.1",
diff --git a/packages/docusaurus-theme-common/package.json b/packages/docusaurus-theme-common/package.json
index 6b0ec6428489..3fd4cc027b42 100644
--- a/packages/docusaurus-theme-common/package.json
+++ b/packages/docusaurus-theme-common/package.json
@@ -30,13 +30,13 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/mdx-loader": "^3.0.0-alpha.0",
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-blog": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-docs": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-pages": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
+ "@docusaurus/mdx-loader": "3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-blog": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-docs": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-pages": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@@ -48,8 +48,8 @@
"utility-types": "^3.10.0"
},
"devDependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
"fs-extra": "^11.1.0",
"lodash": "^4.17.21"
},
diff --git a/packages/docusaurus-theme-live-codeblock/package.json b/packages/docusaurus-theme-live-codeblock/package.json
index fc7d1ff4764c..9646d2fe3e86 100644
--- a/packages/docusaurus-theme-live-codeblock/package.json
+++ b/packages/docusaurus-theme-live-codeblock/package.json
@@ -23,10 +23,10 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/theme-translations": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/theme-translations": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@philpl/buble": "^0.19.7",
"clsx": "^1.2.1",
"fs-extra": "^11.1.0",
@@ -34,7 +34,7 @@
"tslib": "^2.5.0"
},
"devDependencies": {
- "@docusaurus/types": "^3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
"@types/buble": "^0.20.1"
},
"peerDependencies": {
diff --git a/packages/docusaurus-theme-mermaid/package.json b/packages/docusaurus-theme-mermaid/package.json
index 5a142fc76bf5..1d9904a5dc8a 100644
--- a/packages/docusaurus-theme-mermaid/package.json
+++ b/packages/docusaurus-theme-mermaid/package.json
@@ -33,11 +33,11 @@
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
},
"dependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"mermaid": "^9.4.3",
"tslib": "^2.5.0"
},
diff --git a/packages/docusaurus-theme-search-algolia/package.json b/packages/docusaurus-theme-search-algolia/package.json
index d67ee3464cf9..5de7a26119e2 100644
--- a/packages/docusaurus-theme-search-algolia/package.json
+++ b/packages/docusaurus-theme-search-algolia/package.json
@@ -34,13 +34,13 @@
},
"dependencies": {
"@docsearch/react": "^3.3.3",
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/plugin-content-docs": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/theme-translations": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/plugin-content-docs": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/theme-translations": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"algoliasearch": "^4.15.0",
"algoliasearch-helper": "^3.12.0",
"clsx": "^1.2.1",
@@ -51,7 +51,7 @@
"utility-types": "^3.10.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0"
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0"
},
"peerDependencies": {
"react": "^18.0.0",
diff --git a/packages/docusaurus-theme-translations/package.json b/packages/docusaurus-theme-translations/package.json
index 8a7ac63ddd41..6add1f1cc19d 100644
--- a/packages/docusaurus-theme-translations/package.json
+++ b/packages/docusaurus-theme-translations/package.json
@@ -23,8 +23,8 @@
"tslib": "^2.5.0"
},
"devDependencies": {
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
"lodash": "^4.17.21"
},
"engines": {
diff --git a/packages/docusaurus-utils-validation/package.json b/packages/docusaurus-utils-validation/package.json
index ce4bed0ef94d..86877e1fd934 100644
--- a/packages/docusaurus-utils-validation/package.json
+++ b/packages/docusaurus-utils-validation/package.json
@@ -18,8 +18,8 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
"joi": "^17.8.3",
"js-yaml": "^4.1.0",
"tslib": "^2.5.0"
diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json
index c021dfe84325..5ca9bc100224 100644
--- a/packages/docusaurus-utils/package.json
+++ b/packages/docusaurus-utils/package.json
@@ -18,7 +18,7 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/logger": "^3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
"@svgr/webpack": "^6.5.1",
"escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0",
@@ -39,7 +39,7 @@
"node": ">=16.14"
},
"devDependencies": {
- "@docusaurus/types": "^3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
"@types/dedent": "^0.7.0",
"@types/github-slugger": "^1.3.0",
"@types/micromatch": "^4.0.2",
diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json
index 778c615f99e7..ec59a3eb3521 100644
--- a/packages/docusaurus/package.json
+++ b/packages/docusaurus/package.json
@@ -43,13 +43,13 @@
"@babel/runtime": "^7.21.0",
"@babel/runtime-corejs3": "^7.21.0",
"@babel/traverse": "^7.21.2",
- "@docusaurus/cssnano-preset": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/mdx-loader": "^3.0.0-alpha.0",
+ "@docusaurus/cssnano-preset": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/mdx-loader": "3.0.0-alpha.0",
"@docusaurus/react-loadable": "5.5.2",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
- "@docusaurus/utils-validation": "^3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
+ "@docusaurus/utils-validation": "3.0.0-alpha.0",
"@slorber/static-site-generator-webpack-plugin": "^4.0.7",
"@svgr/webpack": "^6.5.1",
"autoprefixer": "^10.4.13",
@@ -106,8 +106,8 @@
"webpackbar": "^5.0.2"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.0.0-alpha.0",
- "@docusaurus/types": "^3.0.0-alpha.0",
+ "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
+ "@docusaurus/types": "3.0.0-alpha.0",
"@types/detect-port": "^1.3.2",
"@types/react-dom": "^18.0.11",
"@types/react-router-config": "^5.0.6",
diff --git a/packages/lqip-loader/package.json b/packages/lqip-loader/package.json
index 0de1bdd3a074..ed9c93489e71 100644
--- a/packages/lqip-loader/package.json
+++ b/packages/lqip-loader/package.json
@@ -17,7 +17,7 @@
},
"license": "MIT",
"dependencies": {
- "@docusaurus/logger": "^3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
"file-loader": "^6.2.0",
"lodash": "^4.17.21",
"sharp": "^0.31.3",
diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index 3fc8ff528aac..45344a383175 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -23,6 +23,20 @@ const ArchivedVersionsDropdownItems = Object.entries(VersionsArchived).splice(
5,
);
+/** @param {string} version */
+function isPrerelease(version) {
+ return (
+ version.includes('alpha') ||
+ version.includes('beta') ||
+ version.includes('rc')
+ );
+}
+
+function getLastVersion() {
+ const firstStableVersion = versions.find((version) => !isPrerelease(version));
+ return firstStableVersion ?? versions[0];
+}
+
// This probably only makes sense for the alpha/beta/rc phase, temporary
function getNextVersionName() {
return 'Canary';
@@ -360,9 +374,9 @@ module.exports = async function createConfigAsync() {
rehypePlugins: [(await import('rehype-katex')).default],
disableVersioning: isVersioningDisabled,
lastVersion:
- isDev || isDeployPreview || isBranchDeploy
+ isDev || isDeployPreview || isBranchDeploy || isBuildFast
? 'current'
- : undefined,
+ : getLastVersion(),
onlyIncludeVersions: (() => {
if (isBuildFast) {
diff --git a/website/package.json b/website/package.json
index 3135c85106b4..3c80f74ea1a7 100644
--- a/website/package.json
+++ b/website/package.json
@@ -36,19 +36,19 @@
"dependencies": {
"@crowdin/cli": "^3.10.0",
"@crowdin/crowdin-api-client": "^1.22.0",
- "@docusaurus/core": "^3.0.0-alpha.0",
- "@docusaurus/logger": "^3.0.0-alpha.0",
- "@docusaurus/plugin-client-redirects": "^3.0.0-alpha.0",
- "@docusaurus/plugin-ideal-image": "^3.0.0-alpha.0",
- "@docusaurus/plugin-pwa": "^3.0.0-alpha.0",
- "@docusaurus/preset-classic": "^3.0.0-alpha.0",
- "@docusaurus/remark-plugin-npm2yarn": "^3.0.0-alpha.0",
- "@docusaurus/theme-classic": "^3.0.0-alpha.0",
- "@docusaurus/theme-common": "^3.0.0-alpha.0",
- "@docusaurus/theme-mermaid": "^3.0.0-alpha.0",
- "@docusaurus/theme-live-codeblock": "^3.0.0-alpha.0",
- "@docusaurus/utils": "^3.0.0-alpha.0",
- "@docusaurus/utils-common": "^3.0.0-alpha.0",
+ "@docusaurus/core": "3.0.0-alpha.0",
+ "@docusaurus/logger": "3.0.0-alpha.0",
+ "@docusaurus/plugin-client-redirects": "3.0.0-alpha.0",
+ "@docusaurus/plugin-ideal-image": "3.0.0-alpha.0",
+ "@docusaurus/plugin-pwa": "3.0.0-alpha.0",
+ "@docusaurus/preset-classic": "3.0.0-alpha.0",
+ "@docusaurus/remark-plugin-npm2yarn": "3.0.0-alpha.0",
+ "@docusaurus/theme-classic": "3.0.0-alpha.0",
+ "@docusaurus/theme-common": "3.0.0-alpha.0",
+ "@docusaurus/theme-live-codeblock": "3.0.0-alpha.0",
+ "@docusaurus/theme-mermaid": "3.0.0-alpha.0",
+ "@docusaurus/utils": "3.0.0-alpha.0",
+ "@docusaurus/utils-common": "3.0.0-alpha.0",
"@popperjs/core": "^2.11.6",
"@swc/core": "1.2.197",
"clsx": "^1.2.1",
@@ -83,8 +83,8 @@
]
},
"devDependencies": {
- "@docusaurus/eslint-plugin": "^3.0.0-alpha.0",
- "@docusaurus/tsconfig": "^3.0.0-alpha.0",
+ "@docusaurus/eslint-plugin": "3.0.0-alpha.0",
+ "@docusaurus/tsconfig": "3.0.0-alpha.0",
"@types/jest": "^29.4.0",
"cross-env": "^7.0.3",
"rimraf": "^3.0.2"
diff --git a/website/versioned_docs/version-3.0.0-alpha.0/advanced/architecture.mdx b/website/versioned_docs/version-3.0.0-alpha.0/advanced/architecture.mdx
new file mode 100644
index 000000000000..91dfecf3675c
--- /dev/null
+++ b/website/versioned_docs/version-3.0.0-alpha.0/advanced/architecture.mdx
@@ -0,0 +1,28 @@
+---
+description: How Docusaurus works to build your app
+---
+
+# Architecture
+
+```mdx-code-block
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import Zoom from 'react-medium-image-zoom';
+```
+
+
+
+![Architecture overview](/img/architecture.png)
+
+
+
+This diagram shows how Docusaurus works to build your app. Plugins each collect their content and emit JSON data; themes provide layout components which receive the JSON data as route modules. The bundler bundles all the components and emits a server bundle and a client bundle.
+
+Although you (either plugin authors or site creators) are writing JavaScript all the time, bear in mind that the JS is actually run in different environments:
+
+- All plugin lifecycle methods are run in Node. Therefore, until we support ES Modules in our codebase, plugin source code must be provided as CommonJS that can be `require`'d.
+- The theme code is built with Webpack. They can be provided as ESM—following React conventions.
+
+Plugin code and theme code never directly import each other: they only communicate through protocols (in our case, through JSON temp files and calls to `addRoute`). A useful mental model is to imagine that the plugins are not written in JavaScript, but in another language like Rust. The only way to interact with plugins for the user is through `docusaurus.config.js`, which itself is run in Node (hence you can use `require` and pass callbacks as plugin options).
+
+During bundling, the config file itself is serialized and bundled, allowing the theme to access config options like `themeConfig` or `baseUrl` through [`useDocusaurusContext()`](../docusaurus-core.mdx#useDocusaurusContext). However, the `siteConfig` object only contains **serializable values** (values that are preserved after `JSON.stringify()`). Functions, regexes, etc. would be lost on the client side. The `themeConfig` is designed to be entirely serializable.
diff --git a/website/versioned_docs/version-3.0.0-alpha.0/advanced/client.mdx b/website/versioned_docs/version-3.0.0-alpha.0/advanced/client.mdx
new file mode 100644
index 000000000000..189faab8ba56
--- /dev/null
+++ b/website/versioned_docs/version-3.0.0-alpha.0/advanced/client.mdx
@@ -0,0 +1,186 @@
+---
+description: How the Docusaurus client is structured
+---
+
+# Client architecture
+
+## Theme aliases {#theme-aliases}
+
+A theme works by exporting a set of components, e.g. `Navbar`, `Layout`, `Footer`, to render the data passed down from plugins. Docusaurus and users use these components by importing them using the `@theme` webpack alias:
+
+```js
+import Navbar from '@theme/Navbar';
+```
+
+The alias `@theme` can refer to a few directories, in the following priority:
+
+1. A user's `website/src/theme` directory, which is a special directory that has the higher precedence.
+2. A Docusaurus theme package's `theme` directory.
+3. Fallback components provided by Docusaurus core (usually not needed).
+
+This is called a _layered architecture_: a higher-priority layer providing the component would shadow a lower-priority layer, making swizzling possible. Given the following structure:
+
+```
+website
+├── node_modules
+│ └── @docusaurus/theme-classic
+│ └── theme
+│ └── Navbar.js
+└── src
+ └── theme
+ └── Navbar.js
+```
+
+`website/src/theme/Navbar.js` takes precedence whenever `@theme/Navbar` is imported. This behavior is called component swizzling. If you are familiar with Objective C where a function's implementation can be swapped during runtime, it's the exact same concept here with changing the target `@theme/Navbar` is pointing to!
+
+We already talked about how the "userland theme" in `src/theme` can re-use a theme component through the [`@theme-original`](#wrapping) alias. One theme package can also wrap a component from another theme, by importing the component from the initial theme, using the `@theme-init` import.
+
+Here's an example of using this feature to enhance the default theme `CodeBlock` component with a `react-live` playground feature.
+
+```js
+import InitialCodeBlock from '@theme-init/CodeBlock';
+import React from 'react';
+
+export default function CodeBlock(props) {
+ return props.live ? (
+
+ ) : (
+
+ );
+}
+```
+
+Check the code of `@docusaurus/theme-live-codeblock` for details.
+
+:::caution
+
+Unless you want to publish a re-usable "theme enhancer" (like `@docusaurus/theme-live-codeblock`), you likely don't need `@theme-init`.
+
+:::
+
+It can be quite hard to wrap your mind around these aliases. Let's imagine the following case with a super convoluted setup with three themes/plugins and the site itself all trying to define the same component. Internally, Docusaurus loads these themes as a "stack".
+
+```text
++-------------------------------------------------+
+| `website/src/theme/CodeBlock.js` | <-- `@theme/CodeBlock` always points to the top
++-------------------------------------------------+
+| `theme-live-codeblock/theme/CodeBlock/index.js` | <-- `@theme-original/CodeBlock` points to the topmost non-swizzled component
++-------------------------------------------------+
+| `plugin-awesome-codeblock/theme/CodeBlock.js` |
++-------------------------------------------------+
+| `theme-classic/theme/CodeBlock/index.js` | <-- `@theme-init/CodeBlock` always points to the bottom
++-------------------------------------------------+
+```
+
+The components in this "stack" are pushed in the order of `preset plugins > preset themes > plugins > themes > site`, so the swizzled component in `website/src/theme` always comes out on top because it's loaded last.
+
+`@theme/*` always points to the topmost component—when `CodeBlock` is swizzled, all other components requesting `@theme/CodeBlock` receive the swizzled version.
+
+`@theme-original/*` always points to the topmost non-swizzled component. That's why you can import `@theme-original/CodeBlock` in the swizzled component—it points to the next one in the "component stack", a theme-provided one. Plugin authors should not try to use this because your component could be the topmost component and cause a self-import.
+
+`@theme-init/*` always points to the bottommost component—usually, this comes from the theme or plugin that first provides this component. Individual plugins / themes trying to enhance code block can safely use `@theme-init/CodeBlock` to get its basic version. Site creators should generally not use this because you likely want to enhance the _topmost_ instead of the _bottommost_ component. It's also possible that the `@theme-init/CodeBlock` alias does not exist at all—Docusaurus only creates it when it points to a different one from `@theme-original/CodeBlock`, i.e. when it's provided by more than one theme. We don't waste aliases!
+
+## Client modules {#client-modules}
+
+Client modules are part of your site's bundle, just like theme components. However, they are usually side-effect-ful. Client modules are anything that can be `import`ed by Webpack—CSS, JS, etc. JS scripts usually work on the global context, like registering event listeners, creating global variables...
+
+These modules are imported globally before React even renders the initial UI.
+
+```js title="@docusaurus/core/App.tsx"
+// How it works under the hood
+import '@generated/client-modules';
+```
+
+Plugins and sites can both declare client modules, through [`getClientModules`](../api/plugin-methods/lifecycle-apis.mdx#getClientModules) and [`siteConfig.clientModules`](../api/docusaurus.config.js.mdx#clientModules), respectively.
+
+Client modules are called during server-side rendering as well, so remember to check the [execution environment](./ssg.mdx#escape-hatches) before accessing client-side globals.
+
+```js title="mySiteGlobalJs.js"
+import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
+
+if (ExecutionEnvironment.canUseDOM) {
+ // As soon as the site loads in the browser, register a global event listener
+ window.addEventListener('keydown', (e) => {
+ if (e.code === 'Period') {
+ location.assign(location.href.replace('.com', '.dev'));
+ }
+ });
+}
+```
+
+CSS stylesheets imported as client modules are [global](../styling-layout.mdx#global-styles).
+
+```css title="mySiteGlobalCss.css"
+/* This stylesheet is global. */
+.globalSelector {
+ color: red;
+}
+```
+
+### Client module lifecycles {#client-module-lifecycles}
+
+Besides introducing side-effects, client modules can optionally export two lifecycle functions: `onRouteUpdate` and `onRouteDidUpdate`.
+
+Because Docusaurus builds a single-page application, `script` tags will only be executed the first time the page loads, but will not re-execute on page transitions. These lifecycles are useful if you have some imperative JS logic that should execute every time a new page has loaded, e.g., to manipulate DOM elements, to send analytics data, etc.
+
+For every route transition, there will be several important timings:
+
+1. The user clicks a link, which causes the router to change its current location.
+2. Docusaurus preloads the next route's assets, while keeping displaying the current page's content.
+3. The next route's assets have loaded.
+4. The new location's route component gets rendered to DOM.
+
+`onRouteUpdate` will be called at event (2), and `onRouteDidUpdate` will be called at (4). They both receive the current location and the previous location (which can be `null`, if this is the first screen).
+
+`onRouteUpdate` can optionally return a "cleanup" callback, which will be called at (3). For example, if you want to display a progress bar, you can start a timeout in `onRouteUpdate`, and clear the timeout in the callback. (The classic theme already provides an `nprogress` integration this way.)
+
+Note that the new page's DOM is only available during event (4). If you need to manipulate the new page's DOM, you'll likely want to use `onRouteDidUpdate`, which will be fired as soon as the DOM on the new page has mounted.
+
+```js title="myClientModule.js"
+import type {Location} from 'history';
+
+export function onRouteDidUpdate({location, previousLocation}) {
+ // Don't execute if we are still on the same page; the lifecycle may be fired
+ // because the hash changes (e.g. when navigating between headings)
+ if (location.pathname !== previousLocation?.pathname) {
+ const title = document.getElementsByTagName('h1')[0];
+ if (title) {
+ title.innerText += '❤️';
+ }
+ }
+}
+
+export function onRouteUpdate({location, previousLocation}) {
+ if (location.pathname !== previousLocation?.pathname) {
+ const progressBarTimeout = window.setTimeout(() => {
+ nprogress.start();
+ }, delay);
+ return () => window.clearTimeout(progressBarTimeout);
+ }
+ return undefined;
+}
+```
+
+Or, if you are using TypeScript and you want to leverage contextual typing:
+
+```ts title="myClientModule.ts"
+import type {ClientModule} from '@docusaurus/types';
+
+const module: ClientModule = {
+ onRouteUpdate({location, previousLocation}) {
+ // ...
+ },
+ onRouteDidUpdate({location, previousLocation}) {
+ // ...
+ },
+};
+export default module;
+```
+
+Both lifecycles will fire on first render, but they will not fire on server-side, so you can safely access browser globals in them.
+
+:::tip Prefer using React
+
+Client module lifecycles are purely imperative, and you can't use React hooks or access React contexts within them. If your operations are state-driven or involve complicated DOM manipulations, you should consider [swizzling components](../swizzling.mdx) instead.
+
+:::
diff --git a/website/versioned_docs/version-3.0.0-alpha.0/advanced/index.mdx b/website/versioned_docs/version-3.0.0-alpha.0/advanced/index.mdx
new file mode 100644
index 000000000000..b5e5deb222b6
--- /dev/null
+++ b/website/versioned_docs/version-3.0.0-alpha.0/advanced/index.mdx
@@ -0,0 +1,11 @@
+# Advanced Tutorials
+
+This section is not going to be very structured, but we will cover the following topics:
+
+```mdx-code-block
+import DocCardList from '@theme/DocCardList';
+
+
+```
+
+We will assume that you have finished the guides, and know the basics like how to configure plugins, how to write React components, etc. These sections will have plugin authors and code contributors in mind, so we may occasionally refer to [plugin APIs](../api/plugin-methods/README.mdx) or other architecture details. Don't panic if you don't understand everything😉
diff --git a/website/versioned_docs/version-3.0.0-alpha.0/advanced/plugins.mdx b/website/versioned_docs/version-3.0.0-alpha.0/advanced/plugins.mdx
new file mode 100644
index 000000000000..01b66d0c305b
--- /dev/null
+++ b/website/versioned_docs/version-3.0.0-alpha.0/advanced/plugins.mdx
@@ -0,0 +1,129 @@
+# Plugins
+
+Plugins are the building blocks of features in a Docusaurus 2 site. Each plugin handles its own individual feature. Plugins may work and be distributed as part of a bundle via presets.
+
+## Creating plugins {#creating-plugins}
+
+A plugin is a function that takes two parameters: `context` and `options`. It returns a plugin instance object (or a promise). You can create plugins as functions or modules. For more information, refer to the [plugin method references section](../api/plugin-methods/README.mdx).
+
+### Function definition {#function-definition}
+
+You can use a plugin as a function directly included in the Docusaurus config file:
+
+```js title="docusaurus.config.js"
+module.exports = {
+ // ...
+ plugins: [
+ // highlight-start
+ async function myPlugin(context, options) {
+ // ...
+ return {
+ name: 'my-plugin',
+ async loadContent() {
+ // ...
+ },
+ async contentLoaded({content, actions}) {
+ // ...
+ },
+ /* other lifecycle API */
+ };
+ },
+ // highlight-end
+ ],
+};
+```
+
+### Module definition {#module-definition}
+
+You can use a plugin as a module path referencing a separate file or npm package:
+
+```js title="docusaurus.config.js"
+module.exports = {
+ // ...
+ plugins: [
+ // without options:
+ './my-plugin',
+ // or with options:
+ ['./my-plugin', options],
+ ],
+};
+```
+
+Then in the folder `my-plugin`, you can create an `index.js` such as this:
+
+```js title="my-plugin/index.js"
+module.exports = async function myPlugin(context, options) {
+ // ...
+ return {
+ name: 'my-plugin',
+ async loadContent() {
+ /* ... */
+ },
+ async contentLoaded({content, actions}) {
+ /* ... */
+ },
+ /* other lifecycle API */
+ };
+};
+```
+
+---
+
+You can view all plugins installed in your site using the [debug plugin's metadata panel](/__docusaurus/debug/metadata).
+
+Plugins come as several types:
+
+- `package`: an external package you installed
+- `project`: a plugin you created in your project, given to Docusaurus as a local file path
+- `local`: a plugin created using the function definition
+- `synthetic`: a "fake plugin" Docusaurus created internally, so we take advantage of our modular architecture and don't let the core do much special work. You won't see this in the metadata because it's an implementation detail.
+
+You can access them on the client side with `useDocusaurusContext().siteMetadata.pluginVersions`.
+
+## Plugin design {#plugin-design}
+
+Docusaurus' implementation of the plugins system provides us with a convenient way to hook into the website's lifecycle to modify what goes on during development/build, which involves (but is not limited to) extending the webpack config, modifying the data loaded, and creating new components to be used in a page.
+
+### Theme design {#theme-design}
+
+When plugins have loaded their content, the data is made available to the client side through actions like [`createData` + `addRoute`](../api/plugin-methods/lifecycle-apis.mdx#addRoute) or [`setGlobalData`](../api/plugin-methods/lifecycle-apis.mdx#setGlobalData). This data has to be _serialized_ to plain strings, because [plugins and themes run in different environments](./architecture.mdx). Once the data arrives on the client side, the rest becomes familiar to React developers: data is passed along components, components are bundled with Webpack, and rendered to the window through `ReactDOM.render`...
+
+**Themes provide the set of UI components to render the content.** Most content plugins need to be paired with a theme in order to be actually useful. The UI is a separate layer from the data schema, which makes swapping designs easy.
+
+For example, a Docusaurus blog may consist of a blog plugin and a blog theme.
+
+:::note
+
+This is a contrived example: in practice, `@docusaurus/theme-classic` provides the theme for docs, blog, and layouts.
+
+:::
+
+```js title="docusaurus.config.js"
+module.exports = {
+ // highlight-next-line
+ themes: ['theme-blog'],
+ plugins: ['plugin-content-blog'],
+};
+```
+
+And if you want to use Bootstrap styling, you can swap out the theme with `theme-blog-bootstrap` (another fictitious non-existing theme):
+
+```js title="docusaurus.config.js"
+module.exports = {
+ // highlight-next-line
+ themes: ['theme-blog-bootstrap'],
+ plugins: ['plugin-content-blog'],
+};
+```
+
+Now, although the theme receives the same data from the plugin, how the theme chooses to _render_ the data as UI can be drastically different.
+
+While themes share the exact same lifecycle methods with plugins, themes' implementations can look very different from those of plugins based on themes' designed objectives.
+
+Themes are designed to complete the build of your Docusaurus site and supply the components used by your site, plugins, and the themes themselves. A theme still acts like a plugin and exposes some lifecycle methods, but most likely they would not use [`loadContent`](../api/plugin-methods/lifecycle-apis.mdx#loadContent), since they only receive data from plugins, but don't generate data themselves; themes are typically also accompanied by an `src/theme` directory full of components, which are made known to the core through the [`getThemePath`](../api/plugin-methods/extend-infrastructure.mdx#getThemePath) lifecycle.
+
+To summarize:
+
+- Themes share the same lifecycle methods with Plugins
+- Themes are run after all existing Plugins
+- Themes add component aliases by providing `getThemePath`.
diff --git a/website/versioned_docs/version-3.0.0-alpha.0/advanced/routing.mdx b/website/versioned_docs/version-3.0.0-alpha.0/advanced/routing.mdx
new file mode 100644
index 000000000000..73fe534e848f
--- /dev/null
+++ b/website/versioned_docs/version-3.0.0-alpha.0/advanced/routing.mdx
@@ -0,0 +1,296 @@
+---
+description: "Docusaurus' routing system follows single-page application conventions: one route, one component."
+---
+
+# Routing
+
+```mdx-code-block
+import Link from '@docusaurus/Link';
+import {useLatestVersion, useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
+import {useLocation} from '@docusaurus/router';
+import BrowserWindow from '@site/src/components/BrowserWindow';
+```
+
+Docusaurus' routing system follows single-page application conventions: one route, one component. In this section, we will begin by talking about routing within the three content plugins (docs, blog, and pages), and then go beyond to talk about the underlying routing system.
+
+## Routing in content plugins {#routing-in-content-plugins}
+
+Every content plugin provides a `routeBasePath` option. It defines where the plugins append their routes to. By default, the docs plugin puts its routes under `/docs`; the blog plugin, `/blog`; and the pages plugin, `/`. You can think about the route structure like this:
+
+```mermaid
+graph LR;
+ A(["https://example.com/"])
+ B(["/base-url/"])
+ C(["/docs/"])
+ D(["/blog/"])
+ E(["/"])
+ F["All docs routes"]
+ G["All blog routes"]
+ H["All pages routes"]
+ A---B;
+ B---C;
+ B---D;
+ B---E;
+ C---F;
+ D---G;
+ E---H;
+```
+
+Any route will be matched against this nested route config until a good match is found. For example, when given a route `/docs/configuration`, Docusaurus first enters the `/docs` branch, and then searches among the subroutes created by the docs plugin.
+
+Changing `routeBasePath` can effectively alter your site's route structure. For example, in [Docs-only mode](../guides/docs/docs-introduction.mdx#docs-only-mode), we mentioned that configuring `routeBasePath: '/'` for docs means that all routes that the docs plugin create would not have the `/docs` prefix, yet it doesn't prevent you from having more subroutes like `/blog` created by other plugins.
+
+Next, let's look at how the three plugins structure their own "boxes of subroutes".
+
+### Pages routing {#pages-routing}
+
+Pages routing are straightforward: the file paths directly map to URLs, without any other way to customize. See the [pages docs](../guides/creating-pages.mdx#routing) for more information.
+
+The component used for Markdown pages is `@theme/MDXPage`. React pages are directly used as the route's component.
+
+### Blog routing {#blog-routing}
+
+The blog creates the following routes:
+
+- **Posts list pages**: `/`, `/page/2`, `/page/3`...
+ - The component is `@theme/BlogListPage`.
+- **Post pages**: `/2021/11/21/algolia-docsearch-migration`, `/2021/05/12/announcing-docusaurus-two-beta`...
+ - Generated from each Markdown post.
+ - The routes are fully customizable through the `slug` front matter.
+ - The component is `@theme/BlogPostPage`.
+- **Tags list page**: `/tags`
+ - The route is customizable through the `tagsBasePath` option.
+ - The component is `@theme/BlogTagsListPage`.
+- **Tag pages**: `/tags/adoption`, `/tags/beta`...
+ - Generated through the tags defined in each post's front matter.
+ - The routes always have base defined in `tagsBasePath`, but the subroutes are customizable through the tag's `permalink` field.
+ - The component is `@theme/BlogTagsPostsPage`.
+- **Archive page**: `/archive`
+ - The route is customizable through the `archiveBasePath` option.
+ - The component is `@theme/BlogArchivePage`.
+
+### Docs routing {#docs-routing}
+
+The docs is the only plugin that creates **nested routes**. At the top, it registers [**version paths**](../guides/docs/versioning.mdx): `/`, `/next`, `/2.0.0-beta.13`... which provide the version context, including the layout and sidebar. This ensures that when switching between individual docs, the sidebar's state is preserved, and that you can switch between versions through the navbar dropdown while staying on the same doc. The component used is `@theme/DocPage`.
+
+```mdx-code-block
+export const URLPath = () => {useLocation().pathname};
+
+export const FilePath = () => {
+ const currentVersion = useActiveDocContext('default').activeVersion.name;
+ return {currentVersion === 'current' ? './docs/' : `./versioned_docs/version-${currentVersion}/`}advanced/routing.md;
+}
+```
+
+The individual docs are rendered in the remaining space after the navbar, footer, sidebar, etc. have all been provided by the `DocPage` component. For example, this page, , is generated from the file at . The component used is `@theme/DocItem`.
+
+The doc's `slug` front matter customizes the last part of the route, but the base route is always defined by the plugin's `routeBasePath` and the version's `path`.
+
+### File paths and URL paths {#file-paths-and-url-paths}
+
+Throughout the documentation, we always try to be unambiguous about whether we are talking about file paths or URL paths. Content plugins usually map file paths directly to URL paths, for example, `./docs/advanced/routing.md` will become `/docs/advanced/routing`. However, with `slug`, you can make URLs totally decoupled from the file structure.
+
+When writing links in Markdown, you could either mean a _file path_, or a _URL path_, which Docusaurus would use several heuristics to determine.
+
+- If the path has a `@site` prefix, it is _always_ an asset file path.
+- If the path has an `http(s)://` prefix, it is _always_ a URL path.
+- If the path doesn't have an extension, it is a URL path. For example, a link `[page](../plugins)` on a page with URL `/docs/advanced/routing` will link to `/docs/plugins`. Docusaurus will only detect broken links when building your site (when it knows the full route structure), but will make no assumptions about the existence of a file. It is exactly equivalent to writing `page` in a JSX file.
+- If the path has an `.md(x)` extension, Docusaurus would try to resolve that Markdown file to a URL, and replace the file path with a URL path.
+- If the path has any other extension, Docusaurus would treat it as [an asset](../guides/markdown-features/markdown-features-assets.mdx) and bundle it.
+
+The following directory structure may help you visualize this file → URL mapping. Assume that there's no slug customization in any page.
+
+
+
+A sample site structure
+
+```bash
+.
+├── blog # blog plugin has routeBasePath: '/blog'
+│ ├── 2019-05-28-first-blog-post.md # -> /blog/2019/05/28/first-blog-post
+│ ├── 2019-05-29-long-blog-post.md # -> /blog/2019/05/29/long-blog-post
+│ ├── 2021-08-01-mdx-blog-post.mdx # -> /blog/2021/08/01/mdx-blog-post
+│ └── 2021-08-26-welcome
+│ ├── docusaurus-plushie-banner.jpeg
+│ └── index.md # -> /blog/2021/08/26/welcome
+├── docs # docs plugin has routeBasePath: '/docs'; current version has base path '/'
+│ ├── intro.md # -> /docs/intro
+│ ├── tutorial-basics
+│ │ ├── _category_.json
+│ │ ├── congratulations.md # -> /docs/tutorial-basics/congratulations
+│ │ └── markdown-features.mdx # -> /docs/tutorial-basics/congratulations
+│ └── tutorial-extras
+│ ├── _category_.json
+│ ├── manage-docs-versions.md # -> /docs/tutorial-extras/manage-docs-versions
+│ └── translate-your-site.md # -> /docs/tutorial-extras/translate-your-site
+├── src
+│ └── pages # pages plugin has routeBasePath: '/'
+│ ├── index.module.css
+│ ├── index.tsx # -> /
+│ └── markdown-page.md # -> /markdown-page
+└── versioned_docs
+ └── version-1.0.0 # version has base path '/1.0.0'
+ ├── intro.md # -> /docs/1.0.0/intro
+ ├── tutorial-basics
+ │ ├── _category_.json
+ │ ├── congratulations.md # -> /docs/1.0.0/tutorial-basics/congratulations
+ │ └── markdown-features.mdx # -> /docs/1.0.0/tutorial-basics/markdown-features
+ └── tutorial-extras
+ ├── _category_.json
+ ├── manage-docs-versions.md # -> /docs/1.0.0/tutorial-extras/manage-docs-versions
+ └── translate-your-site.md # -> /docs/1.0.0/tutorial-extras/translate-your-site
+```
+
+
+
+So much about content plugins. Let's take one step back and talk about how routing works in a Docusaurus app in general.
+
+## Routes become HTML files {#routes-become-html-files}
+
+Because Docusaurus is a server-side rendering framework, all routes generated will be server-side rendered into static HTML files. If you are familiar with the behavior of HTTP servers like [Apache2](https://httpd.apache.org/docs/trunk/getting-started.html), you will understand how this is done: when the browser sends a request to the route `/docs/advanced/routing`, the server interprets that as request for the HTML file `/docs/advanced/routing/index.html`, and returns that.
+
+The `/docs/advanced/routing` route can correspond to either `/docs/advanced/routing/index.html` or `/docs/advanced/routing.html`. Some hosting providers differentiate between them using the presence of a trailing slash, and may or may not tolerate the other. Read more in the [trailing slash guide](https://github.com/slorber/trailing-slash-guide).
+
+For example, the build output of the directory above is (ignoring other assets and JS bundle):
+
+
+
+Output of the above workspace
+
+```bash
+build
+├── 404.html # /404/
+├── blog
+│ ├── archive
+│ │ └── index.html # /blog/archive/
+│ ├── first-blog-post
+│ │ └── index.html # /blog/first-blog-post/
+│ ├── index.html # /blog/
+│ ├── long-blog-post
+│ │ └── index.html # /blog/long-blog-post/
+│ ├── mdx-blog-post
+│ │ └── index.html # /blog/mdx-blog-post/
+│ ├── tags
+│ │ ├── docusaurus
+│ │ │ └── index.html # /blog/tags/docusaurus/
+│ │ ├── hola
+│ │ │ └── index.html # /blog/tags/hola/
+│ │ └── index.html # /blog/tags/
+│ └── welcome
+│ └── index.html # /blog/welcome/
+├── docs
+│ ├── 1.0.0
+│ │ ├── intro
+│ │ │ └── index.html # /docs/1.0.0/intro/
+│ │ ├── tutorial-basics
+│ │ │ ├── congratulations
+│ │ │ │ └── index.html # /docs/1.0.0/tutorial-basics/congratulations/
+│ │ │ └── markdown-features
+│ │ │ └── index.html # /docs/1.0.0/tutorial-basics/markdown-features/
+│ │ └── tutorial-extras
+│ │ ├── manage-docs-versions
+│ │ │ └── index.html # /docs/1.0.0/tutorial-extras/manage-docs-versions/
+│ │ └── translate-your-site
+│ │ └── index.html # /docs/1.0.0/tutorial-extras/translate-your-site/
+│ ├── intro
+│ │ └── index.html # /docs/1.0.0/intro/
+│ ├── tutorial-basics
+│ │ ├── congratulations
+│ │ │ └── index.html # /docs/tutorial-basics/congratulations/
+│ │ └── markdown-features
+│ │ └── index.html # /docs/tutorial-basics/markdown-features/
+│ └── tutorial-extras
+│ ├── manage-docs-versions
+│ │ └── index.html # /docs/tutorial-extras/manage-docs-versions/
+│ └── translate-your-site
+│ └── index.html # /docs/tutorial-extras/translate-your-site/
+├── index.html # /
+└── markdown-page
+ └── index.html # /markdown-page/
+```
+
+
+
+If `trailingSlash` is set to `false`, the build would emit `intro.html` instead of `intro/index.html`.
+
+All HTML files will reference its JS assets using absolute URLs, so in order for the correct assets to be located, you have to configure the `baseUrl` field. Note that `baseUrl` doesn't affect the emitted bundle's file structure: the base URL is one level above the Docusaurus routing system. You can see the aggregate of `url` and `baseUrl` as the actual location of your Docusaurus site.
+
+For example, the emitted HTML would contain links like ``. Because absolute URLs are resolved from the host, if the bundle placed under the path `https://example.com/base/`, the link will point to `https://example.com/assets/js/runtime~main.7ed5108a.js`, which is, well, non-existent. By specifying `/base/` as base URL, the link will correctly point to `/base/assets/js/runtime~main.7ed5108a.js`.
+
+Localized sites have the locale as part of the base URL as well. For example, `https://docusaurus.io/zh-CN/docs/advanced/routing/` has base URL `/zh-CN/`.
+
+## Generating and accessing routes {#generating-and-accessing-routes}
+
+The `addRoute` lifecycle action is used to generate routes. It registers a piece of route config to the route tree, giving a route, a component, and props that the component needs. The props and the component are both provided as paths for the bundler to `require`, because as explained in the [architecture overview](architecture.mdx), server and client only communicate through temp files.
+
+All routes are aggregated in `.docusaurus/routes.js`, which you can view with the debug plugin's [routes panel](/__docusaurus/debug/routes).
+
+On the client side, we offer `@docusaurus/router` to access the page's route. `@docusaurus/router` is a re-export of the [`react-router-dom`](https://www.npmjs.com/package/react-router-dom/v/5.3.0) package. For example, you can use `useLocation` to get the current page's [location](https://developer.mozilla.org/en-US/docs/Web/API/Location), and `useHistory` to access the [history object](https://developer.mozilla.org/en-US/docs/Web/API/History). (They are not the same as the browser API, although similar in functionality. Refer to the React Router documentation for specific APIs.)
+
+This API is **SSR safe**, as opposed to the browser-only `window.location`.
+
+```jsx title="myComponent.js"
+import React from 'react';
+import {useLocation} from '@docusaurus/router';
+
+export function PageRoute() {
+ // React router provides the current component's route, even in SSR
+ const location = useLocation();
+ return (
+
+ We are currently on {location.pathname}
+
+ );
+}
+```
+
+```mdx-code-block
+export function PageRoute() {
+ const location = useLocation();
+ return (
+
+ We are currently on {location.pathname}
+
+ );
+}
+
+
+
+
+
+
+```
+
+## Escaping from SPA redirects {#escaping-from-spa-redirects}
+
+Docusaurus builds a [single-page application](https://developer.mozilla.org/en-US/docs/Glossary/SPA), where route transitions are done through the `history.push()` method of React router. This operation is done on the client side. However, the prerequisite for a route transition to happen this way is that the target URL is known to our router. Otherwise, the router catches this path and displays a 404 page instead.
+
+If you put some HTML pages under the `static` folder, they will be copied to the build output and therefore become accessible as part of your website, yet it's not part of the Docusaurus route system. We provide a `pathname://` protocol that allows you to redirect to another part of your domain in a non-SPA fashion, as if this route is an external link. Try the following two links:
+
+```md
+- [/pure-html](/pure-html)
+- [pathname:///pure-html](pathname:///pure-html)
+```
+
+
+
+- [/pure-html](/pure-html)
+- [pathname:///pure-html](pathname:///pure-html)
+
+
+
+:::tip
+
+The first link will **not** trigger a "broken links detected" check during the production build, because the respective file actually exists. Nevertheless, when you click on the link, a "page not found" will be displayed until you refresh.
+
+:::
+
+The `pathname://` protocol is useful for referencing any content in the static folder. For example, Docusaurus would convert [all Markdown static assets to require() calls](../guides/markdown-features/markdown-features-assets.mdx#static-assets). You can use `pathname://` to keep it a regular link instead of being hashed by Webpack.
+
+```md title="my-doc.md"
+![An image from the static](pathname:///img/docusaurus.png)
+
+[An asset from the static](pathname:///files/asset.pdf)
+```
+
+Docusaurus will only strip the `pathname://` prefix without processing the content.
diff --git a/website/versioned_docs/version-3.0.0-alpha.0/advanced/ssg.mdx b/website/versioned_docs/version-3.0.0-alpha.0/advanced/ssg.mdx
new file mode 100644
index 000000000000..7fd0724ece35
--- /dev/null
+++ b/website/versioned_docs/version-3.0.0-alpha.0/advanced/ssg.mdx
@@ -0,0 +1,218 @@
+---
+sidebar_label: Static site generation
+description: Docusaurus statically renders your React code into HTML, allowing faster load speed and better SEO.
+---
+
+# Static site generation (SSG)
+
+In [architecture](architecture.mdx), we mentioned that the theme is run in Webpack. But beware: that doesn't mean it always has access to browser globals! The theme is built twice:
+
+- During **server-side rendering**, the theme is compiled in a sandbox called [React DOM Server](https://reactjs.org/docs/react-dom-server.html). You can see this as a "headless browser", where there is no `window` or `document`, only React. SSR produces static HTML pages.
+- During **client-side rendering**, the theme is compiled to JavaScript that gets eventually executed in the browser, so it has access to browser variables.
+
+:::info SSR or SSG?
+
+_Server-side rendering_ and _static site generation_ can be different concepts, but we use them interchangeably.
+
+Strictly speaking, Docusaurus is a static site generator, because there's no server-side runtime—we statically render to HTML files that are deployed on a CDN, instead of dynamically pre-rendering on each request. This differs from the working model of [Next.js](https://nextjs.org/).
+
+:::
+
+Therefore, while you probably know not to access Node globals like `process` ([or can we?](#node-env)) or the `'fs'` module, you can't freely access browser globals either.
+
+```jsx
+import React from 'react';
+
+export default function WhereAmI() {
+ return {window.location.href};
+}
+```
+
+This looks like idiomatic React, but if you run `docusaurus build`, you will get an error:
+
+```
+ReferenceError: window is not defined
+```
+
+This is because during server-side rendering, the Docusaurus app isn't actually run in browser, and it doesn't know what `window` is.
+
+```mdx-code-block
+
+What about process.env.NODE_ENV?
+```
+
+One exception to the "no Node globals" rule is `process.env.NODE_ENV`. In fact, you can use it in React, because Webpack injects this variable as a global:
+
+```jsx
+import React from 'react';
+
+export default function expensiveComp() {
+ if (process.env.NODE_ENV === 'development') {
+ return <>This component is not shown in development>;
+ }
+ const res = someExpensiveOperationThatLastsALongTime();
+ return <>{res}>;
+}
+```
+
+During Webpack build, the `process.env.NODE_ENV` will be replaced with the value, either `'development'` or `'production'`. You will then get different build results after dead code elimination:
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+```mdx-code-block
+
+
+```
+
+```diff
+import React from 'react';
+
+export default function expensiveComp() {
+ // highlight-next-line
+ if ('development' === 'development') {
++ return <>This component is not shown in development>;
+ }
+- const res = someExpensiveOperationThatLastsALongTime();
+- return <>{res}>;
+}
+```
+
+```mdx-code-block
+
+
+```
+
+```diff
+import React from 'react';
+
+export default function expensiveComp() {
+ // highlight-next-line
+- if ('production' === 'development') {
+- return <>This component is not shown in development>;
+- }
++ const res = someExpensiveOperationThatLastsALongTime();
++ return <>{res}>;
+}
+```
+
+```mdx-code-block
+
+
+
+```
+
+## Understanding SSR {#understanding-ssr}
+
+React is not just a dynamic UI runtime—it's also a templating engine. Because Docusaurus sites mostly contain static contents, it should be able to work without any JavaScript (which React runs in), but only plain HTML/CSS. And that's what server-side rendering offers: statically rendering your React code into HTML, without any dynamic content. An HTML file has no concept of client state (it's purely markup), hence it shouldn't rely on browser APIs.
+
+These HTML files are the first to arrive at the user's browser screen when a URL is visited (see [routing](routing.mdx)). Afterwards, the browser fetches and runs other JS code to provide the "dynamic" parts of your site—anything implemented with JavaScript. However, before that, the main content of your page is already visible, allowing faster loading.
+
+In CSR-only apps, all DOM elements are generated on client side with React, and the HTML file only ever contains one root element for React to mount DOM to; in SSR, React is already facing a fully built HTML page, and it only needs to correlate the DOM elements with the virtual DOM in its model. This step is called "hydration". After React has hydrated the static markup, the app starts to work as any normal React app.
+
+Note that Docusaurus is ultimately a single-page application, so static site generation is only an optimization (_progressive enhancement_, as it's called), but our functionality does not fully depend on those HTML files. This is contrary to site generators like [Jekyll](https://jekyllrb.com/) and [Docusaurus v1](https://v1.docusaurus.io/), where all files are statically transformed to markup, and interactiveness is added through external JavaScript linked with `
+ <% }); %>
+ <%~ it.postBodyTags %>
+