vite-react-ssg 0.0.2 → 0.0.3
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/LICENSE +21 -21
- package/README.md +238 -171
- package/bin/vite-react-ssg.js +3 -3
- package/dist/chunks/jsdomGlobal.cjs +79 -79
- package/dist/chunks/jsdomGlobal.mjs +79 -79
- package/dist/node/cli.cjs +1 -1
- package/dist/node/cli.mjs +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.mjs +1 -1
- package/dist/shared/{vite-react-ssg.f66e4ba5.mjs → vite-react-ssg.524ba00d.mjs} +26 -7
- package/dist/shared/{vite-react-ssg.0e1b881e.cjs → vite-react-ssg.a5dfecac.cjs} +27 -8
- package/package.json +2 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023 Riri
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Riri
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,172 +1,239 @@
|
|
|
1
|
-
# Vite React SSG
|
|
2
|
-
|
|
3
|
-
Static-site generation for React on Vite.
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/vite-react-ssg)
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
> **This library requires Node.js version >= 17**
|
|
10
|
-
> or `Request` is available
|
|
11
|
-
<pre>
|
|
12
|
-
<b>npm i -D vite-react-ssg</b> <em>react-router-dom</em>
|
|
13
|
-
</pre>
|
|
14
|
-
|
|
15
|
-
```diff
|
|
16
|
-
// package.json
|
|
17
|
-
{
|
|
18
|
-
"scripts": {
|
|
19
|
-
"dev": "vite",
|
|
20
|
-
- "build": "vite build"
|
|
21
|
-
+ "build": "vite-react-ssg build"
|
|
22
|
-
|
|
23
|
-
// OR if you want to use another vite config file
|
|
24
|
-
+ "build": "vite-react-ssg build -c another-vite.config.ts"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
// src/main.ts
|
|
31
|
-
import { ViteReactSSG } from 'vite-react-ssg'
|
|
32
|
-
import routes from './App.tsx'
|
|
33
|
-
|
|
34
|
-
export const createRoot = ViteReactSSG(
|
|
35
|
-
// react-router-dom data routes
|
|
36
|
-
{ routes },
|
|
37
|
-
// function to have custom setups
|
|
38
|
-
({ router, routes, isClient, initialState }) => {
|
|
39
|
-
// do something.
|
|
40
|
-
},
|
|
41
|
-
)
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
```tsx
|
|
45
|
-
// src/App.tsx
|
|
46
|
-
import React from 'react'
|
|
47
|
-
import type { RouteRecord } from 'vite-react-ssg'
|
|
48
|
-
import './App.css'
|
|
49
|
-
|
|
50
|
-
const pages = import.meta.glob<any>('./pages/**/*.tsx')
|
|
51
|
-
|
|
52
|
-
const children: RouteRecord[] = Object.entries(pages).map(([filepath, component]) => {
|
|
53
|
-
let path = filepath.split('/pages')[1]
|
|
54
|
-
path = path.split('.')[0].replace('index', '')
|
|
55
|
-
const entry = `src${filepath.slice(1)}`
|
|
56
|
-
|
|
57
|
-
if (path.endsWith('/')) {
|
|
58
|
-
return {
|
|
59
|
-
index: true,
|
|
60
|
-
Component: React.lazy(component),
|
|
61
|
-
entry,
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
path,
|
|
66
|
-
Component: React.lazy(component),
|
|
67
|
-
// Used to obtain static resources through manifest
|
|
68
|
-
entry,
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const Layout = React.lazy(() => import('./Layout'))
|
|
73
|
-
export const routes: RouteRecord[] = [
|
|
74
|
-
{
|
|
75
|
-
path: '/',
|
|
76
|
-
element: <Layout />,
|
|
77
|
-
children,
|
|
78
|
-
// Used to obtain static resources through manifest
|
|
79
|
-
entry: 'src/Layout.tsx',
|
|
80
|
-
},
|
|
81
|
-
]
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
1
|
+
# Vite React SSG
|
|
2
|
+
|
|
3
|
+
Static-site generation for React on Vite.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/vite-react-ssg)
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
> **This library requires Node.js version >= 17**
|
|
10
|
+
> or `Request` is available
|
|
11
|
+
<pre>
|
|
12
|
+
<b>npm i -D vite-react-ssg</b> <em>react-router-dom</em>
|
|
13
|
+
</pre>
|
|
14
|
+
|
|
15
|
+
```diff
|
|
16
|
+
// package.json
|
|
17
|
+
{
|
|
18
|
+
"scripts": {
|
|
19
|
+
"dev": "vite",
|
|
20
|
+
- "build": "vite build"
|
|
21
|
+
+ "build": "vite-react-ssg build"
|
|
22
|
+
|
|
23
|
+
// OR if you want to use another vite config file
|
|
24
|
+
+ "build": "vite-react-ssg build -c another-vite.config.ts"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// src/main.ts
|
|
31
|
+
import { ViteReactSSG } from 'vite-react-ssg'
|
|
32
|
+
import routes from './App.tsx'
|
|
33
|
+
|
|
34
|
+
export const createRoot = ViteReactSSG(
|
|
35
|
+
// react-router-dom data routes
|
|
36
|
+
{ routes },
|
|
37
|
+
// function to have custom setups
|
|
38
|
+
({ router, routes, isClient, initialState }) => {
|
|
39
|
+
// do something.
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
// src/App.tsx
|
|
46
|
+
import React from 'react'
|
|
47
|
+
import type { RouteRecord } from 'vite-react-ssg'
|
|
48
|
+
import './App.css'
|
|
49
|
+
|
|
50
|
+
const pages = import.meta.glob<any>('./pages/**/*.tsx')
|
|
51
|
+
|
|
52
|
+
const children: RouteRecord[] = Object.entries(pages).map(([filepath, component]) => {
|
|
53
|
+
let path = filepath.split('/pages')[1]
|
|
54
|
+
path = path.split('.')[0].replace('index', '')
|
|
55
|
+
const entry = `src${filepath.slice(1)}`
|
|
56
|
+
|
|
57
|
+
if (path.endsWith('/')) {
|
|
58
|
+
return {
|
|
59
|
+
index: true,
|
|
60
|
+
Component: React.lazy(component),
|
|
61
|
+
entry,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
path,
|
|
66
|
+
Component: React.lazy(component),
|
|
67
|
+
// Used to obtain static resources through manifest
|
|
68
|
+
entry,
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const Layout = React.lazy(() => import('./Layout'))
|
|
73
|
+
export const routes: RouteRecord[] = [
|
|
74
|
+
{
|
|
75
|
+
path: '/',
|
|
76
|
+
element: <Layout />,
|
|
77
|
+
children,
|
|
78
|
+
// Used to obtain static resources through manifest
|
|
79
|
+
entry: 'src/Layout.tsx',
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Document head
|
|
85
|
+
|
|
86
|
+
You can use `<Head/>` to manage all of your changes to the document head. It takes plain HTML tags and outputs plain HTML tags. It is a wrapper around [React Helmet](https://github.com/nfl/react-helmet).
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { Head } from 'vite-react-ssg'
|
|
90
|
+
|
|
91
|
+
const MyHead = () => (
|
|
92
|
+
<Head>
|
|
93
|
+
<meta property="og:description" content="My custom description" />
|
|
94
|
+
<meta charSet="utf-8" />
|
|
95
|
+
<title>My Title</title>
|
|
96
|
+
<link rel="canonical" href="http://mysite.com/example" />
|
|
97
|
+
</Head>
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Nested or latter components will override duplicate usages:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { Head } from 'vite-react-ssg'
|
|
105
|
+
|
|
106
|
+
const MyHead = () => (
|
|
107
|
+
<parent>
|
|
108
|
+
<Head>
|
|
109
|
+
<title>My Title</title>
|
|
110
|
+
<meta name="description" content="Helmet application" />
|
|
111
|
+
</Head>
|
|
112
|
+
<child>
|
|
113
|
+
<Head>
|
|
114
|
+
<title>Nested Title</title>
|
|
115
|
+
<meta name="description" content="Nested component" />
|
|
116
|
+
</Head>
|
|
117
|
+
</child>
|
|
118
|
+
</parent>
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Outputs:
|
|
123
|
+
```html
|
|
124
|
+
<head>
|
|
125
|
+
<title>Nested Title</title>
|
|
126
|
+
<meta name="description" content="Nested component" />
|
|
127
|
+
</head>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Reactive head
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { useState } from 'react'
|
|
134
|
+
import { Head } from 'vite-react-ssg'
|
|
135
|
+
|
|
136
|
+
export default function MyHead() {
|
|
137
|
+
const [state, setState] = useState(false)
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<Head>
|
|
141
|
+
<meta charSet="UTF-8" />
|
|
142
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
143
|
+
<title>head test {state ? 'A' : 'B'}</title>
|
|
144
|
+
{/* You can also set the 'body' attributes here */}
|
|
145
|
+
<body className={`body-class-in-head-${state ? 'a' : 'b'}`} />
|
|
146
|
+
</Head>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Critical CSS
|
|
152
|
+
|
|
153
|
+
Vite SSG has built-in support for generating [Critical CSS](https://web.dev/extract-critical-css/) inlined in the HTML via the [`critters`](https://github.com/GoogleChromeLabs/critters) package.
|
|
154
|
+
Install it with:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm i -D critters
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Critical CSS generation will automatically be enabled for you.
|
|
161
|
+
|
|
162
|
+
To configure `critters`, pass [its options](https://github.com/GoogleChromeLabs/critters#usage) into `ssgOptions.crittersOptions` in `vite.config.ts`:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// vite.config.ts
|
|
166
|
+
export default defineConfig({
|
|
167
|
+
ssgOptions: {
|
|
168
|
+
crittersOptions: {
|
|
169
|
+
// E.g., change the preload strategy
|
|
170
|
+
preload: 'media',
|
|
171
|
+
// Other options: https://github.com/GoogleChromeLabs/critters#usage
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Configuration
|
|
178
|
+
|
|
179
|
+
You can pass options to Vite SSG in the `ssgOptions` field of your `vite.config.js`
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
// vite.config.js
|
|
183
|
+
|
|
184
|
+
export default {
|
|
185
|
+
plugins: [],
|
|
186
|
+
ssgOptions: {
|
|
187
|
+
script: 'async',
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
See [src/types.ts](./src/types.ts). for more options available.
|
|
193
|
+
|
|
194
|
+
### Custom Routes to Render
|
|
195
|
+
|
|
196
|
+
You can use the `includedRoutes` hook to include or exclude route paths to render, or even provide some completely custom ones.
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
// vite.config.js
|
|
200
|
+
|
|
201
|
+
export default {
|
|
202
|
+
plugins: [],
|
|
203
|
+
ssgOptions: {
|
|
204
|
+
includedRoutes(paths, routes) {
|
|
205
|
+
// exclude all the route paths that contains 'foo'
|
|
206
|
+
return paths.filter(i => !i.includes('foo'))
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
```js
|
|
212
|
+
// vite.config.js
|
|
213
|
+
|
|
214
|
+
export default {
|
|
215
|
+
plugins: [],
|
|
216
|
+
ssgOptions: {
|
|
217
|
+
includedRoutes(paths, routes) {
|
|
218
|
+
// use original route records
|
|
219
|
+
return routes.flatMap((route) => {
|
|
220
|
+
return route.name === 'Blog'
|
|
221
|
+
? myBlogSlugs.map(slug => `/blog/${slug}`)
|
|
222
|
+
: route.path
|
|
223
|
+
})
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Roadmap
|
|
230
|
+
|
|
231
|
+
- [x] Preload assets
|
|
232
|
+
- [x] Document head
|
|
233
|
+
- [ ] SSR under dev
|
|
234
|
+
- [ ] Initial State
|
|
235
|
+
- [ ] More Client components, such as `<ClientOnly />`
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
172
239
|
[MIT](./LICENSE) License © 2023 [Riri](https://github.com/Daydreamer-riri)
|
package/bin/vite-react-ssg.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict'
|
|
3
|
-
import('../dist/node/cli.mjs')
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
import('../dist/node/cli.mjs')
|
|
@@ -6,85 +6,85 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
6
6
|
|
|
7
7
|
const JSDOM__default = /*#__PURE__*/_interopDefaultCompat(JSDOM);
|
|
8
8
|
|
|
9
|
-
/*
|
|
10
|
-
MIT License
|
|
11
|
-
|
|
12
|
-
Copyright for portions of global-jsdom are held by Rico Sta. Cruz, 2016 as part of
|
|
13
|
-
jsdom-global. All other copyright for global-jsdom are held by jonathan schatz, 2017.
|
|
14
|
-
|
|
15
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
-
in the Software without restriction, including without limitation the rights
|
|
18
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
-
furnished to do so, subject to the following conditions:
|
|
21
|
-
|
|
22
|
-
The above copyright notice and this permission notice shall be included in all
|
|
23
|
-
copies or substantial portions of the Software.
|
|
24
|
-
|
|
25
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
-
SOFTWARE.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const defaultHtml = '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
|
|
36
|
-
|
|
37
|
-
// define this here so that we only ever dynamically populate KEYS once.
|
|
38
|
-
|
|
39
|
-
const KEYS = [];
|
|
40
|
-
|
|
41
|
-
function jsdomGlobal(html = defaultHtml, options = {}) {
|
|
42
|
-
// Idempotency
|
|
43
|
-
if (global.navigator
|
|
44
|
-
&& global.navigator.userAgent
|
|
45
|
-
&& global.navigator.userAgent.includes('Node.js')
|
|
46
|
-
&& global.document
|
|
47
|
-
&& typeof global.document.destroy === 'function')
|
|
48
|
-
return global.document.destroy
|
|
49
|
-
|
|
50
|
-
// set a default url if we don't get one - otherwise things explode when we copy localstorage keys
|
|
51
|
-
if (!('url' in options))
|
|
52
|
-
Object.assign(options, { url: 'http://localhost:3000' });
|
|
53
|
-
|
|
54
|
-
// enable pretendToBeVisual by default since react needs
|
|
55
|
-
// window.requestAnimationFrame, see https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser
|
|
56
|
-
if (!('pretendToBeVisual' in options))
|
|
57
|
-
Object.assign(options, { pretendToBeVisual: true });
|
|
58
|
-
|
|
59
|
-
const jsdom = new JSDOM__default.JSDOM(html, options);
|
|
60
|
-
const { window } = jsdom;
|
|
61
|
-
const { document } = window;
|
|
62
|
-
|
|
63
|
-
// generate our list of keys by enumerating document.window - this list may vary
|
|
64
|
-
// based on the jsdom version. filter out internal methods as well as anything
|
|
65
|
-
// that node already defines
|
|
66
|
-
|
|
67
|
-
if (KEYS.length === 0) {
|
|
68
|
-
KEYS.push(...Object.getOwnPropertyNames(window).filter(k => !k.startsWith('_')).filter(k => !(k in global)));
|
|
69
|
-
// going to add our jsdom instance, see below
|
|
70
|
-
KEYS.push('$jsdom');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
KEYS.forEach(key => global[key] = window[key]);
|
|
74
|
-
|
|
75
|
-
// setup document / window / window.console
|
|
76
|
-
global.document = document;
|
|
77
|
-
global.window = window;
|
|
78
|
-
window.console = global.console;
|
|
79
|
-
|
|
80
|
-
// add access to our jsdom instance
|
|
81
|
-
global.$jsdom = jsdom;
|
|
82
|
-
|
|
83
|
-
const cleanup = () => KEYS.forEach(key => delete global[key]);
|
|
84
|
-
|
|
85
|
-
document.destroy = cleanup;
|
|
86
|
-
|
|
87
|
-
return cleanup
|
|
9
|
+
/*
|
|
10
|
+
MIT License
|
|
11
|
+
|
|
12
|
+
Copyright for portions of global-jsdom are held by Rico Sta. Cruz, 2016 as part of
|
|
13
|
+
jsdom-global. All other copyright for global-jsdom are held by jonathan schatz, 2017.
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const defaultHtml = '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
|
|
36
|
+
|
|
37
|
+
// define this here so that we only ever dynamically populate KEYS once.
|
|
38
|
+
|
|
39
|
+
const KEYS = [];
|
|
40
|
+
|
|
41
|
+
function jsdomGlobal(html = defaultHtml, options = {}) {
|
|
42
|
+
// Idempotency
|
|
43
|
+
if (global.navigator
|
|
44
|
+
&& global.navigator.userAgent
|
|
45
|
+
&& global.navigator.userAgent.includes('Node.js')
|
|
46
|
+
&& global.document
|
|
47
|
+
&& typeof global.document.destroy === 'function')
|
|
48
|
+
return global.document.destroy
|
|
49
|
+
|
|
50
|
+
// set a default url if we don't get one - otherwise things explode when we copy localstorage keys
|
|
51
|
+
if (!('url' in options))
|
|
52
|
+
Object.assign(options, { url: 'http://localhost:3000' });
|
|
53
|
+
|
|
54
|
+
// enable pretendToBeVisual by default since react needs
|
|
55
|
+
// window.requestAnimationFrame, see https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser
|
|
56
|
+
if (!('pretendToBeVisual' in options))
|
|
57
|
+
Object.assign(options, { pretendToBeVisual: true });
|
|
58
|
+
|
|
59
|
+
const jsdom = new JSDOM__default.JSDOM(html, options);
|
|
60
|
+
const { window } = jsdom;
|
|
61
|
+
const { document } = window;
|
|
62
|
+
|
|
63
|
+
// generate our list of keys by enumerating document.window - this list may vary
|
|
64
|
+
// based on the jsdom version. filter out internal methods as well as anything
|
|
65
|
+
// that node already defines
|
|
66
|
+
|
|
67
|
+
if (KEYS.length === 0) {
|
|
68
|
+
KEYS.push(...Object.getOwnPropertyNames(window).filter(k => !k.startsWith('_')).filter(k => !(k in global)));
|
|
69
|
+
// going to add our jsdom instance, see below
|
|
70
|
+
KEYS.push('$jsdom');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
KEYS.forEach(key => global[key] = window[key]);
|
|
74
|
+
|
|
75
|
+
// setup document / window / window.console
|
|
76
|
+
global.document = document;
|
|
77
|
+
global.window = window;
|
|
78
|
+
window.console = global.console;
|
|
79
|
+
|
|
80
|
+
// add access to our jsdom instance
|
|
81
|
+
global.$jsdom = jsdom;
|
|
82
|
+
|
|
83
|
+
const cleanup = () => KEYS.forEach(key => delete global[key]);
|
|
84
|
+
|
|
85
|
+
document.destroy = cleanup;
|
|
86
|
+
|
|
87
|
+
return cleanup
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
exports.jsdomGlobal = jsdomGlobal;
|
|
@@ -1,84 +1,84 @@
|
|
|
1
1
|
import JSDOM from 'jsdom';
|
|
2
2
|
|
|
3
|
-
/*
|
|
4
|
-
MIT License
|
|
5
|
-
|
|
6
|
-
Copyright for portions of global-jsdom are held by Rico Sta. Cruz, 2016 as part of
|
|
7
|
-
jsdom-global. All other copyright for global-jsdom are held by jonathan schatz, 2017.
|
|
8
|
-
|
|
9
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
-
in the Software without restriction, including without limitation the rights
|
|
12
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
-
furnished to do so, subject to the following conditions:
|
|
15
|
-
|
|
16
|
-
The above copyright notice and this permission notice shall be included in all
|
|
17
|
-
copies or substantial portions of the Software.
|
|
18
|
-
|
|
19
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
-
SOFTWARE.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const defaultHtml = '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
|
|
30
|
-
|
|
31
|
-
// define this here so that we only ever dynamically populate KEYS once.
|
|
32
|
-
|
|
33
|
-
const KEYS = [];
|
|
34
|
-
|
|
35
|
-
function jsdomGlobal(html = defaultHtml, options = {}) {
|
|
36
|
-
// Idempotency
|
|
37
|
-
if (global.navigator
|
|
38
|
-
&& global.navigator.userAgent
|
|
39
|
-
&& global.navigator.userAgent.includes('Node.js')
|
|
40
|
-
&& global.document
|
|
41
|
-
&& typeof global.document.destroy === 'function')
|
|
42
|
-
return global.document.destroy
|
|
43
|
-
|
|
44
|
-
// set a default url if we don't get one - otherwise things explode when we copy localstorage keys
|
|
45
|
-
if (!('url' in options))
|
|
46
|
-
Object.assign(options, { url: 'http://localhost:3000' });
|
|
47
|
-
|
|
48
|
-
// enable pretendToBeVisual by default since react needs
|
|
49
|
-
// window.requestAnimationFrame, see https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser
|
|
50
|
-
if (!('pretendToBeVisual' in options))
|
|
51
|
-
Object.assign(options, { pretendToBeVisual: true });
|
|
52
|
-
|
|
53
|
-
const jsdom = new JSDOM.JSDOM(html, options);
|
|
54
|
-
const { window } = jsdom;
|
|
55
|
-
const { document } = window;
|
|
56
|
-
|
|
57
|
-
// generate our list of keys by enumerating document.window - this list may vary
|
|
58
|
-
// based on the jsdom version. filter out internal methods as well as anything
|
|
59
|
-
// that node already defines
|
|
60
|
-
|
|
61
|
-
if (KEYS.length === 0) {
|
|
62
|
-
KEYS.push(...Object.getOwnPropertyNames(window).filter(k => !k.startsWith('_')).filter(k => !(k in global)));
|
|
63
|
-
// going to add our jsdom instance, see below
|
|
64
|
-
KEYS.push('$jsdom');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
KEYS.forEach(key => global[key] = window[key]);
|
|
68
|
-
|
|
69
|
-
// setup document / window / window.console
|
|
70
|
-
global.document = document;
|
|
71
|
-
global.window = window;
|
|
72
|
-
window.console = global.console;
|
|
73
|
-
|
|
74
|
-
// add access to our jsdom instance
|
|
75
|
-
global.$jsdom = jsdom;
|
|
76
|
-
|
|
77
|
-
const cleanup = () => KEYS.forEach(key => delete global[key]);
|
|
78
|
-
|
|
79
|
-
document.destroy = cleanup;
|
|
80
|
-
|
|
81
|
-
return cleanup
|
|
3
|
+
/*
|
|
4
|
+
MIT License
|
|
5
|
+
|
|
6
|
+
Copyright for portions of global-jsdom are held by Rico Sta. Cruz, 2016 as part of
|
|
7
|
+
jsdom-global. All other copyright for global-jsdom are held by jonathan schatz, 2017.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const defaultHtml = '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
|
|
30
|
+
|
|
31
|
+
// define this here so that we only ever dynamically populate KEYS once.
|
|
32
|
+
|
|
33
|
+
const KEYS = [];
|
|
34
|
+
|
|
35
|
+
function jsdomGlobal(html = defaultHtml, options = {}) {
|
|
36
|
+
// Idempotency
|
|
37
|
+
if (global.navigator
|
|
38
|
+
&& global.navigator.userAgent
|
|
39
|
+
&& global.navigator.userAgent.includes('Node.js')
|
|
40
|
+
&& global.document
|
|
41
|
+
&& typeof global.document.destroy === 'function')
|
|
42
|
+
return global.document.destroy
|
|
43
|
+
|
|
44
|
+
// set a default url if we don't get one - otherwise things explode when we copy localstorage keys
|
|
45
|
+
if (!('url' in options))
|
|
46
|
+
Object.assign(options, { url: 'http://localhost:3000' });
|
|
47
|
+
|
|
48
|
+
// enable pretendToBeVisual by default since react needs
|
|
49
|
+
// window.requestAnimationFrame, see https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser
|
|
50
|
+
if (!('pretendToBeVisual' in options))
|
|
51
|
+
Object.assign(options, { pretendToBeVisual: true });
|
|
52
|
+
|
|
53
|
+
const jsdom = new JSDOM.JSDOM(html, options);
|
|
54
|
+
const { window } = jsdom;
|
|
55
|
+
const { document } = window;
|
|
56
|
+
|
|
57
|
+
// generate our list of keys by enumerating document.window - this list may vary
|
|
58
|
+
// based on the jsdom version. filter out internal methods as well as anything
|
|
59
|
+
// that node already defines
|
|
60
|
+
|
|
61
|
+
if (KEYS.length === 0) {
|
|
62
|
+
KEYS.push(...Object.getOwnPropertyNames(window).filter(k => !k.startsWith('_')).filter(k => !(k in global)));
|
|
63
|
+
// going to add our jsdom instance, see below
|
|
64
|
+
KEYS.push('$jsdom');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
KEYS.forEach(key => global[key] = window[key]);
|
|
68
|
+
|
|
69
|
+
// setup document / window / window.console
|
|
70
|
+
global.document = document;
|
|
71
|
+
global.window = window;
|
|
72
|
+
window.console = global.console;
|
|
73
|
+
|
|
74
|
+
// add access to our jsdom instance
|
|
75
|
+
global.$jsdom = jsdom;
|
|
76
|
+
|
|
77
|
+
const cleanup = () => KEYS.forEach(key => delete global[key]);
|
|
78
|
+
|
|
79
|
+
document.destroy = cleanup;
|
|
80
|
+
|
|
81
|
+
return cleanup
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
export { jsdomGlobal };
|
package/dist/node/cli.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const kolorist = require('kolorist');
|
|
4
4
|
const yargs = require('yargs');
|
|
5
5
|
const helpers = require('yargs/helpers');
|
|
6
|
-
const build = require('../shared/vite-react-ssg.
|
|
6
|
+
const build = require('../shared/vite-react-ssg.a5dfecac.cjs');
|
|
7
7
|
require('node:path');
|
|
8
8
|
require('node:module');
|
|
9
9
|
require('fs-extra');
|
package/dist/node/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { gray, bold, red, reset, underline } from 'kolorist';
|
|
2
2
|
import yargs from 'yargs';
|
|
3
3
|
import { hideBin } from 'yargs/helpers';
|
|
4
|
-
import { b as build } from '../shared/vite-react-ssg.
|
|
4
|
+
import { b as build } from '../shared/vite-react-ssg.524ba00d.mjs';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'node:module';
|
|
7
7
|
import 'fs-extra';
|
package/dist/node.cjs
CHANGED
package/dist/node.mjs
CHANGED
|
@@ -868,9 +868,10 @@ function routesToPaths(routes) {
|
|
|
868
868
|
pathToEntry[path] = /* @__PURE__ */ new Set([entry]);
|
|
869
869
|
}
|
|
870
870
|
if (!routes)
|
|
871
|
-
return { paths: ["/"] };
|
|
871
|
+
return { paths: ["/"], pathToEntry };
|
|
872
872
|
const paths = /* @__PURE__ */ new Set();
|
|
873
873
|
const getPaths = (routes2, prefix = "") => {
|
|
874
|
+
const parentPath = prefix;
|
|
874
875
|
prefix = prefix.replace(/\/$/g, "");
|
|
875
876
|
for (const route of routes2) {
|
|
876
877
|
let path = route.path;
|
|
@@ -878,6 +879,10 @@ function routesToPaths(routes) {
|
|
|
878
879
|
path = prefix && !route.path.startsWith("/") ? `${prefix}${route.path ? `/${route.path}` : ""}` : route.path;
|
|
879
880
|
paths.add(path);
|
|
880
881
|
addEntry(path, route.entry);
|
|
882
|
+
if (pathToEntry[parentPath]) {
|
|
883
|
+
const pathCopy = path;
|
|
884
|
+
pathToEntry[parentPath].forEach((entry) => addEntry(pathCopy, entry));
|
|
885
|
+
}
|
|
881
886
|
}
|
|
882
887
|
if (route.index)
|
|
883
888
|
addEntry(prefix, route.entry);
|
|
@@ -958,17 +963,18 @@ async function render(routes, request) {
|
|
|
958
963
|
throw context;
|
|
959
964
|
const router = createStaticRouter(dataRoutes, context);
|
|
960
965
|
const app = /* @__PURE__ */ React.createElement(HelmetProvider, { context: helmetContext }, /* @__PURE__ */ React.createElement(SiteMetadataDefaults, null), /* @__PURE__ */ React.createElement(StaticRouterProvider, { router, context }));
|
|
961
|
-
const
|
|
966
|
+
const appHTML = await renderStaticApp(app);
|
|
962
967
|
const { helmet } = helmetContext;
|
|
963
|
-
helmet.htmlAttributes.toString();
|
|
964
|
-
helmet.bodyAttributes.toString();
|
|
965
|
-
[
|
|
968
|
+
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
969
|
+
const bodyAttributes = helmet.bodyAttributes.toString();
|
|
970
|
+
const metaStrings = [
|
|
966
971
|
helmet.title.toString(),
|
|
967
972
|
helmet.meta.toString(),
|
|
968
973
|
helmet.link.toString(),
|
|
969
974
|
helmet.script.toString()
|
|
970
975
|
];
|
|
971
|
-
|
|
976
|
+
const metaAttributes = metaStrings.filter(Boolean);
|
|
977
|
+
return { appHTML, htmlAttributes, bodyAttributes, metaAttributes };
|
|
972
978
|
}
|
|
973
979
|
|
|
974
980
|
function renderPreloadLinks(document, modules, ssrManifest) {
|
|
@@ -1118,12 +1124,15 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1118
1124
|
url.hash = "";
|
|
1119
1125
|
url.pathname = route;
|
|
1120
1126
|
const request = new Request(url.href);
|
|
1121
|
-
const appHTML = await render([...routes2], request);
|
|
1127
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes2], request);
|
|
1122
1128
|
await triggerOnSSRAppRendered?.(route, appHTML, appCtx);
|
|
1123
1129
|
const renderedHTML = await renderHTML({
|
|
1124
1130
|
rootContainerId,
|
|
1125
1131
|
appHTML,
|
|
1126
1132
|
indexHTML,
|
|
1133
|
+
metaAttributes,
|
|
1134
|
+
bodyAttributes,
|
|
1135
|
+
htmlAttributes,
|
|
1127
1136
|
initialState: null
|
|
1128
1137
|
});
|
|
1129
1138
|
const jsdom = new JSDOM(renderedHTML);
|
|
@@ -1189,10 +1198,20 @@ async function renderHTML({
|
|
|
1189
1198
|
rootContainerId,
|
|
1190
1199
|
indexHTML,
|
|
1191
1200
|
appHTML,
|
|
1201
|
+
metaAttributes,
|
|
1202
|
+
bodyAttributes,
|
|
1203
|
+
htmlAttributes,
|
|
1192
1204
|
initialState
|
|
1193
1205
|
}) {
|
|
1194
1206
|
const stateScript = initialState ? `
|
|
1195
1207
|
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1208
|
+
const headStartTag = "<head>";
|
|
1209
|
+
const metaTags = metaAttributes.join("");
|
|
1210
|
+
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
1211
|
+
const bodyStartTag = "<body";
|
|
1212
|
+
indexHTML = indexHTML.replace(bodyStartTag, `${bodyStartTag} ${bodyAttributes}`);
|
|
1213
|
+
const htmlStartTag = "<html";
|
|
1214
|
+
indexHTML = indexHTML.replace(htmlStartTag, `${htmlStartTag} ${htmlAttributes}`);
|
|
1196
1215
|
const container = `<div id="${rootContainerId}"></div>`;
|
|
1197
1216
|
if (indexHTML.includes(container)) {
|
|
1198
1217
|
return indexHTML.replace(
|
|
@@ -875,9 +875,10 @@ function routesToPaths(routes) {
|
|
|
875
875
|
pathToEntry[path] = /* @__PURE__ */ new Set([entry]);
|
|
876
876
|
}
|
|
877
877
|
if (!routes)
|
|
878
|
-
return { paths: ["/"] };
|
|
878
|
+
return { paths: ["/"], pathToEntry };
|
|
879
879
|
const paths = /* @__PURE__ */ new Set();
|
|
880
880
|
const getPaths = (routes2, prefix = "") => {
|
|
881
|
+
const parentPath = prefix;
|
|
881
882
|
prefix = prefix.replace(/\/$/g, "");
|
|
882
883
|
for (const route of routes2) {
|
|
883
884
|
let path = route.path;
|
|
@@ -885,6 +886,10 @@ function routesToPaths(routes) {
|
|
|
885
886
|
path = prefix && !route.path.startsWith("/") ? `${prefix}${route.path ? `/${route.path}` : ""}` : route.path;
|
|
886
887
|
paths.add(path);
|
|
887
888
|
addEntry(path, route.entry);
|
|
889
|
+
if (pathToEntry[parentPath]) {
|
|
890
|
+
const pathCopy = path;
|
|
891
|
+
pathToEntry[parentPath].forEach((entry) => addEntry(pathCopy, entry));
|
|
892
|
+
}
|
|
888
893
|
}
|
|
889
894
|
if (route.index)
|
|
890
895
|
addEntry(prefix, route.entry);
|
|
@@ -965,17 +970,18 @@ async function render(routes, request) {
|
|
|
965
970
|
throw context;
|
|
966
971
|
const router = server_js.createStaticRouter(dataRoutes, context);
|
|
967
972
|
const app = /* @__PURE__ */ React__default.createElement(reactHelmetAsync.HelmetProvider, { context: helmetContext }, /* @__PURE__ */ React__default.createElement(SiteMetadataDefaults.SiteMetadataDefaults, null), /* @__PURE__ */ React__default.createElement(server_js.StaticRouterProvider, { router, context }));
|
|
968
|
-
const
|
|
973
|
+
const appHTML = await renderStaticApp(app);
|
|
969
974
|
const { helmet } = helmetContext;
|
|
970
|
-
helmet.htmlAttributes.toString();
|
|
971
|
-
helmet.bodyAttributes.toString();
|
|
972
|
-
[
|
|
975
|
+
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
976
|
+
const bodyAttributes = helmet.bodyAttributes.toString();
|
|
977
|
+
const metaStrings = [
|
|
973
978
|
helmet.title.toString(),
|
|
974
979
|
helmet.meta.toString(),
|
|
975
980
|
helmet.link.toString(),
|
|
976
981
|
helmet.script.toString()
|
|
977
982
|
];
|
|
978
|
-
|
|
983
|
+
const metaAttributes = metaStrings.filter(Boolean);
|
|
984
|
+
return { appHTML, htmlAttributes, bodyAttributes, metaAttributes };
|
|
979
985
|
}
|
|
980
986
|
|
|
981
987
|
function renderPreloadLinks(document, modules, ssrManifest) {
|
|
@@ -1098,7 +1104,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1098
1104
|
const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
|
|
1099
1105
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
1100
1106
|
const serverEntry = node_path.join(prefix, ssgOut, node_path.parse(ssrEntry).name + ext);
|
|
1101
|
-
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('shared/vite-react-ssg.
|
|
1107
|
+
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('shared/vite-react-ssg.a5dfecac.cjs', document.baseURI).href)));
|
|
1102
1108
|
const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
|
|
1103
1109
|
const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
|
|
1104
1110
|
const { routes } = await createRoot(false);
|
|
@@ -1125,12 +1131,15 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1125
1131
|
url.hash = "";
|
|
1126
1132
|
url.pathname = route;
|
|
1127
1133
|
const request = new Request(url.href);
|
|
1128
|
-
const appHTML = await render([...routes2], request);
|
|
1134
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes2], request);
|
|
1129
1135
|
await triggerOnSSRAppRendered?.(route, appHTML, appCtx);
|
|
1130
1136
|
const renderedHTML = await renderHTML({
|
|
1131
1137
|
rootContainerId,
|
|
1132
1138
|
appHTML,
|
|
1133
1139
|
indexHTML,
|
|
1140
|
+
metaAttributes,
|
|
1141
|
+
bodyAttributes,
|
|
1142
|
+
htmlAttributes,
|
|
1134
1143
|
initialState: null
|
|
1135
1144
|
});
|
|
1136
1145
|
const jsdom = new JSDOM.JSDOM(renderedHTML);
|
|
@@ -1196,10 +1205,20 @@ async function renderHTML({
|
|
|
1196
1205
|
rootContainerId,
|
|
1197
1206
|
indexHTML,
|
|
1198
1207
|
appHTML,
|
|
1208
|
+
metaAttributes,
|
|
1209
|
+
bodyAttributes,
|
|
1210
|
+
htmlAttributes,
|
|
1199
1211
|
initialState
|
|
1200
1212
|
}) {
|
|
1201
1213
|
const stateScript = initialState ? `
|
|
1202
1214
|
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1215
|
+
const headStartTag = "<head>";
|
|
1216
|
+
const metaTags = metaAttributes.join("");
|
|
1217
|
+
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
1218
|
+
const bodyStartTag = "<body";
|
|
1219
|
+
indexHTML = indexHTML.replace(bodyStartTag, `${bodyStartTag} ${bodyAttributes}`);
|
|
1220
|
+
const htmlStartTag = "<html";
|
|
1221
|
+
indexHTML = indexHTML.replace(htmlStartTag, `${htmlStartTag} ${htmlAttributes}`);
|
|
1203
1222
|
const container = `<div id="${rootContainerId}"></div>`;
|
|
1204
1223
|
if (indexHTML.includes(container)) {
|
|
1205
1224
|
return indexHTML.replace(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-react-ssg",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"packageManager": "pnpm@8.6.6",
|
|
6
6
|
"description": "",
|
|
7
7
|
"author": "Riri <Daydreamerriri@outlook.com>",
|
|
@@ -110,4 +110,4 @@
|
|
|
110
110
|
"vite-plugin-pwa": "^0.16.4",
|
|
111
111
|
"vitest": "0.33.0"
|
|
112
112
|
}
|
|
113
|
-
}
|
|
113
|
+
}
|