proteum 1.0.2 → 2.0.0-1

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 (185) hide show
  1. package/AGENTS.md +101 -0
  2. package/agents/codex/AGENTS.md +95 -0
  3. package/agents/codex/CODING_STYLE.md +71 -0
  4. package/agents/codex/agents.md.zip +0 -0
  5. package/agents/codex/client/AGENTS.md +102 -0
  6. package/agents/codex/client/pages/AGENTS.md +35 -0
  7. package/agents/codex/server/routes/AGENTS.md +12 -0
  8. package/agents/codex/server/services/AGENTS.md +137 -0
  9. package/agents/codex/tests/AGENTS.md +8 -0
  10. package/cli/app/config.ts +13 -11
  11. package/cli/app/index.ts +74 -82
  12. package/cli/bin.js +1 -1
  13. package/cli/commands/build.ts +51 -14
  14. package/cli/commands/check.ts +19 -0
  15. package/cli/commands/deploy/app.ts +4 -8
  16. package/cli/commands/deploy/web.ts +16 -20
  17. package/cli/commands/dev.ts +189 -64
  18. package/cli/commands/devEvents.ts +106 -0
  19. package/cli/commands/init.ts +63 -57
  20. package/cli/commands/lint.ts +21 -0
  21. package/cli/commands/refresh.ts +18 -0
  22. package/cli/commands/typecheck.ts +18 -0
  23. package/cli/compiler/client/identite.ts +80 -53
  24. package/cli/compiler/client/index.ts +139 -213
  25. package/cli/compiler/common/bundleAnalysis.ts +94 -0
  26. package/cli/compiler/common/clientManifest.ts +67 -0
  27. package/cli/compiler/common/controllers.ts +288 -0
  28. package/cli/compiler/common/files/autres.ts +7 -18
  29. package/cli/compiler/common/files/images.ts +40 -37
  30. package/cli/compiler/common/files/style.ts +11 -22
  31. package/cli/compiler/common/generatedRouteModules.ts +368 -0
  32. package/cli/compiler/common/index.ts +31 -65
  33. package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
  34. package/cli/compiler/common/rspackAliases.ts +13 -0
  35. package/cli/compiler/common/scripts.ts +37 -0
  36. package/cli/compiler/index.ts +781 -230
  37. package/cli/compiler/server/index.ts +59 -75
  38. package/cli/compiler/writeIfChanged.ts +21 -0
  39. package/cli/index.ts +71 -72
  40. package/cli/paths.ts +51 -57
  41. package/cli/print.ts +17 -11
  42. package/cli/tsconfig.json +5 -4
  43. package/cli/utils/agents.ts +100 -0
  44. package/cli/utils/check.ts +71 -0
  45. package/cli/utils/index.ts +1 -3
  46. package/cli/utils/keyboard.ts +8 -25
  47. package/cli/utils/runProcess.ts +30 -0
  48. package/client/app/component.tsx +29 -29
  49. package/client/app/index.ts +36 -57
  50. package/client/app/service.ts +7 -12
  51. package/client/app.tsconfig.json +2 -2
  52. package/client/components/Dialog/Manager.ssr.tsx +40 -0
  53. package/client/components/Dialog/Manager.tsx +119 -150
  54. package/client/components/Dialog/status.tsx +3 -3
  55. package/client/components/index.ts +1 -1
  56. package/client/components/types.d.ts +1 -3
  57. package/client/dev/hmr.ts +65 -0
  58. package/client/global.d.ts +2 -2
  59. package/client/hooks.ts +6 -9
  60. package/client/index.ts +2 -1
  61. package/client/islands/index.ts +7 -0
  62. package/client/islands/useDeferredModule.ts +199 -0
  63. package/client/pages/_layout/index.tsx +4 -12
  64. package/client/pages/useHeader.tsx +14 -21
  65. package/client/router.ts +27 -0
  66. package/client/services/router/components/Link.tsx +34 -27
  67. package/client/services/router/components/Page.tsx +6 -14
  68. package/client/services/router/components/router.ssr.tsx +36 -0
  69. package/client/services/router/components/router.tsx +63 -83
  70. package/client/services/router/index.tsx +185 -220
  71. package/client/services/router/request/api.ts +97 -119
  72. package/client/services/router/request/history.ts +2 -2
  73. package/client/services/router/request/index.ts +13 -12
  74. package/client/services/router/request/multipart.ts +72 -62
  75. package/client/services/router/response/index.tsx +68 -61
  76. package/client/services/router/response/page.ts +28 -32
  77. package/client/utils/dom.ts +17 -33
  78. package/common/app/index.ts +3 -3
  79. package/common/data/chaines/index.ts +22 -23
  80. package/common/data/dates.ts +35 -70
  81. package/common/data/markdown.ts +42 -39
  82. package/common/dev/serverHotReload.ts +26 -0
  83. package/common/errors/index.tsx +110 -142
  84. package/common/router/contracts.ts +29 -0
  85. package/common/router/index.ts +89 -108
  86. package/common/router/layouts.ts +34 -47
  87. package/common/router/pageSetup.ts +50 -0
  88. package/common/router/register.ts +53 -24
  89. package/common/router/request/api.ts +30 -36
  90. package/common/router/request/index.ts +2 -8
  91. package/common/router/response/index.ts +8 -15
  92. package/common/router/response/page.ts +70 -58
  93. package/common/utils.ts +1 -1
  94. package/doc/TODO.md +1 -1
  95. package/eslint.js +62 -0
  96. package/package.json +14 -49
  97. package/prettier.config.cjs +9 -0
  98. package/scripts/cleanup-generated-controllers.ts +62 -0
  99. package/scripts/fix-reference-app-typing.ts +490 -0
  100. package/scripts/refactor-client-app-imports.ts +244 -0
  101. package/scripts/refactor-client-pages.ts +587 -0
  102. package/scripts/refactor-server-controllers.ts +470 -0
  103. package/scripts/refactor-server-runtime-aliases.ts +360 -0
  104. package/scripts/restore-client-app-import-files.ts +41 -0
  105. package/scripts/restore-files-from-git-head.ts +20 -0
  106. package/scripts/update-codex-agents.ts +35 -0
  107. package/server/app/commands.ts +35 -64
  108. package/server/app/container/config.ts +48 -59
  109. package/server/app/container/console/index.ts +202 -248
  110. package/server/app/container/index.ts +33 -71
  111. package/server/app/controller/index.ts +61 -0
  112. package/server/app/index.ts +39 -105
  113. package/server/app/service/container.ts +41 -42
  114. package/server/app/service/index.ts +120 -147
  115. package/server/context.ts +1 -1
  116. package/server/index.ts +25 -1
  117. package/server/services/auth/index.ts +75 -115
  118. package/server/services/auth/router/index.ts +31 -32
  119. package/server/services/auth/router/request.ts +14 -16
  120. package/server/services/cron/CronTask.ts +13 -26
  121. package/server/services/cron/index.ts +14 -36
  122. package/server/services/disks/driver.ts +40 -58
  123. package/server/services/disks/drivers/local/index.ts +79 -90
  124. package/server/services/disks/drivers/s3/index.ts +116 -163
  125. package/server/services/disks/index.ts +23 -38
  126. package/server/services/email/index.ts +45 -104
  127. package/server/services/email/utils.ts +14 -27
  128. package/server/services/fetch/index.ts +53 -85
  129. package/server/services/prisma/Facet.ts +39 -91
  130. package/server/services/prisma/index.ts +74 -110
  131. package/server/services/router/generatedRuntime.ts +29 -0
  132. package/server/services/router/http/index.ts +78 -73
  133. package/server/services/router/http/multipart.ts +19 -42
  134. package/server/services/router/index.ts +378 -365
  135. package/server/services/router/request/api.ts +26 -25
  136. package/server/services/router/request/index.ts +44 -51
  137. package/server/services/router/request/service.ts +7 -11
  138. package/server/services/router/request/validation/zod.ts +111 -148
  139. package/server/services/router/response/index.ts +110 -125
  140. package/server/services/router/response/mask/Filter.ts +31 -72
  141. package/server/services/router/response/mask/index.ts +8 -15
  142. package/server/services/router/response/mask/selecteurs.ts +11 -25
  143. package/server/services/router/response/page/clientManifest.ts +25 -0
  144. package/server/services/router/response/page/document.tsx +199 -127
  145. package/server/services/router/response/page/index.tsx +89 -94
  146. package/server/services/router/service.ts +13 -15
  147. package/server/services/schema/index.ts +17 -26
  148. package/server/services/schema/request.ts +19 -33
  149. package/server/services/schema/router/index.ts +8 -11
  150. package/server/services/security/encrypt/aes/index.ts +15 -35
  151. package/server/utils/slug.ts +29 -35
  152. package/skills/clean-project-code/SKILL.md +63 -0
  153. package/skills/clean-project-code/agents/openai.yaml +4 -0
  154. package/tsconfig.common.json +4 -3
  155. package/tsconfig.json +4 -1
  156. package/types/aliases.d.ts +17 -21
  157. package/types/controller-input.test.ts +48 -0
  158. package/types/express-extra.d.ts +6 -0
  159. package/types/global/constants.d.ts +13 -0
  160. package/types/global/express-extra.d.ts +6 -0
  161. package/types/global/modules.d.ts +13 -16
  162. package/types/global/utils.d.ts +17 -49
  163. package/types/global/vendors.d.ts +62 -0
  164. package/types/icons.d.ts +65 -1
  165. package/types/uuid.d.ts +3 -0
  166. package/types/vendors.d.ts +62 -0
  167. package/cli/compiler/common/babel/index.ts +0 -170
  168. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  169. package/cli/compiler/common/babel/plugins/services.ts +0 -586
  170. package/cli/compiler/common/babel/routes/imports.ts +0 -127
  171. package/cli/compiler/common/babel/routes/routes.ts +0 -1130
  172. package/client/services/captcha/index.ts +0 -67
  173. package/client/services/socket/index.ts +0 -147
  174. package/common/data/rte/nodes.ts +0 -83
  175. package/common/data/stats.ts +0 -90
  176. package/common/utils/rte.ts +0 -183
  177. package/server/services/auth/old.ts +0 -277
  178. package/server/services/cache/commands.ts +0 -41
  179. package/server/services/cache/index.ts +0 -297
  180. package/server/services/cache/service.json +0 -6
  181. package/server/services/socket/index.ts +0 -162
  182. package/server/services/socket/scope.ts +0 -226
  183. package/server/services/socket/service.json +0 -6
  184. package/server/services_old/SocketClient.ts +0 -92
  185. package/server/services_old/Token.old.ts +0 -97
@@ -3,7 +3,7 @@
3
3
  ----------------------------------*/
4
4
 
5
5
  // Libs
6
- import compilerSelecteurs, { TObjetSelecteurs } from './selecteurs';
6
+ import compilerSelecteurs, { TObjetSelecteurs, TSelecteur } from './selecteurs';
7
7
  import Filter from './Filter';
8
8
 
9
9
  // Filtres spécifiques métier
@@ -24,24 +24,18 @@ const debug = false;
24
24
  ----------------------------------*/
25
25
 
26
26
  // proprieteModele = Si l'objet actuellement traité fait partie des valeurs d'un modèle
27
- export default (
28
- donnee: any,
29
- selecteurs?: string | TObjetSelecteurs
30
- ) => {
31
-
27
+ export default (donnee: any, selecteurs?: string | TObjetSelecteurs) => {
32
28
  // Pas besoin de filtrer
33
- if (donnee === null || typeof donnee !== 'object'/* || donnee._filtered === true */) {
29
+ if (donnee === null || typeof donnee !== 'object' /* || donnee._filtered === true */) {
34
30
  return donnee;
35
31
  }
36
32
 
37
33
  // Correction sélecteurs
38
- let selecteursCompiles: TObjetSelecteurs | undefined;
39
- if (selecteurs === undefined)
40
- selecteursCompiles = undefined;
34
+ let selecteursCompiles: TSelecteur | undefined;
35
+ if (selecteurs === undefined) selecteursCompiles = undefined;
41
36
  else if (typeof selecteurs === 'string')
42
- selecteursCompiles = compilerSelecteurs(selecteurs);
43
- else // Déjà un objet, pas besoin de compiler
44
- selecteursCompiles = selecteurs;
37
+ selecteursCompiles = compilerSelecteurs(selecteurs); // Déjà un objet, pas besoin de compiler
38
+ else selecteursCompiles = selecteurs;
45
39
 
46
40
  debug && console.log('Avant filtrage', donnee);
47
41
 
@@ -56,5 +50,4 @@ export default (
56
50
  debug && console.log('Apres filtrage', retour);
57
51
 
58
52
  return retour;
59
-
60
- }
53
+ };
@@ -5,10 +5,10 @@
5
5
  /*----------------------------------
6
6
  - TYPES
7
7
  ----------------------------------*/
8
- export type TSelecteur = true | "*" | TObjetSelecteurs
8
+ export type TSelecteur = true | '*' | TObjetSelecteurs;
9
9
  // Wildcard en clé = selectionner toutes les clés
10
10
  // Wildcard en valeur = sélectionner absolument toutes les valeur descendantes
11
- export type TObjetSelecteurs = {[cle: string]: TSelecteur}
11
+ export type TObjetSelecteurs = { [cle: string]: TSelecteur };
12
12
 
13
13
  /*----------------------------------
14
14
  - CONSTANTES
@@ -21,66 +21,53 @@ const cache: TObjetSelecteurs = {};
21
21
  - FONCTION
22
22
  ----------------------------------*/
23
23
  export default (selecteurs: string) => {
24
-
25
- if (cache[selecteurs] === undefined)
26
- cache[selecteurs] = compiler(selecteurs);
24
+ if (cache[selecteurs] === undefined) cache[selecteurs] = compiler(selecteurs);
27
25
 
28
26
  return cache[selecteurs];
29
-
30
- }
27
+ };
31
28
 
32
29
  const compiler = (selecteurs: string): TObjetSelecteurs => {
33
-
34
30
  let chemins: TObjetSelecteurs = {};
35
31
  let cheminA: string[] = []; // Chemin en construction
36
32
 
37
33
  let branche;
38
- while (branche = reSelecteurs.exec(selecteurs)) {
39
-
40
- if (branche[0] === ')') { // fermeture
34
+ while ((branche = reSelecteurs.exec(selecteurs))) {
35
+ if (branche[0] === ')') {
36
+ // fermeture
41
37
 
42
38
  // Niveau précédent: docs.titre => docs
43
39
  cheminA.pop();
44
-
45
40
  } else {
46
-
47
41
  const nomBranche = branche[2];
48
42
  const ouverture = branche[5] === '(';
49
43
 
50
44
  // Ligne débutant par un # = commentaire
51
- if (nomBranche.startsWith("#"))
52
- continue;
45
+ if (nomBranche.startsWith('#')) continue;
53
46
 
54
47
  if (ouverture)
55
48
  // Ouverture de la branche: docs => docs.titre
56
49
  cheminA.push(nomBranche);
57
50
  else {
58
-
59
51
  const chemin = [...cheminA, nomBranche];
60
52
 
61
53
  // Construction du chemin
62
54
  let brancheA = chemins;
63
55
  const nbBranches = chemin.length;
64
56
  for (let iBranche = 0; iBranche < nbBranches; iBranche++) {
65
-
66
57
  const nomBranche = chemin[iBranche];
67
58
 
68
- const extremite = iBranche === nbBranches - 1
59
+ const extremite = iBranche === nbBranches - 1;
69
60
  if (extremite) {
70
-
71
61
  // Dernière branche = extremité = true
72
62
  brancheA[nomBranche] = true;
73
-
74
63
  } else {
75
-
76
64
  // Pas encore définie
77
65
  if (brancheA[nomBranche] === undefined)
78
66
  // Sinon, initialisation
79
67
  brancheA[nomBranche] = {};
80
68
 
81
69
  // Rférnce pour la prochaine itération
82
- brancheA = brancheA[nomBranche];
83
-
70
+ brancheA = brancheA[nomBranche] as TObjetSelecteurs;
84
71
  }
85
72
  }
86
73
  }
@@ -88,5 +75,4 @@ const compiler = (selecteurs: string): TObjetSelecteurs => {
88
75
  }
89
76
 
90
77
  return chemins;
91
-
92
- }
78
+ };
@@ -0,0 +1,25 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ type TClientManifestAssets = { assets?: string[]; css?: string[]; js?: string[] };
5
+
6
+ export type TClientBuildManifest = {
7
+ publicPath?: string;
8
+ entries?: Record<string, TClientManifestAssets>;
9
+ chunks?: Record<string, TClientManifestAssets>;
10
+ };
11
+
12
+ const manifestPath = path.join(__dirname, 'client-manifest.json');
13
+ let cachedManifest: TClientBuildManifest | undefined;
14
+
15
+ export const getClientBuildManifest = (): TClientBuildManifest => {
16
+ if (!__DEV__) {
17
+ if (!cachedManifest) {
18
+ cachedManifest = fs.existsSync(manifestPath) ? fs.readJSONSync(manifestPath) : {};
19
+ }
20
+
21
+ return cachedManifest ?? {};
22
+ }
23
+
24
+ return fs.existsSync(manifestPath) ? fs.readJSONSync(manifestPath) : {};
25
+ };
@@ -4,157 +4,229 @@
4
4
 
5
5
  // Npm
6
6
  import React from 'react';
7
- import renderToString from "preact-render-to-string";
7
+ import renderToString from 'preact-render-to-string';
8
8
  const safeStringify = require('fast-safe-stringify'); // remplace les références circulairs par un [Circular]
9
9
 
10
10
  // Core
11
- import type { default as Router, Response as ServerResponse } from "@server/services/router";
11
+ import type { TServerRouter, Response as ServerResponse } from '@server/services/router';
12
12
  import type Page from '.';
13
+ import { getClientBuildManifest } from './clientManifest';
13
14
 
14
15
  /*----------------------------------
15
16
  - TYPES
16
17
  ----------------------------------*/
17
18
 
18
-
19
19
  /*----------------------------------
20
20
  - SERVICE
21
21
  ----------------------------------*/
22
- export default class DocumentRenderer<TRouter extends Router> {
23
-
22
+ export default class DocumentRenderer<TRouter extends TServerRouter> {
24
23
  public constructor(
25
24
  public router: TRouter,
26
- public app = router.app
27
- ) {
25
+ public app = router.app,
26
+ ) {}
28
27
 
28
+ public staticDocument() {
29
+ const routesForClient = JSON.stringify(this.router.ssrRoutes);
30
+ return (
31
+ '<!doctype html>' +
32
+ renderToString(
33
+ <html lang="en">
34
+ <head>
35
+ {/* Format */}
36
+ <meta charSet="utf-8" />
37
+ <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
38
+
39
+ {/* CSS */}
40
+ {this.clientStyles()}
41
+ <link rel="preload" as="font" href={'/public/icons.woff2?v=' + BUILD_ID} type="font/woff2" />
42
+ <link rel="stylesheet" type="text/css" href="/public/icons.css" />
43
+
44
+ {/* JS */}
45
+ <script
46
+ type="text/javascript"
47
+ dangerouslySetInnerHTML={{
48
+ __html:
49
+ `window.routes=${routesForClient};` +
50
+ (this.app.env.profile === 'dev' ? 'window.dev = true;' : ''),
51
+ }}
52
+ />
53
+ {this.clientScripts()}
54
+ </head>
55
+ <body></body>
56
+ </html>,
57
+ )
58
+ );
29
59
  }
30
60
 
31
- public staticDocument() {
32
- const routesForClient = JSON.stringify( this.router.ssrRoutes );
33
- return '<!doctype html>' + renderToString(
34
- <html lang="en">
35
- <head>
36
- {/* Format */}
37
- <meta charSet="utf-8" />
38
- <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
39
-
40
- {/* CSS */}
41
- <link rel="preload" href="/public/client.css" as="style" />
42
- <link rel="preload" as="font" href={"/public/icons.woff2?v=" + BUILD_ID} type="font/woff2" />
43
- <link rel="stylesheet" type="text/css" href="/public/icons.css" />
44
- <link rel="stylesheet" type="text/css" href="/public/client.css" />
45
-
46
- {/* JS */}
47
- <script type="text/javascript" dangerouslySetInnerHTML={{
48
- __html: `window.routes=${routesForClient};` + (this.app.env.profile === 'dev' ? 'window.dev = true;' : '')
49
- }} />
50
- <link rel="preload" href="/public/client.js" as="script" />
51
- <script defer type="text/javascript" src="/public/client.js" />
52
-
53
- </head>
54
- <body></body>
55
- </html>
61
+ public async page(html: string, page: Page<TRouter>, response: ServerResponse<TRouter>) {
62
+ let attrsBody = { className: [...page.bodyClass].join(' ') };
63
+
64
+ return (
65
+ '<!doctype html>' +
66
+ renderToString(
67
+ <html lang="en">
68
+ <head>
69
+ {/* Format */}
70
+ <meta charSet="utf-8" />
71
+ <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
72
+ <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
73
+
74
+ {/* Mobile */}
75
+ <meta name="application-name" content={this.app.identity.web.title} />
76
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
77
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
78
+ <meta content={this.app.identity.author.name} name="author" />
79
+ <meta name="theme-color" content={this.app.identity.maincolor} />
80
+ <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
81
+ <meta name="apple-mobile-web-app-capable" content="yes" />
82
+ <meta name="mobile-web-app-capable" content="yes" />
83
+ <meta
84
+ name="viewport"
85
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
86
+ />
87
+
88
+ {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
89
+ {/*<link rel="manifest" href={RES['manifest.json']} />*/}
90
+ <link rel="shortcut icon" href="/public/app/favicon.ico" />
91
+ <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
92
+ <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
93
+ <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
94
+ <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
95
+
96
+ {/* Page */}
97
+ <title>{page.title}</title>
98
+ <meta content={page.description} name="description" />
99
+ <link rel="canonical" href={String(response.canonicalUrl)} />
100
+
101
+ {/* SEO, social medias, OG tags, ... */}
102
+ {page.head.map(({ $, ...attrs }) => React.createElement($, attrs))}
103
+
104
+ {this.styles(page)}
105
+
106
+ {await this.scripts(response, page)}
107
+
108
+ {/* Rich Snippets: https://schema.org/docs/full.html + https://jsonld.com/ */}
109
+ <script
110
+ type="application/ld+json"
111
+ dangerouslySetInnerHTML={{
112
+ __html: JSON.stringify({ '@context': 'http://schema.org', '@graph': page.jsonld }),
113
+ }}
114
+ />
115
+ </head>
116
+ <body {...attrsBody} dangerouslySetInnerHTML={{ __html: html }}></body>
117
+ </html>,
118
+ )
56
119
  );
57
120
  }
58
121
 
59
- public async page( html: string, page: Page, response: ServerResponse<TRouter> ) {
60
-
61
- let attrsBody = {
62
- className: [...page.bodyClass].join(' '),
63
- };
64
-
65
- return '<!doctype html>' + renderToString(
66
- <html lang="en">
67
- <head>
68
- {/* Format */}
69
- <meta charSet="utf-8" />
70
- <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
71
- <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
72
-
73
- {/* Mobile */}
74
- <meta name="application-name" content={this.app.identity.web.title} />
75
- <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
76
- <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
77
- <meta content={this.app.identity.author.name} name="author" />
78
- <meta name="theme-color" content={this.app.identity.maincolor} />
79
- <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
80
- <meta name="apple-mobile-web-app-capable" content="yes" />
81
- <meta name="mobile-web-app-capable" content="yes" />
82
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
83
-
84
- {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
85
- {/*<link rel="manifest" href={RES['manifest.json']} />*/}
86
- <link rel="shortcut icon" href="/public/app/favicon.ico" />
87
- <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
88
- <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
89
- <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
90
- <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
91
-
92
- {/* Page */}
93
- <title>{page.title}</title>
94
- <meta content={page.description} name="description" />
95
- <link rel="canonical" href={response.canonicalUrl} />
96
-
97
- {/* SEO, social medias, OG tags, ... */}
98
- {page.head.map(({ $, ...attrs }) => (
99
- React.createElement($, attrs)
100
- ))}
101
-
102
- {this.styles( page )}
103
-
104
- {await this.scripts( response, page )}
105
-
106
- {/* Rich Snippets: https://schema.org/docs/full.html + https://jsonld.com/ */}
107
- <script type="application/ld+json" dangerouslySetInnerHTML={{
108
- __html: JSON.stringify({
109
- '@context': 'http://schema.org',
110
- '@graph': page.jsonld
111
- })
112
- }}/>
113
-
114
- </head>
115
- <body {...attrsBody} dangerouslySetInnerHTML={{ __html: html }}></body>
116
- </html>
117
- )
122
+ private styles(page: Page<TRouter>) {
123
+ return (
124
+ <>
125
+ {this.clientStyles()}
126
+
127
+ {page.style.map((style) =>
128
+ 'url' in style ? (
129
+ <>
130
+ <link rel="preload" href={style.url} as="style" />
131
+ <link rel="stylesheet" type="text/css" href={style.url} />
132
+ </>
133
+ ) : (
134
+ <>
135
+ <style id={style.id} dangerouslySetInnerHTML={{ __html: style.inline }} />
136
+ </>
137
+ ),
138
+ )}
139
+ </>
140
+ );
118
141
  }
119
142
 
120
- private styles( page: Page ) {
121
- return <>
122
- <link rel="preload" href="/public/client.css" as="style" />
123
- <link rel="stylesheet" type="text/css" href="/public/client.css" />
124
-
125
- {page.style.map( style => 'url' in style ? <>
126
- <link rel="preload" href={style.url} as="style" />
127
- <link rel="stylesheet" type="text/css" href={style.url} />
128
- </> : <>
129
- <style id={style.id} dangerouslySetInnerHTML={{ __html: style.inline }} />
130
- </>)}
131
- </>
143
+ private clientStyles() {
144
+ const styles = this.clientEntryAssets('css');
145
+
146
+ return (
147
+ <>
148
+ {styles.map((style) => {
149
+ const href = this.clientAssetUrl(style);
150
+
151
+ return (
152
+ <React.Fragment key={style}>
153
+ <link rel="preload" href={href} as="style" />
154
+ <link rel="stylesheet" type="text/css" href={href} />
155
+ </React.Fragment>
156
+ );
157
+ })}
158
+ </>
159
+ );
132
160
  }
133
161
 
134
- private async scripts( response: ServerResponse<TRouter>, page: Page ) {
162
+ private clientScripts() {
163
+ const scripts = this.clientEntryAssets('js');
164
+
165
+ return (
166
+ <>
167
+ {scripts.map((script) => {
168
+ const src = this.clientAssetUrl(script, true);
169
+
170
+ return (
171
+ <React.Fragment key={script}>
172
+ <link rel="preload" href={src} as="script" />
173
+ <script defer type="text/javascript" src={src} />
174
+ </React.Fragment>
175
+ );
176
+ })}
177
+ </>
178
+ );
179
+ }
135
180
 
181
+ private async scripts(response: ServerResponse<TRouter>, page: Page<TRouter>) {
136
182
  const ssrData = response.forSsr(page);
137
- const context = safeStringify( ssrData );
138
- const routesForClient = JSON.stringify( this.router.ssrRoutes );
139
-
140
- return <>
141
- {/* JS */}
142
- <script type="text/javascript" dangerouslySetInnerHTML={{
143
- __html: `window.ssr=${context}; window.routes=${routesForClient};` + (
144
- this.app.env.profile === 'dev' ? 'window.dev = true;' : ''
145
- )
146
- }} />
147
-
148
- <link rel="preload" href={"/public/client.js?v=" + BUILD_ID} as="script" />
149
- <script defer type="text/javascript" src={"/public/client.js?v=" + BUILD_ID} />
150
-
151
- {page.scripts.map( script => 'url' in script ? <>
152
- <link rel="preload" href={script.url} as="script" />
153
- <script type="text/javascript" src={script.url} {...script.attrs || {}} />
154
- </> : <>
155
- <script type="text/javascript" {...script.attrs || {}} id={script.id}
156
- dangerouslySetInnerHTML={{ __html: script.inline }} />
157
- </>)}
158
- </>
183
+ const context = safeStringify(ssrData);
184
+ const routesForClient = JSON.stringify(this.router.ssrRoutes);
185
+
186
+ return (
187
+ <>
188
+ {/* JS */}
189
+ <script
190
+ type="text/javascript"
191
+ dangerouslySetInnerHTML={{
192
+ __html:
193
+ `window.ssr=${context}; window.routes=${routesForClient};` +
194
+ (this.app.env.profile === 'dev' ? 'window.dev = true;' : ''),
195
+ }}
196
+ />
197
+
198
+ {this.clientScripts()}
199
+
200
+ {page.scripts.map((script) =>
201
+ 'url' in script ? (
202
+ <>
203
+ <link rel="preload" href={script.url} as="script" />
204
+ <script type="text/javascript" src={script.url} {...(script.attrs || {})} />
205
+ </>
206
+ ) : (
207
+ <>
208
+ <script
209
+ type="text/javascript"
210
+ {...(script.attrs || {})}
211
+ id={script.id}
212
+ dangerouslySetInnerHTML={{ __html: script.inline }}
213
+ />
214
+ </>
215
+ ),
216
+ )}
217
+ </>
218
+ );
219
+ }
220
+
221
+ private clientEntryAssets(kind: 'assets' | 'css' | 'js' = 'assets'): string[] {
222
+ const manifest = getClientBuildManifest();
223
+ const entry = manifest.entries?.client;
224
+ const assets = entry?.[kind];
225
+
226
+ return Array.isArray(assets) ? assets : [];
227
+ }
228
+
229
+ private clientAssetUrl(asset: string, withBuildId = false) {
230
+ return `/public/${asset}${withBuildId ? `?v=${BUILD_ID}` : ''}`;
159
231
  }
160
- }
232
+ }