react-cheminfo 0.4.1 → 0.6.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.
- package/README.md +182 -34
- package/lib/ecosystem/core/sites.d.ts +1 -1
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +10 -0
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +3 -0
- package/lib/ecosystem/ui/glyphs.js.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts +5 -0
- package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalCanvas.js +4 -3
- package/lib/orbital/ui/AtomicOrbitalCanvas.js.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalViewer.d.ts +5 -0
- package/lib/orbital/ui/AtomicOrbitalViewer.d.ts.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalViewer.js.map +1 -1
- package/lib/orbital/ui/axesGeometry.d.ts +27 -0
- package/lib/orbital/ui/axesGeometry.d.ts.map +1 -0
- package/lib/orbital/ui/axesGeometry.js +74 -0
- package/lib/orbital/ui/axesGeometry.js.map +1 -0
- package/lib/orbital/ui/camera.d.ts +7 -0
- package/lib/orbital/ui/camera.d.ts.map +1 -1
- package/lib/orbital/ui/camera.js +8 -1
- package/lib/orbital/ui/camera.js.map +1 -1
- package/lib/orbital/ui/renderAxes.d.ts +53 -0
- package/lib/orbital/ui/renderAxes.d.ts.map +1 -0
- package/lib/orbital/ui/renderAxes.js +110 -0
- package/lib/orbital/ui/renderAxes.js.map +1 -0
- package/lib/orbital/ui/viewer.d.ts +16 -0
- package/lib/orbital/ui/viewer.d.ts.map +1 -1
- package/lib/orbital/ui/viewer.js +24 -2
- package/lib/orbital/ui/viewer.js.map +1 -1
- package/lib/seo/core/documentMeta.d.ts +2 -2
- package/lib/seo/core/documentMeta.js +4 -3
- package/lib/seo/core/documentMeta.js.map +1 -1
- package/lib/seo/core/index.d.ts +13 -4
- package/lib/seo/core/index.d.ts.map +1 -1
- package/lib/seo/core/index.js +8 -3
- package/lib/seo/core/index.js.map +1 -1
- package/lib/seo/core/noscript.d.ts +97 -0
- package/lib/seo/core/noscript.d.ts.map +1 -0
- package/lib/seo/core/noscript.js +93 -0
- package/lib/seo/core/noscript.js.map +1 -0
- package/lib/seo/core/pageMeta.d.ts +30 -14
- package/lib/seo/core/pageMeta.d.ts.map +1 -1
- package/lib/seo/core/pageMeta.js +40 -43
- package/lib/seo/core/pageMeta.js.map +1 -1
- package/lib/seo/core/robots.d.ts +55 -0
- package/lib/seo/core/robots.d.ts.map +1 -0
- package/lib/seo/core/robots.js +70 -0
- package/lib/seo/core/robots.js.map +1 -0
- package/lib/seo/core/routes.d.ts +73 -5
- package/lib/seo/core/routes.d.ts.map +1 -1
- package/lib/seo/core/routes.js +142 -16
- package/lib/seo/core/routes.js.map +1 -1
- package/lib/seo/core/siteFiles.d.ts +39 -43
- package/lib/seo/core/siteFiles.d.ts.map +1 -1
- package/lib/seo/core/siteFiles.js +53 -69
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/seo/core/startDocumentMeta.d.ts +44 -0
- package/lib/seo/core/startDocumentMeta.d.ts.map +1 -0
- package/lib/seo/core/startDocumentMeta.js +47 -0
- package/lib/seo/core/startDocumentMeta.js.map +1 -0
- package/lib/seo/core/structuredData.d.ts +48 -0
- package/lib/seo/core/structuredData.d.ts.map +1 -0
- package/lib/seo/core/structuredData.js +41 -0
- package/lib/seo/core/structuredData.js.map +1 -0
- package/lib/seo/core/template.d.ts +48 -0
- package/lib/seo/core/template.d.ts.map +1 -0
- package/lib/seo/core/template.js +53 -0
- package/lib/seo/core/template.js.map +1 -0
- package/lib/seo/vite/ogCard.d.ts +9 -1
- package/lib/seo/vite/ogCard.d.ts.map +1 -1
- package/lib/seo/vite/ogCard.js +14 -4
- package/lib/seo/vite/ogCard.js.map +1 -1
- package/lib/seo/vite/prerender.d.ts +38 -7
- package/lib/seo/vite/prerender.d.ts.map +1 -1
- package/lib/seo/vite/prerender.js +68 -30
- package/lib/seo/vite/prerender.js.map +1 -1
- package/package.json +1 -1
- package/src/ecosystem/core/sites.ts +11 -0
- package/src/ecosystem/ui/glyphs.tsx +19 -0
- package/src/orbital/ui/AtomicOrbitalCanvas.tsx +9 -2
- package/src/orbital/ui/AtomicOrbitalViewer.tsx +5 -0
- package/src/orbital/ui/axesGeometry.ts +91 -0
- package/src/orbital/ui/camera.ts +9 -1
- package/src/orbital/ui/renderAxes.ts +190 -0
- package/src/orbital/ui/viewer.ts +32 -2
- package/src/seo/core/documentMeta.ts +5 -5
- package/src/seo/core/index.ts +19 -12
- package/src/seo/core/noscript.ts +195 -0
- package/src/seo/core/pageMeta.ts +54 -53
- package/src/seo/core/robots.ts +114 -0
- package/src/seo/core/routes.ts +181 -14
- package/src/seo/core/siteFiles.ts +58 -96
- package/src/seo/core/startDocumentMeta.ts +77 -0
- package/src/seo/core/structuredData.ts +80 -0
- package/src/seo/core/template.ts +54 -0
- package/src/seo/vite/ogCard.ts +15 -5
- package/src/seo/vite/prerender.ts +105 -58
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
* crawler gets whatever came off the wire. Without this every address carries
|
|
7
7
|
* the same title and a search engine folds the whole site into one result.
|
|
8
8
|
*
|
|
9
|
+
* The build's `index.html` is the template: it declares where its head and its
|
|
10
|
+
* crawl path go with `<!--cheminfo:head-->` and `<!--cheminfo:body-->`, and
|
|
11
|
+
* every file written here is filled from it. The dev server is filled the same
|
|
12
|
+
* way, from the home route, so what a developer opens is what the build ships.
|
|
13
|
+
*
|
|
9
14
|
* These files are also what makes the server's catch-all fallback unnecessary.
|
|
10
15
|
* Every address the tool answers is on disk, so an address that is *not* on
|
|
11
16
|
* disk is genuinely not a page and must 404 rather than serving the tool under
|
|
@@ -18,14 +23,16 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
18
23
|
import type { Logger, Plugin } from 'vite';
|
|
19
24
|
|
|
20
25
|
import type { EcosystemSite, SiteId } from '../../ecosystem/core/sites.ts';
|
|
21
|
-
import {
|
|
26
|
+
import type { NoscriptText } from '../core/noscript.ts';
|
|
27
|
+
import { noscriptIndex } from '../core/noscript.ts';
|
|
28
|
+
import { pageHeadTags } from '../core/pageMeta.ts';
|
|
29
|
+
import type { RobotsDisallow } from '../core/robots.ts';
|
|
30
|
+
import { robotsTxt } from '../core/robots.ts';
|
|
22
31
|
import type { RouteMeta } from '../core/routes.ts';
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
structuredDataScript,
|
|
28
|
-
} from '../core/siteFiles.ts';
|
|
32
|
+
import { assertRoutes, homeRoute, trimTrailingSlash } from '../core/routes.ts';
|
|
33
|
+
import { sitemapXml } from '../core/siteFiles.ts';
|
|
34
|
+
import { structuredDataScript } from '../core/structuredData.ts';
|
|
35
|
+
import { PAGE_BODY_MARKER, PAGE_HEAD_MARKER, fill } from '../core/template.ts';
|
|
29
36
|
|
|
30
37
|
/** What the build needs to know to write the site's addresses. */
|
|
31
38
|
export interface PrerenderOptions {
|
|
@@ -34,16 +41,20 @@ export interface PrerenderOptions {
|
|
|
34
41
|
/** Every address it answers, each with its title and description. */
|
|
35
42
|
routes: readonly RouteMeta[];
|
|
36
43
|
/**
|
|
37
|
-
*
|
|
44
|
+
* Where the site is served, mount path included. Every absolute address is
|
|
45
|
+
* built on it, and `robots.txt` and the `noscript` index write their paths
|
|
46
|
+
* under its mount. The files on disk are laid out from the build's own root
|
|
47
|
+
* either way: it is the server that puts them under the mount.
|
|
38
48
|
* @default `https://<the site's host>`
|
|
39
49
|
*/
|
|
40
50
|
origin?: string;
|
|
41
51
|
/**
|
|
42
|
-
*
|
|
43
|
-
* `false` to write no `robots.txt` at
|
|
52
|
+
* Addresses `robots.txt` keeps out of the index, e.g. `/v1/`, each optionally
|
|
53
|
+
* with the sentence saying why. Set to `false` to write no `robots.txt` at
|
|
54
|
+
* all, for a site that ships its own.
|
|
44
55
|
* @default []
|
|
45
56
|
*/
|
|
46
|
-
robots?: false |
|
|
57
|
+
robots?: false | ReadonlyArray<string | RobotsDisallow>;
|
|
47
58
|
/**
|
|
48
59
|
* The schema.org category of the structured-data block, or `false` to write
|
|
49
60
|
* none.
|
|
@@ -56,80 +67,98 @@ export interface PrerenderOptions {
|
|
|
56
67
|
*/
|
|
57
68
|
operatingSystem?: string;
|
|
58
69
|
/**
|
|
59
|
-
*
|
|
60
|
-
* the
|
|
70
|
+
* What the tool does, in the structured-data block.
|
|
71
|
+
* @default the site's tagline
|
|
72
|
+
*/
|
|
73
|
+
description?: string;
|
|
74
|
+
/**
|
|
75
|
+
* What a browser has to offer for the tool to run.
|
|
76
|
+
* @default 'Requires JavaScript'
|
|
77
|
+
*/
|
|
78
|
+
browserRequirements?: string;
|
|
79
|
+
/**
|
|
80
|
+
* The currency the zero price is quoted in.
|
|
81
|
+
* @default 'EUR'
|
|
82
|
+
*/
|
|
83
|
+
currency?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Whether the built page carries a `noscript` index of the addresses, what it
|
|
86
|
+
* says, which pages it lists and how it writes their addresses. It is the
|
|
87
|
+
* only crawl path through a site whose body is an empty root element, so
|
|
88
|
+
* `false` leaves one without any — and is also what lets a template ship no
|
|
89
|
+
* `<!--cheminfo:body-->` at all.
|
|
61
90
|
* @default true
|
|
62
91
|
*/
|
|
63
|
-
noscript?: boolean;
|
|
92
|
+
noscript?: boolean | NoscriptText;
|
|
64
93
|
}
|
|
65
94
|
|
|
66
95
|
/**
|
|
67
96
|
* Prerender every routed address of a cheminfo site.
|
|
68
97
|
* @param options - The site, its routes, and what a crawler is told.
|
|
69
98
|
* @returns The Vite plugin.
|
|
99
|
+
* @throws {Error} When the route table names an address twice or names one that
|
|
100
|
+
* is not a path, or when the origin is not an absolute address.
|
|
70
101
|
*/
|
|
71
102
|
export function cheminfoPrerender(options: PrerenderOptions): Plugin {
|
|
72
|
-
const {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
category,
|
|
78
|
-
operatingSystem,
|
|
79
|
-
noscript = true,
|
|
80
|
-
} = options;
|
|
103
|
+
const { site, routes, origin, robots = [] } = options;
|
|
104
|
+
assertRoutes(routes);
|
|
105
|
+
const structuredData = structuredDataOf(options);
|
|
106
|
+
const crawlPath = crawlPathOf(options);
|
|
107
|
+
|
|
81
108
|
let out = 'dist';
|
|
109
|
+
let serve = false;
|
|
82
110
|
let logger: Logger | null = null;
|
|
83
111
|
|
|
112
|
+
const page = (template: string, url: string) => {
|
|
113
|
+
const head = fill(
|
|
114
|
+
template,
|
|
115
|
+
PAGE_HEAD_MARKER,
|
|
116
|
+
`${pageHeadTags({ site, routes, origin, url })}${structuredData}`,
|
|
117
|
+
);
|
|
118
|
+
return crawlPath === '' ? head : fill(head, PAGE_BODY_MARKER, crawlPath);
|
|
119
|
+
};
|
|
120
|
+
|
|
84
121
|
return {
|
|
85
122
|
name: 'cheminfo:prerender',
|
|
86
|
-
apply: 'build',
|
|
87
123
|
|
|
88
124
|
configResolved(config) {
|
|
125
|
+
serve = config.command === 'serve';
|
|
89
126
|
out = resolve(config.root, config.build.outDir);
|
|
90
127
|
logger = config.logger;
|
|
91
128
|
},
|
|
92
129
|
|
|
130
|
+
// A dev run has no build to prerender, so the page vite serves is filled
|
|
131
|
+
// from the home route rather than shipped with its markers showing.
|
|
93
132
|
transformIndexHtml: {
|
|
94
133
|
order: 'post',
|
|
95
|
-
handler(html)
|
|
96
|
-
|
|
97
|
-
if (category !== false) {
|
|
98
|
-
page = insertBeforeHeadEnd(
|
|
99
|
-
page,
|
|
100
|
-
structuredDataScript({
|
|
101
|
-
site,
|
|
102
|
-
routes,
|
|
103
|
-
origin,
|
|
104
|
-
category,
|
|
105
|
-
operatingSystem,
|
|
106
|
-
}),
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
if (noscript) {
|
|
110
|
-
page = insertBeforeBodyEnd(
|
|
111
|
-
page,
|
|
112
|
-
noscriptIndex({ site, routes, origin }),
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
return page;
|
|
116
|
-
},
|
|
134
|
+
handler: (html: string) =>
|
|
135
|
+
serve ? page(html, homeRoute(routes).path) : html,
|
|
117
136
|
},
|
|
118
137
|
|
|
119
138
|
closeBundle() {
|
|
120
|
-
|
|
139
|
+
if (serve) return;
|
|
140
|
+
const template = readFileSync(join(out, 'index.html'), 'utf8');
|
|
141
|
+
|
|
142
|
+
const write = (url: string, file: string) => {
|
|
143
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
144
|
+
writeFileSync(file, page(template, url));
|
|
145
|
+
};
|
|
121
146
|
|
|
147
|
+
let root = false;
|
|
122
148
|
for (const route of routes) {
|
|
123
|
-
const
|
|
124
|
-
|
|
149
|
+
const address = trimTrailingSlash(route.path);
|
|
150
|
+
if (address === '/') root = true;
|
|
151
|
+
write(
|
|
152
|
+
route.path,
|
|
153
|
+
address === '/'
|
|
125
154
|
? join(out, 'index.html')
|
|
126
|
-
: join(out,
|
|
127
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
128
|
-
writeFileSync(
|
|
129
|
-
file,
|
|
130
|
-
injectPageMeta(index, { site, routes, origin, url: route.path }),
|
|
155
|
+
: join(out, address.slice(1), 'index.html'),
|
|
131
156
|
);
|
|
132
157
|
}
|
|
158
|
+
// The file a static server hands out for the mount itself. A table naming
|
|
159
|
+
// no root would otherwise leave the template vite built, and ship a site
|
|
160
|
+
// whose front page carries its markers instead of a head.
|
|
161
|
+
if (!root) write(homeRoute(routes).path, join(out, 'index.html'));
|
|
133
162
|
|
|
134
163
|
writeFileSync(
|
|
135
164
|
join(out, 'sitemap.xml'),
|
|
@@ -149,8 +178,26 @@ export function cheminfoPrerender(options: PrerenderOptions): Plugin {
|
|
|
149
178
|
};
|
|
150
179
|
}
|
|
151
180
|
|
|
152
|
-
function
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
155
|
-
|
|
181
|
+
function structuredDataOf(options: PrerenderOptions): string {
|
|
182
|
+
const { category, ...rest } = options;
|
|
183
|
+
if (category === false) return '';
|
|
184
|
+
const { site, routes, origin } = rest;
|
|
185
|
+
const { operatingSystem, description, browserRequirements, currency } = rest;
|
|
186
|
+
return `\n${structuredDataScript({
|
|
187
|
+
site,
|
|
188
|
+
routes,
|
|
189
|
+
origin,
|
|
190
|
+
category,
|
|
191
|
+
operatingSystem,
|
|
192
|
+
description,
|
|
193
|
+
browserRequirements,
|
|
194
|
+
currency,
|
|
195
|
+
})}`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function crawlPathOf(options: PrerenderOptions): string {
|
|
199
|
+
const { site, routes, origin, noscript = true } = options;
|
|
200
|
+
if (noscript === false) return '';
|
|
201
|
+
const { routes: listed, ...prose } = noscript === true ? {} : noscript;
|
|
202
|
+
return noscriptIndex({ site, origin, ...prose, routes: listed ?? routes });
|
|
156
203
|
}
|