@mdn/fred 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/.env-dist +3 -3
  2. package/CHANGELOG.md +33 -0
  3. package/README.md +4 -0
  4. package/build/env.js +11 -2
  5. package/build/render.js +4 -8
  6. package/build/ssr.js +3 -2
  7. package/components/env/README.md +28 -0
  8. package/components/env/index.js +9 -30
  9. package/components/env/runtime.js +6 -0
  10. package/components/env/types.d.ts +5 -0
  11. package/components/env/utils.js +56 -0
  12. package/components/outer-layout/server.js +12 -0
  13. package/components/play-runner/element.js +7 -2
  14. package/out/service-worker.js +1 -1
  15. package/out/service-worker.js.map +1 -1
  16. package/out/static/client/{1231.df3f6728f4b7e36e.js → 1231.84c230e0fa92f2d4.js} +2 -2
  17. package/out/static/client/{1231.df3f6728f4b7e36e.js.map → 1231.84c230e0fa92f2d4.js.map} +1 -1
  18. package/out/static/client/{1274.5c4c7493aa8334bf.js → 1274.e98f5c68889cda35.js} +2 -2
  19. package/out/static/client/{1274.5c4c7493aa8334bf.js.map → 1274.e98f5c68889cda35.js.map} +1 -1
  20. package/out/static/client/{2936.2446688864e1a136.js → 2936.7d85bf584b89578b.js} +2 -2
  21. package/out/static/client/{2936.2446688864e1a136.js.map → 2936.7d85bf584b89578b.js.map} +1 -1
  22. package/out/static/client/{370.85e6b0ff8596c5ae.js → 370.d2e13711140af6d1.js} +3 -3
  23. package/out/static/client/{370.85e6b0ff8596c5ae.js.map → 370.d2e13711140af6d1.js.map} +1 -1
  24. package/out/static/client/{451.d36f6f80badd6af6.js → 451.cd85e2808f388a00.js} +2 -2
  25. package/out/static/client/{451.d36f6f80badd6af6.js.map → 451.cd85e2808f388a00.js.map} +1 -1
  26. package/out/static/client/{606.221fc4347a8278e8.js → 606.d22d2cf33232a730.js} +2 -2
  27. package/out/static/client/{606.221fc4347a8278e8.js.map → 606.d22d2cf33232a730.js.map} +1 -1
  28. package/out/static/client/{8093.81b1b345d454a85e.js → 8093.b03f1cb1e8b0984a.js} +3 -3
  29. package/out/static/client/{8093.81b1b345d454a85e.js.map → 8093.b03f1cb1e8b0984a.js.map} +1 -1
  30. package/out/static/client/{9784.0096d3445a2a7e98.js → 9784.214845ec6d3b77e3.js} +3 -3
  31. package/out/static/client/{9784.0096d3445a2a7e98.js.map → 9784.214845ec6d3b77e3.js.map} +1 -1
  32. package/out/static/client/{9837.2374d8bd425a9866.js → 9837.6876cb5a9d3ad763.js} +2 -2
  33. package/out/static/client/{9837.2374d8bd425a9866.js.map → 9837.6876cb5a9d3ad763.js.map} +1 -1
  34. package/out/static/client/{9914.9b7171874efa4629.js → 9914.0e9589033d2579e2.js} +2 -2
  35. package/out/static/client/9914.0e9589033d2579e2.js.map +1 -0
  36. package/out/static/client/{index.dfccf913556b909a.js → index.1e789b86311a8c84.js} +10 -10
  37. package/out/static/client/index.1e789b86311a8c84.js.map +1 -0
  38. package/out/static/client/{runtime.05472639a6b3fea7.js → runtime.8c7621b5c39c82eb.js} +2 -2
  39. package/out/static/client/{runtime.05472639a6b3fea7.js.map → runtime.8c7621b5c39c82eb.js.map} +1 -1
  40. package/out/static/client/stats.json +332 -332
  41. package/out/static/client/{styles-a11y-menu.87133247d94d171f.js → styles-a11y-menu.9ef9230de282e800.js} +1 -1
  42. package/out/static/client/{styles-advertising.a820b0fbd3627483.js → styles-advertising.a44392a700080714.js} +1 -1
  43. package/out/static/client/{styles-article-footer.6be3444c8d5eb565.js → styles-article-footer.86b64eeebebad91b.js} +1 -1
  44. package/out/static/client/{styles-banner.bca362a6a4f7c302.js → styles-banner.fbff125bcec971bb.js} +1 -1
  45. package/out/static/client/styles-baseline-indicator.bf566965786907bc.js +1 -0
  46. package/out/static/client/{styles-blog-index.acbed372695bc055.js → styles-blog-index.ffc8cf956c8e4373.js} +1 -1
  47. package/out/static/client/{styles-blog-post.72b868f89027427f.js → styles-blog-post.a91d641515116579.js} +1 -1
  48. package/out/static/client/{styles-breadcrumbs-bar.0e8d97523444c0fe.js → styles-breadcrumbs-bar.99a04f7eef75930e.js} +1 -1
  49. package/out/static/client/{styles-breadcrumbs.9160a3861a8ab53a.js → styles-breadcrumbs.efcc208fb9e255c5.js} +1 -1
  50. package/out/static/client/{styles-button.9ae9af48571a4080.js → styles-button.fbe882b992422121.js} +1 -1
  51. package/out/static/client/{styles-content-section.ec1b9dc73aceca10.js → styles-content-section.97477ade56571b27.js} +1 -1
  52. package/out/static/client/styles-contributor-spotlight.f38b65412f05511a.js +1 -0
  53. package/out/static/client/{styles-curriculum-about.14f748159af30620.js → styles-curriculum-about.f15ed5fd5438c809.js} +1 -1
  54. package/out/static/client/styles-curriculum-default.e5662ee1eb84c092.js +1 -0
  55. package/out/static/client/styles-curriculum-landing.6e4b9b74a02421c0.js +1 -0
  56. package/out/static/client/{styles-curriculum-module.7957e2e3bd0eafb5.js → styles-curriculum-module.4f565696a741e039.js} +1 -1
  57. package/out/static/client/styles-curriculum-overview.03c8bb59e85f60fc.js +1 -0
  58. package/out/static/client/{styles-featured-articles.fe5075936dc1689d.js → styles-featured-articles.33d674ab9d0a4b23.js} +1 -1
  59. package/out/static/client/{styles-footer.5a5264232af3c286.js → styles-footer.61afa985d6c61587.js} +1 -1
  60. package/out/static/client/{styles-generic-about.bd6c3ab10cbfb61b.js → styles-generic-about.832ee823b2a15f3d.js} +1 -1
  61. package/out/static/client/{styles-generic-community.01f6a7593bc9268d.js → styles-generic-community.747ac72340973838.js} +1 -1
  62. package/out/static/client/{styles-generic-content.37bf952fe2b843c3.js → styles-generic-content.a3756d3e18ebaa38.js} +1 -1
  63. package/out/static/client/{styles-generic-layout.d5a8393d0e416a5a.js → styles-generic-layout.35e962adef8a2f23.js} +1 -1
  64. package/out/static/client/{styles-generic-sidebar.b3d7d5203335b86b.js → styles-generic-sidebar.0292229bdf97c876.js} +1 -1
  65. package/out/static/client/{styles-generic-toc.0f2eb841500811fe.js → styles-generic-toc.0cf78fef4fb1ca04.js} +1 -1
  66. package/out/static/client/{styles-global.1edda3f0378c4985.js → styles-global.73ea7609e20e907a.js} +1 -1
  67. package/out/static/client/styles-global.d92154c94ac95c1e.css +2 -0
  68. package/out/static/client/{styles-global.c9f2a49e47bf5c55.css.map → styles-global.d92154c94ac95c1e.css.map} +1 -1
  69. package/out/static/client/{styles-heading-anchor.459f5d2b6ef27a35.js → styles-heading-anchor.40bbc9df73fbe3ed.js} +1 -1
  70. package/out/static/client/{styles-homepage-body.1353218dc43e8403.js → styles-homepage-body.4d5de7246b823efb.js} +1 -1
  71. package/out/static/client/styles-homepage-contributor-spotlight.40146b76a1b9b98d.js +1 -0
  72. package/out/static/client/{styles-homepage-footer.a2e302b524b9cb41.js → styles-homepage-footer.1d2128d057b63f1c.js} +1 -1
  73. package/out/static/client/{styles-homepage-header.61d200f9e7261cf9.js → styles-homepage-header.7f9ca8158a115853.js} +1 -1
  74. package/out/static/client/{styles-homepage-hero.49347a14601630f9.js → styles-homepage-hero.a378110befc1e2cf.js} +1 -1
  75. package/out/static/client/{styles-homepage.5659711ea0d54c03.js → styles-homepage.5fb3fbe7543e268c.js} +1 -1
  76. package/out/static/client/{styles-latest-news.c935e3ecd62721be.js → styles-latest-news.9807f67c0586ad37.js} +1 -1
  77. package/out/static/client/{styles-left-sidebar.d250c9e1d0b8e944.js → styles-left-sidebar.2b2c4b35ffab8b27.js} +1 -1
  78. package/out/static/client/{styles-logo.d710c44f8c185a20.js → styles-logo.b0bad5a338d3c9d5.js} +1 -1
  79. package/out/static/client/{styles-mandala.80f6df343c206d80.js → styles-mandala.12a581abb318dbd8.js} +1 -1
  80. package/out/static/client/{styles-menu.5cf6280521425c6e.js → styles-menu.5b31bb6fde3da1a1.js} +1 -1
  81. package/out/static/client/{styles-navigation.ce5485bf0d2aa72c.js → styles-navigation.48b5d8d8c84bded3.js} +1 -1
  82. package/out/static/client/{styles-not-found.ed1a36323c6f034f.js → styles-not-found.d239b62bbdf556a1.js} +1 -1
  83. package/out/static/client/styles-observatory-landing.35868a8dba7b4d88.js +1 -0
  84. package/out/static/client/styles-observatory-results.7639a9793cb4d5f4.js +1 -0
  85. package/out/static/client/{styles-page-layout.ebaba26f8be73ed6.js → styles-page-layout.88f6a1626ac74ab0.js} +1 -1
  86. package/out/static/client/{styles-pagination.2180f506e667ba5c.js → styles-pagination.cf614f5da0884ae8.js} +1 -1
  87. package/out/static/client/{styles-playground.022236b630f29462.js → styles-playground.372ea0d0972b1cf7.js} +1 -1
  88. package/out/static/client/styles-recent-contributions.1381c21c0d5a9068.js +1 -0
  89. package/out/static/client/{styles-reference-layout.bffd0e6da5605009.js → styles-reference-layout.d9101683510063c5.js} +1 -1
  90. package/out/static/client/{styles-reference-toc.c8955d29f707494b.js → styles-reference-toc.b16b3ae26546340c.js} +1 -1
  91. package/out/static/client/{styles-sandbox.6a001e2be84a6688.js → styles-sandbox.c6f491538eb37b5a.js} +1 -1
  92. package/out/static/client/{styles-site-search.dda21a516b8b58c1.js → styles-site-search.0c4b85eda79571bf.js} +1 -1
  93. package/out/static/client/{styles-translation-banner.affb41df0468f016.js → styles-translation-banner.89994e4b4025fca7.js} +1 -1
  94. package/out/static/client/{styles-writer-toolbar.dc0dfffc08e850d6.js → styles-writer-toolbar.8cf64ea391d384dc.js} +1 -1
  95. package/out/static/client/{styles.a184d8a933a6c3a6.js → styles.7e12510d3d62d6c2.js} +2 -2
  96. package/out/static/client/{styles.a184d8a933a6c3a6.js.map → styles.7e12510d3d62d6c2.js.map} +1 -1
  97. package/out/static/legacy/asset-manifest.json +6 -6
  98. package/out/static/legacy/{index.c10af7d92675e9fd.html → index.7a7a7a6c9ea9fbe7.html} +1 -1
  99. package/out/static/legacy/{index.4b9e35f28a890bda.js → index.fdfbaab08cf3189a.js} +3 -3
  100. package/out/static/legacy/{index.4b9e35f28a890bda.js.map → index.fdfbaab08cf3189a.js.map} +1 -1
  101. package/out/static/legacy/stats.json +7 -7
  102. package/out/static/legacy/{yari.2771217736dd92b4.js → yari.9ba4e4812214ca1d.js} +3 -3
  103. package/out/static/legacy/{yari.2771217736dd92b4.js.map → yari.9ba4e4812214ca1d.js.map} +1 -1
  104. package/out/static/ssr/index.js +11 -8
  105. package/out/static/ssr/index.js.map +1 -1
  106. package/out/static/ssr/stats.json +4 -4
  107. package/package.json +6 -5
  108. package/rspack.config.js +8 -7
  109. package/server.js +8 -8
  110. package/out/static/client/9914.9b7171874efa4629.js.map +0 -1
  111. package/out/static/client/index.dfccf913556b909a.js.map +0 -1
  112. package/out/static/client/styles-baseline-indicator.475001c3d152eda6.js +0 -1
  113. package/out/static/client/styles-contributor-spotlight.08c74d3c426050ed.js +0 -1
  114. package/out/static/client/styles-curriculum-default.89b14c7bf3342041.js +0 -1
  115. package/out/static/client/styles-curriculum-landing.4a5fa59933fb70fd.js +0 -1
  116. package/out/static/client/styles-curriculum-overview.9614bb249432e5e3.js +0 -1
  117. package/out/static/client/styles-global.c9f2a49e47bf5c55.css +0 -2
  118. package/out/static/client/styles-homepage-contributor-spotlight.db46ee4b1e184c36.js +0 -1
  119. package/out/static/client/styles-observatory-landing.987e00f1527a651f.js +0 -1
  120. package/out/static/client/styles-observatory-results.736e05f4bd6e1487.js +0 -1
  121. package/out/static/client/styles-recent-contributions.b5366c0daf414e8a.js +0 -1
  122. /package/out/static/client/{370.85e6b0ff8596c5ae.js.LICENSE.txt → 370.d2e13711140af6d1.js.LICENSE.txt} +0 -0
  123. /package/out/static/client/{8093.81b1b345d454a85e.js.LICENSE.txt → 8093.b03f1cb1e8b0984a.js.LICENSE.txt} +0 -0
  124. /package/out/static/client/{9784.0096d3445a2a7e98.js.LICENSE.txt → 9784.214845ec6d3b77e3.js.LICENSE.txt} +0 -0
  125. /package/out/static/client/{index.dfccf913556b909a.js.LICENSE.txt → index.1e789b86311a8c84.js.LICENSE.txt} +0 -0
  126. /package/out/static/legacy/{index.4b9e35f28a890bda.js.LICENSE.txt → index.fdfbaab08cf3189a.js.LICENSE.txt} +0 -0
  127. /package/out/static/legacy/{yari.2771217736dd92b4.js.LICENSE.txt → yari.9ba4e4812214ca1d.js.LICENSE.txt} +0 -0
package/.env-dist CHANGED
@@ -2,8 +2,8 @@
2
2
  CONTENT_ROOT=../content/files
3
3
  # https://github.com/mdn/translated-content
4
4
  CONTENT_TRANSLATED_ROOT=../translated-content/files
5
- # https://github.com/mdn/mdn-studio
6
- BLOG_ROOT=../mdn-studio/content/posts
5
+ # https://github.com/mdn/blog
6
+ BLOG_ROOT=../blog/content/posts
7
7
  # https://github.com/mdn/curriculum/
8
8
  CURRICULUM_ROOT=../curriculum
9
9
  # https://github.com/mdn/mdn-contributor-spotlight
@@ -29,4 +29,4 @@ RARI_URL="http://localhost:8083"
29
29
  REACT_APP_KUMA_HOST="localhost:3000"
30
30
  REACT_APP_FXA_SIGNIN_URL="/users/fxa/login/authenticate/"
31
31
  REACT_APP_FXA_SETTINGS_URL="https://accounts.stage.mozaws.net/settings/"
32
- REACT_APP_PLACEMENT_ENABLED="true"
32
+ REACT_APP_PLACEMENT_ENABLED="true"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.0](https://github.com/mdn/fred/compare/v1.2.0...v1.3.0) (2025-09-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * **package/bin:** add fred-ssr executable ([#678](https://github.com/mdn/fred/issues/678)) ([faa175d](https://github.com/mdn/fred/commit/faa175dbf31d5cc715bccbcb9673572e8323e340))
9
+ * **server:** allow specifiying port from env var ([#679](https://github.com/mdn/fred/issues/679)) ([eea7274](https://github.com/mdn/fred/commit/eea72742ed07d3e2230cc33c30a2f3a1fcc9b4d3))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **env:** prefix runtime var fallback only once ([eea7274](https://github.com/mdn/fred/commit/eea72742ed07d3e2230cc33c30a2f3a1fcc9b4d3))
15
+ * **server:** omit Playground server link in output ([eea7274](https://github.com/mdn/fred/commit/eea72742ed07d3e2230cc33c30a2f3a1fcc9b4d3))
16
+
17
+
18
+ ### Miscellaneous
19
+
20
+ * **deps-dev:** bump @mdn/browser-compat-data from 7.1.0 to 7.1.1 ([#677](https://github.com/mdn/fred/issues/677)) ([2a90bc2](https://github.com/mdn/fred/commit/2a90bc213785c778481299ae6fad996d3c5fe890))
21
+ * **deps-dev:** bump the dev group with 2 updates ([#660](https://github.com/mdn/fred/issues/660)) ([08c2d3d](https://github.com/mdn/fred/commit/08c2d3d465ad31dcac9f0722856822d5da8f833c))
22
+ * rename {mdn-studio => blog} ([#681](https://github.com/mdn/fred/issues/681)) ([39ab241](https://github.com/mdn/fred/commit/39ab241bf912f0f395634029d9fd11b784f28be1))
23
+
24
+ ## [1.2.0](https://github.com/mdn/fred/compare/v1.1.1...v1.2.0) (2025-08-28)
25
+
26
+
27
+ ### Features
28
+
29
+ * **env:** add runtime variables ([#642](https://github.com/mdn/fred/issues/642)) ([ab504ef](https://github.com/mdn/fred/commit/ab504effc762002df03d709e9ed605f58b6b2b22))
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * **npm:** js/styles/assets weren't being found ([#641](https://github.com/mdn/fred/issues/641)) ([1c4e02a](https://github.com/mdn/fred/commit/1c4e02a2ea20da72e8a43b9362c8a285f060af5c))
35
+
3
36
  ## [1.1.1](https://github.com/mdn/fred/compare/v1.1.0...v1.1.1) (2025-08-28)
4
37
 
5
38
 
package/README.md CHANGED
@@ -26,6 +26,10 @@ MDN's next fr(ont)e(n)d.
26
26
 
27
27
  ## Development principles
28
28
 
29
+ ### Environment variables
30
+
31
+ See [the environment variables README](./components/env/README.md).
32
+
29
33
  ### Inline JS
30
34
 
31
35
  We need to run some JS as soon as possible at page load, to avoid layout shifts and flashes.
package/build/env.js CHANGED
@@ -1,3 +1,12 @@
1
1
  import path from "node:path";
2
- export const BUILD_OUT_ROOT =
3
- process.env.BUILD_OUT_ROOT || path.join(import.meta.dirname, "..", "out");
2
+
3
+ const defaultOut = path.join(import.meta.dirname, "..", "out");
4
+ const nodeModule = defaultOut.endsWith(
5
+ path.join("node_modules", "@mdn", "fred", "out"),
6
+ );
7
+
8
+ export const RARI_BUILD_ROOT = process.env.BUILD_OUT_ROOT || defaultOut;
9
+
10
+ // When running from an npm package, this needs to be the default output directory,
11
+ // so we can load the pre-built assets
12
+ export const FRED_BUILD_ROOT = nodeModule ? defaultOut : RARI_BUILD_ROOT;
package/build/render.js CHANGED
@@ -2,27 +2,23 @@ import { readFile } from "node:fs/promises";
2
2
 
3
3
  import path from "node:path";
4
4
 
5
- // TODO: this should respect process.env.BUILD_OUT_ROOT at runtime
6
- // but when we package it into an npm package, it needs to be a relative path
7
- // based on the value of BUILD_OUT_ROOT at that point in time
8
- // https://github.com/mdn/fred/issues/594
9
- const BUILD_OUT_ROOT = path.resolve(import.meta.dirname, "..", "out");
5
+ import { FRED_BUILD_ROOT } from "./env.js";
10
6
 
11
7
  const { render: distRender } = /** @type {import("../entry.ssr.js")} */ (
12
- await import(path.resolve(BUILD_OUT_ROOT, "static", "ssr", "index.js"))
8
+ await import(path.resolve(FRED_BUILD_ROOT, "static", "ssr", "index.js"))
13
9
  );
14
10
 
15
11
  /** @type {import("@rspack/core").StatsCompilation} */
16
12
  const clientManifest = JSON.parse(
17
13
  await readFile(
18
- path.join(BUILD_OUT_ROOT, "static", "client", "stats.json"),
14
+ path.join(FRED_BUILD_ROOT, "static", "client", "stats.json"),
19
15
  "utf8",
20
16
  ),
21
17
  );
22
18
  /** @type {import("@rspack/core").StatsCompilation} */
23
19
  const legacyManifest = JSON.parse(
24
20
  await readFile(
25
- path.join(BUILD_OUT_ROOT, "static", "legacy", "stats.json"),
21
+ path.join(FRED_BUILD_ROOT, "static", "legacy", "stats.json"),
26
22
  "utf8",
27
23
  ),
28
24
  );
package/build/ssr.js CHANGED
@@ -1,8 +1,9 @@
1
+ #!/usr/bin/env node
1
2
  import { readFile, writeFile } from "node:fs/promises";
2
3
 
3
4
  import { fdir } from "fdir";
4
5
 
5
- import { BUILD_OUT_ROOT } from "./env.js";
6
+ import { RARI_BUILD_ROOT } from "./env.js";
6
7
  import { render } from "./render.js";
7
8
 
8
9
  /**
@@ -59,7 +60,7 @@ async function findDocuments() {
59
60
  .withFullPaths()
60
61
  .withErrors()
61
62
  .filter((filePath) => filePath.endsWith("/index.json"))
62
- .crawl(BUILD_OUT_ROOT);
63
+ .crawl(RARI_BUILD_ROOT);
63
64
  const docs = await api.withPromise();
64
65
  return docs;
65
66
  }
@@ -0,0 +1,28 @@
1
+ # Environment Variables
2
+
3
+ If a component or other part of Fred requires a variable set from the environment, you should define it in the [`./index.js`](./index.js) file, with a safe default value.
4
+
5
+ ## Defaults
6
+
7
+ We set safe defaults for prod, unless the risk from doing - and having this set everywhere, across local dev etc. - outweighs the risk of it not being set on prod.
8
+
9
+ E.g. we don't set `GLEAN_ENABLED` to the prod default, as we don't want to send telemetry pings for prod from other environments, and we'll notice in our telemetry if it's not set in prod.
10
+
11
+ ## Naming
12
+
13
+ Within Fred, variables are unprefixed, however the environment variable name is prefixed with `FRED_` to avoid conflicts with other environment variables. For example, if you define a variable `MY_VAR` in Fred, the environment variable to set would be `FRED_MY_VAR`.
14
+
15
+ ## Secrets
16
+
17
+ Rspack will bundle **all** environment variables prefixed with `FRED_` into the bundle, which is exposed client side.
18
+
19
+ > [!WARNING]
20
+ > **Never set secrets** through `FRED_` environment variables.
21
+ >
22
+ > As secrets can only be used in server-side components, you should simply set them through a non-`FRED_`-prefixed environment variable, and access them using the `process.env` object.
23
+
24
+ ## Build-time vs runtime
25
+
26
+ By default, variables are baked into our bundle at build time. However, you can define variables as runtime environment variables, which can be changed when running a version of Fred built with `FRED_RUNTIME_ENV=true`.
27
+
28
+ This is used in our npm package, so we can e.g. set `FRED_WRITER_MODE=true` in the `content` repo, without having to bake that into the npm package for all consumers.
@@ -1,15 +1,16 @@
1
- /**
2
- * @file Retrieves environment variables, setting defaults, for other areas of the app.
3
- *
4
- * We set safe defaults for prod, unless the risk from doing - and having this set
5
- * everywhere, across local dev etc. - outweighs the risk of it not being set on prod.
6
- */
1
+ import { parseBool, parseInt, parseString } from "./utils.js";
7
2
 
8
3
  export const PLAYGROUND_BASE_HOST = parseString(
9
4
  "PLAYGROUND_BASE_HOST",
10
5
  "mdnplay.dev",
11
6
  );
12
- export const PLAYGROUND_LOCAL = parseBool("PLAYGROUND_LOCAL", false);
7
+ export const PLAYGROUND_LOCAL = parseBool("PLAYGROUND_LOCAL", false, {
8
+ runtime: true,
9
+ });
10
+ export const PORT = parseInt("PORT", 3000, { runtime: true });
11
+ export const PLAYGROUND_PORT = parseInt("PLAYGROUND_PORT", 3001, {
12
+ runtime: true,
13
+ });
13
14
 
14
15
  export const FXA_SIGNIN_URL = parseString(
15
16
  "FXA_SIGNIN_URL",
@@ -33,7 +34,7 @@ export const GLEAN_DEBUG = parseBool("GLEAN_DEBUG", false);
33
34
  */
34
35
  export const ROBOTS_GLOBAL_ALLOW = parseBool("ROBOTS_GLOBAL_ALLOW", true);
35
36
 
36
- export const WRITER_MODE = parseBool("WRITER_MODE", false);
37
+ export const WRITER_MODE = parseBool("WRITER_MODE", false, { runtime: true });
37
38
 
38
39
  export const BCD_BASE_URL = parseString(
39
40
  "BCD_BASE_URL",
@@ -44,25 +45,3 @@ export const OBSERVATORY_API_URL = parseString(
44
45
  "OBSERVATORY_API_URL",
45
46
  "https://observatory-api.mdn.mozilla.net",
46
47
  );
47
-
48
- /**
49
- * @param {string} name
50
- * @param {boolean} fallback
51
- */
52
- function parseBool(name, fallback) {
53
- try {
54
- return Boolean(
55
- JSON.parse(process.env[`FRED_${name}`] || JSON.stringify(fallback)),
56
- );
57
- } catch {
58
- return fallback;
59
- }
60
- }
61
-
62
- /**
63
- * @param {string} name
64
- * @param {string} fallback
65
- */
66
- function parseString(name, fallback) {
67
- return process.env[`FRED_${name}`] || fallback;
68
- }
@@ -0,0 +1,6 @@
1
+ import { parseBool } from "./utils.js";
2
+
3
+ /** @type {string[]} */
4
+ export const runtimeVariables = [];
5
+ /** Overriden to prod default (false) in rspack config, set to true so it works in dev server by default. */
6
+ export const RUNTIME_ENV = parseBool("RUNTIME_ENV", true);
@@ -0,0 +1,5 @@
1
+ declare global {
2
+ var __MDNEnv: Record<string, string> | undefined;
3
+ }
4
+
5
+ export {};
@@ -0,0 +1,56 @@
1
+ import { RUNTIME_ENV, runtimeVariables } from "./runtime.js";
2
+
3
+ /**
4
+ * @typedef {object} Options
5
+ * @property {boolean} [runtime] Allow setting this value at runtime
6
+ */
7
+
8
+ /**
9
+ * @param {string} name
10
+ * @param {boolean} fallback
11
+ * @param {Options} [options]
12
+ */
13
+ export function parseBool(name, fallback, options) {
14
+ try {
15
+ return Boolean(
16
+ JSON.parse(getEnv(name, options) || JSON.stringify(fallback)),
17
+ );
18
+ } catch {
19
+ return fallback;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * @param {string} name
25
+ * @param {number} fallback
26
+ * @param {Options} [options]
27
+ */
28
+ export function parseInt(name, fallback, options) {
29
+ const stringValue = getEnv(name, options);
30
+ const numberValue = stringValue ? Number.parseInt(stringValue, 10) : fallback;
31
+ return Number.isNaN(numberValue) ? fallback : numberValue;
32
+ }
33
+
34
+ /**
35
+ * @param {string} name
36
+ * @param {string} fallback
37
+ * @param {Options} [options]
38
+ */
39
+ export function parseString(name, fallback, options) {
40
+ return getEnv(name, options) || fallback;
41
+ }
42
+
43
+ /**
44
+ * @param {string} name
45
+ * @param {Options} [options]
46
+ * @returns {string | undefined}
47
+ */
48
+ function getEnv(name, options = {}) {
49
+ const { runtime } = { runtime: false, ...options };
50
+ const fullName = `FRED_${name}`;
51
+ if (runtime && RUNTIME_ENV) {
52
+ runtimeVariables.push(fullName);
53
+ return process.env[fullName] || getEnv(name);
54
+ }
55
+ return globalThis.__MDNEnv?.[fullName];
56
+ }
@@ -5,6 +5,7 @@ import { unsafeHTML } from "lit/directives/unsafe-html.js";
5
5
 
6
6
  import inlineScript from "../../entry.inline.js?source&csp=true";
7
7
  import { ROBOTS_GLOBAL_ALLOW, WRITER_MODE } from "../env/index.js";
8
+ import { RUNTIME_ENV, runtimeVariables } from "../env/runtime.js";
8
9
  import Favicon from "../favicon/pure.js";
9
10
  import { asyncLocalStorage } from "../server/async-local-storage.js";
10
11
  import { ServerComponent } from "../server/index.js";
@@ -68,6 +69,12 @@ export class OuterLayout extends ServerComponent {
68
69
  ? "learn"
69
70
  : undefined;
70
71
 
72
+ const env = Object.fromEntries(
73
+ Object.entries(process.env).filter(([key]) =>
74
+ runtimeVariables.includes(key),
75
+ ),
76
+ );
77
+
71
78
  // if you want to put some script inline, put it in entry.inline.js
72
79
  // and you'll get CSP generation: see the README
73
80
  return html`
@@ -86,6 +93,11 @@ export class OuterLayout extends ServerComponent {
86
93
  content="width=device-width, initial-scale=1.0"
87
94
  />
88
95
  <title>${context.pageTitle || "MDN"}</title>
96
+ ${RUNTIME_ENV
97
+ ? unsafeHTML(`<script>process = {
98
+ env: ${JSON.stringify(env)}
99
+ };</script>`)
100
+ : nothing}
89
101
  ${unsafeHTML(`<script>${inlineScript}</script>`)}
90
102
  ${styles.map(
91
103
  (path) =>
@@ -5,7 +5,12 @@ import { keyed } from "lit/directives/keyed.js";
5
5
  import { createRef, ref } from "lit/directives/ref.js";
6
6
 
7
7
  import { ThemeController } from "../color-theme/controller.js";
8
- import { PLAYGROUND_BASE_HOST, PLAYGROUND_LOCAL } from "../env/index.js";
8
+ import {
9
+ PLAYGROUND_BASE_HOST,
10
+ PLAYGROUND_LOCAL,
11
+ PLAYGROUND_PORT,
12
+ PORT,
13
+ } from "../env/index.js";
9
14
  import { compressAndBase64Encode } from "../playground/utils.js";
10
15
 
11
16
  import styles from "./element.css?lit";
@@ -101,7 +106,7 @@ export class MDNPlayRunner extends LitElement {
101
106
  const url = new URL(
102
107
  `${prefix}/runner.html`,
103
108
  PLAYGROUND_LOCAL
104
- ? location.origin.replace("3000", "3001")
109
+ ? location.origin.replace(PORT.toString(), PLAYGROUND_PORT.toString())
105
110
  : `${location.protocol}//${this._subdomain}.${PLAYGROUND_BASE_HOST}`,
106
111
  );
107
112
  // pass the uuid for postMessage isolation