5htp-core 0.4.9-6 → 0.4.9-7

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.4.9-6",
4
+ "version": "0.4.9-7",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -99,9 +99,10 @@
99
99
  "@types/universal-analytics": "^0.4.5",
100
100
  "@types/webpack-env": "^1.16.2",
101
101
  "@types/ws": "^7.4.7",
102
- "@types/yargs-parser": "^21.0.0"
102
+ "@types/yargs-parser": "^21.0.0",
103
+ "schema-dts": "^1.1.2"
103
104
  },
104
105
  "peerDependencies": {
105
- "5htp": "0.3.9"
106
+ "5htp": "0.4.5"
106
107
  }
107
108
  }
@@ -65,6 +65,7 @@ export default abstract class PageResponse<TRouter extends ClientOrServerRouter
65
65
  public description?: string;
66
66
  public bodyClass: Set<string> = new Set<string>();
67
67
  public bodyId?: string;
68
+ public url: string;
68
69
 
69
70
  // Resources
70
71
  public scripts: TPageResource[] = [];
@@ -82,6 +83,8 @@ export default abstract class PageResponse<TRouter extends ClientOrServerRouter
82
83
 
83
84
  this.chunkId = context.route.options["id"];
84
85
 
86
+ this.url = context.request.url;
87
+
85
88
  this.fetchers = this.createFetchers(route.options.data);
86
89
 
87
90
  }
@@ -48,6 +48,7 @@ type AppIdentityConfig = {
48
48
 
49
49
  },
50
50
 
51
+ locale: string
51
52
  language: string
52
53
  maincolor: string,
53
54
  iconsPack?: string,
@@ -72,22 +72,46 @@ export default class DocumentRenderer<TRouter extends Router> {
72
72
  <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
73
73
  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
74
74
 
75
- {/* Basique*/}
76
- <meta content={this.app.identity.web.title} name="apple-mobile-web-app-title" />
75
+ {/* Mobile */}
76
+ <meta name="application-name" content={this.app.identity.web.title} />
77
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
78
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
79
+ <meta content={this.app.identity.author.name} name="author" />
80
+ <meta name="theme-color" content={this.app.identity.maincolor} />
81
+ <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
82
+ <meta name="apple-mobile-web-app-capable" content="yes" />
83
+ <meta name="mobile-web-app-capable" content="yes" />
84
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
85
+
86
+ {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
87
+ {/*<link rel="manifest" href={RES['manifest.json']} />*/}
88
+ <link rel="shortcut icon" href="/public/app/favicon.ico" />
89
+ <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
90
+ <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
91
+ <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
92
+ <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
93
+
94
+ {/* Page */}
77
95
  <title>{page.title}</title>
78
96
  <meta content={page.description} name="description" />
79
97
  <link rel="canonical" href={canonicalUrl} />
80
98
 
81
- {this.metas( page )}
99
+ {/* SEO, social medias, OG tags, ... */}
100
+ {page.head.map(({ $, ...attrs }) => (
101
+ React.createElement($, attrs)
102
+ ))}
82
103
 
83
104
  {this.styles( page )}
84
105
 
85
106
  {await this.scripts( response, page )}
86
107
 
87
108
  {/* Rich Snippets: https://schema.org/docs/full.html + https://jsonld.com/ */}
88
- {/* <script type="application/ld+json" dangerouslySetInnerHTML={{
89
- __html: JSON.stringify( schemaGenerator(page, route) )
90
- }}/> */}
109
+ <script type="application/ld+json" dangerouslySetInnerHTML={{
110
+ __html: JSON.stringify({
111
+ '@context': 'http://schema.org',
112
+ '@graph': page.jsonld
113
+ })
114
+ }}/>
91
115
 
92
116
  </head>
93
117
  <body {...attrsBody} dangerouslySetInnerHTML={{ __html: html }}></body>
@@ -95,41 +119,6 @@ export default class DocumentRenderer<TRouter extends Router> {
95
119
  )
96
120
  }
97
121
 
98
- private metas( page: Page ) {
99
- return <>
100
- {/* Réseaux sociaux */}
101
- {/*page.metas.metasAdditionnelles && Object.entries(page.metas.metasAdditionnelles).map(
102
- ([ cle, val ]: [ string, string ]) => (
103
- <meta name={cle} content={val} />
104
- )
105
- )*/}
106
-
107
- {/* Mobile */}
108
- <meta name="theme-color" content={this.app.identity.maincolor} />
109
- <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
110
- <meta name="apple-mobile-web-app-capable" content="yes" />
111
- <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
112
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
113
-
114
- {/* Identité */}
115
- <meta name="mobile-web-app-capable" content="yes" />
116
- <meta name="application-name" content={this.app.identity.web.title} />
117
- <meta name="type" content="website" />
118
-
119
- {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
120
- {/*<link rel="manifest" href={RES['manifest.json']} />*/}
121
- <link rel="shortcut icon" href="/public/app/favicon.ico" />
122
- <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
123
- <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
124
- <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
125
- <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
126
-
127
- {page.metas?.map(({ $, ...attrs }) => (
128
- React.createElement($, attrs)
129
- ))}
130
- </>
131
- }
132
-
133
122
  private styles( page: Page ) {
134
123
  return <>
135
124
  <link rel="stylesheet" type="text/css" href={"/public/icons.css?" + BUILD_ID} />
@@ -4,8 +4,8 @@
4
4
 
5
5
  // Npm
6
6
  import React from 'react';
7
- import renderToString from "preact-render-to-string";
8
- const safeStringify = require('fast-safe-stringify'); // remplace les références circulairs par un [Circular]
7
+ import renderToString from "preact-render-to-string";
8
+ import type { Thing } from 'schema-dts';
9
9
 
10
10
  // Core
11
11
  import { default as Router, TRouterContext } from "@server/services/router";
@@ -35,7 +35,9 @@ type TMetasList = ({ $: string } & { [key: string]: string })[]
35
35
 
36
36
  export default class Page<TRouter extends Router = Router> extends PageResponse<TRouter> {
37
37
 
38
- public metas: TMetasList = [];
38
+ public head: TMetasList = [];
39
+ public metas: {[name: string]: string} = {};
40
+ public jsonld: Thing[] = [];
39
41
 
40
42
  public constructor(
41
43
  public route: TRoute | TErrorRoute,
@@ -75,6 +77,10 @@ export default class Page<TRouter extends Router = Router> extends PageResponse<
75
77
  if (html === undefined)
76
78
  throw new Error(`Page HTML is empty (undefined)`);
77
79
 
80
+ // Metas
81
+ this.buildMetas();
82
+ this.buildJsonLd();
83
+
78
84
  // Un chunk peut regrouper plusieurs fihciers css / js
79
85
  // L'id du chunk est injecté depuis le plugin babel
80
86
  this.addChunks();
@@ -119,52 +125,72 @@ export default class Page<TRouter extends Router = Router> extends PageResponse<
119
125
  }
120
126
  }
121
127
 
122
- private getSocialMetas() {
123
- /*if (page.metas.imageUrl)
124
- page.metas.imageUrl = app.web.url + page.metas.imageUrl;
125
-
126
- if (!page.metas.metasAdditionnelles)
127
- page.metas.metasAdditionnelles = {};
128
-
129
- page.metas.metasAdditionnelles = {
130
- 'og:locale': 'fr_FR',
131
- 'og:site_name': app.identity.web.title,
132
- 'og:title': page.title,
133
- 'og:description': page.description,
134
- 'og:url': fullUrl,
135
-
136
- ...(page.metas.imageUrl ? {
137
- 'og:image': page.metas.imageUrl,
138
- ...(page.metas.imageX ? {
139
- 'og:image:width': page.metas.imageX.toString()
140
- } : {}),
141
- ...(page.metas.imageY ? {
142
- 'og:image:height': page.metas.imageY.toString()
143
- } : {})
144
- } : {}),
128
+ private buildMetas() {
129
+
130
+ const metas = {
131
+
132
+ 'og:type': 'website',
133
+ 'og:locale': this.app.identity.locale,
134
+ 'og:site_name': this.app.identity.web.title,
135
+ 'og:url': this.context.request.req.url,
145
136
 
137
+ 'og:title': this.title,
138
+ 'og:description': this.description,
139
+
140
+ 'twitter:url': this.context.request.req.url,
146
141
  'twitter:card': 'summary_large_image',
147
- 'twitter:title': page.title,
148
- 'twitter:description': page.description,
149
- 'twitter:url': fullUrl,
150
- 'twitter:text:title': page.title,
151
-
152
- ...(app.identity.social?.twitter? ? {
153
- 'twitter:site': `@${app.identity.social?.twitter?}`,
154
- 'twitter:creator': `@${app.identity.social?.twitter?}`
155
- } : {}),
156
-
157
- ...(page.metas.imageUrl ? {
158
- 'twitter:image': page.metas.imageUrl,
159
- ...(page.metas.imageX ? {
160
- 'twitter:image:width': page.metas.imageX.toString()
161
- } : {}),
162
- ...(page.metas.imageY ? {
163
- 'twitter:image:height': page.metas.imageY.toString()
164
- } : {})
165
- } : {}),
166
-
167
- ...page.metas.metasAdditionnelles
168
- };*/
142
+ 'twitter:title': this.title,
143
+ 'twitter:text:title': this.title,
144
+ 'twitter:description': this.description,
145
+
146
+ ...this.metas
147
+ };
148
+
149
+ for (const key in metas) {
150
+ const value = metas[key];
151
+ if (value === "") continue;
152
+ this.head.push({ $: 'meta', property: key, content: value });
153
+ }
154
+ }
155
+
156
+ private buildJsonLd() {
157
+ this.jsonld.push({
158
+ '@type': 'Organization',
159
+ '@id': this.router.url('/#organization'),
160
+ name: this.app.identity.author.name,
161
+ url: this.app.identity.author.url,
162
+ logo: {
163
+ '@type': 'ImageObject',
164
+ '@id': this.router.url('/#logo'),
165
+ url: this.router.url('/public/app/android-chrome-512x512.png'),
166
+ width: "512px",
167
+ height: "512px",
168
+ caption: this.app.identity.author.name
169
+ },
170
+ sameAs: []
171
+ }, {
172
+ '@type': 'WebSite',
173
+ '@id': this.router.url('/#website'),
174
+ url: this.router.url('/'),
175
+ name: this.app.identity.name,
176
+ description: this.app.identity.description,
177
+ "publisher": {
178
+ "@id": this.router.url('/#organization'),
179
+ },
180
+ inLanguage: this.app.identity.locale,
181
+ potentialAction: [],
182
+ }, {
183
+ '@type': "WebPage",
184
+ '@id': this.url,
185
+ url: this.url,
186
+
187
+ "isPartOf": {
188
+ "@id": this.router.url('/#website'),
189
+ },
190
+
191
+ name: this.title,
192
+ description: this.description,
193
+ inLanguage: this.app.identity.locale,
194
+ });
169
195
  }
170
196
  }
@@ -1,70 +0,0 @@
1
- // Types
2
-
3
-
4
- export default (page: TInfosPage, route: TInfosRoute) => {
5
- //const isSubPage = pageTitle && url.pathname !== '/';
6
-
7
- let schemaPage = {
8
- '@type': "WebPage",
9
- '@id': route.requete.url,
10
- name: page.title,
11
- url: route.requete.url,
12
- description: page.description,
13
- potentialAction: [{
14
- "@type": "SearchAction"
15
- }],
16
-
17
- ...(page.metas.richSnippetsPage === undefined ? {} : page.metas.richSnippetsPage)
18
- }
19
-
20
- /*if (isSubPage)
21
- schemaPage.breadcrumb = {
22
- '@context': 'http://schema.org',
23
- '@type': 'BreadcrumbList',
24
- itemListElement: [
25
- {
26
- '@type': 'ListItem',
27
- position: 1,
28
- item: {
29
- '@id': siteUrl,
30
- name: siteTitle,
31
- },
32
- },
33
- {
34
- '@type': 'ListItem',
35
- position: 2,
36
- item: {
37
- '@id': canonical,
38
- name: pageTitle,
39
- },
40
- },
41
- ],
42
- }*/
43
-
44
- let schemaFinal = page.metas.richSnippets === undefined ? schemaPage : {
45
- ...page.metas.richSnippets,
46
- mainEntityOfPage: schemaPage
47
- };
48
-
49
- return {
50
- '@context': 'http://schema.org',
51
- ...schemaFinal
52
- }
53
-
54
- /*
55
- '@type': 'WebSite',
56
- url: SEO.url,
57
- name: SEO.titre.site,
58
- inLanguage: 'French',
59
- about: [{
60
- "@type": "Thing",
61
- name: "Gagner de l'argent sur internet"
62
- }, {
63
- "@type": "Thing",
64
- name: "Développer son business en ligne"
65
- }, {
66
- "@type": "Thing",
67
- name: "Marketing"
68
- }]
69
- */
70
- };