@jasonshimmy/vite-plugin-cer-app 0.23.1 → 0.23.2
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/CHANGELOG.md +4 -0
- package/commits.txt +1 -1
- package/dist/cli/commands/preview.d.ts.map +1 -1
- package/dist/cli/commands/preview.js +37 -4
- package/dist/cli/commands/preview.js.map +1 -1
- package/dist/plugin/build-ssg.d.ts +4 -2
- package/dist/plugin/build-ssg.d.ts.map +1 -1
- package/dist/plugin/build-ssg.js +55 -5
- package/dist/plugin/build-ssg.js.map +1 -1
- package/dist/plugin/dev-server.d.ts +2 -0
- package/dist/plugin/dev-server.d.ts.map +1 -1
- package/dist/plugin/dev-server.js.map +1 -1
- package/dist/plugin/generated-dir.js +1 -1
- package/dist/plugin/generated-dir.js.map +1 -1
- package/dist/plugin/html-post-process.d.ts +29 -0
- package/dist/plugin/html-post-process.d.ts.map +1 -0
- package/dist/plugin/html-post-process.js +88 -0
- package/dist/plugin/html-post-process.js.map +1 -0
- package/dist/plugin/index.d.ts +9 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +30 -2
- package/dist/plugin/index.js.map +1 -1
- package/dist/runtime/app-template.d.ts +1 -4
- package/dist/runtime/app-template.d.ts.map +1 -1
- package/dist/runtime/app-template.js +14 -13
- package/dist/runtime/app-template.js.map +1 -1
- package/dist/runtime/composables/use-head.d.ts.map +1 -1
- package/dist/runtime/composables/use-head.js +30 -6
- package/dist/runtime/composables/use-head.js.map +1 -1
- package/dist/types/config.d.ts +8 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/docs/configuration.md +29 -0
- package/package.json +1 -1
- package/src/__tests__/plugin/app-template.test.ts +72 -18
- package/src/__tests__/plugin/html-post-process.test.ts +146 -0
- package/src/__tests__/plugin/resolve-config.test.ts +33 -0
- package/src/__tests__/runtime/app-template.test.ts +10 -0
- package/src/__tests__/runtime/use-head.test.ts +45 -0
- package/src/cli/commands/preview.ts +38 -4
- package/src/plugin/build-ssg.ts +72 -5
- package/src/plugin/dev-server.ts +2 -0
- package/src/plugin/generated-dir.ts +1 -1
- package/src/plugin/html-post-process.ts +96 -0
- package/src/plugin/index.ts +33 -2
- package/src/runtime/app-template.ts +14 -17
- package/src/runtime/composables/use-head.ts +28 -6
- package/src/types/config.ts +8 -0
|
@@ -4,23 +4,18 @@
|
|
|
4
4
|
* Always written to `.cer/app.ts` on every dev/build so consumers
|
|
5
5
|
* automatically receive the latest bootstrap code on plugin update.
|
|
6
6
|
* This file is gitignored and should never be edited directly.
|
|
7
|
-
*
|
|
8
|
-
* @param customColors - Project-specific color families to register in the JIT
|
|
9
|
-
* CSS engine at runtime. Serialized as a JSON literal in the generated source.
|
|
10
7
|
*/
|
|
11
|
-
export function generateAppEntryTemplate(
|
|
12
|
-
customColors?: Record<string, Record<string, string>>,
|
|
13
|
-
): string {
|
|
14
|
-
const enableJITCSSCall =
|
|
15
|
-
customColors && Object.keys(customColors).length > 0
|
|
16
|
-
? `enableJITCSS({ customColors: ${JSON.stringify(customColors)} })`
|
|
17
|
-
: `enableJITCSS()`
|
|
18
|
-
|
|
8
|
+
export function generateAppEntryTemplate(): string {
|
|
19
9
|
return `// AUTO-GENERATED by @jasonshimmy/vite-plugin-cer-app — do not edit.
|
|
20
10
|
// Regenerated automatically on every dev server start and build.
|
|
21
11
|
|
|
22
12
|
import '@jasonshimmy/custom-elements-runtime/css'
|
|
23
13
|
import 'virtual:cer-jit-css'
|
|
14
|
+
// virtual:cer-jit-init must run before virtual:cer-layouts and virtual:cer-plugins
|
|
15
|
+
// so JIT CSS is enabled before those modules upgrade custom elements via
|
|
16
|
+
// customElements.define(). Static imports execute depth-first in module order,
|
|
17
|
+
// so placing this import here guarantees enableJITCSS() fires first.
|
|
18
|
+
import 'virtual:cer-jit-init'
|
|
24
19
|
import 'virtual:cer-content-components'
|
|
25
20
|
import routes from 'virtual:cer-routes'
|
|
26
21
|
import layouts from 'virtual:cer-layouts'
|
|
@@ -38,7 +33,6 @@ import {
|
|
|
38
33
|
registerBuiltinComponents,
|
|
39
34
|
} from '@jasonshimmy/custom-elements-runtime'
|
|
40
35
|
import { initRouter } from '@jasonshimmy/custom-elements-runtime/router'
|
|
41
|
-
import { enableJITCSS } from '@jasonshimmy/custom-elements-runtime/jit-css'
|
|
42
36
|
import { initRuntimeConfig } from '@jasonshimmy/vite-plugin-cer-app/composables'
|
|
43
37
|
|
|
44
38
|
const _cerProcess = (globalThis).process
|
|
@@ -57,7 +51,6 @@ const _cerRuntimeDev =
|
|
|
57
51
|
|
|
58
52
|
registerBuiltinComponents()
|
|
59
53
|
setDevMode(_cerRuntimeDev)
|
|
60
|
-
${enableJITCSSCall}
|
|
61
54
|
initRuntimeConfig(runtimeConfig)
|
|
62
55
|
|
|
63
56
|
const router = initRouter({ routes })
|
|
@@ -217,9 +210,13 @@ component('cer-layout-view', () => {
|
|
|
217
210
|
// store.subscribe() synchronously pushes the current route once on
|
|
218
211
|
// subscription. That initial callback is not a real navigation and must not
|
|
219
212
|
// tear down the SSR slot before _doHydrate has pre-loaded the page.
|
|
220
|
-
// Subsequent callbacks
|
|
221
|
-
//
|
|
222
|
-
//
|
|
213
|
+
// Subsequent callbacks may be real navigations, but initRouter() also fires
|
|
214
|
+
// a queueMicrotask(() => navigate(...)) to run guards on the entry URL.
|
|
215
|
+
// That startup microtask resolves during the await route.load() gap —
|
|
216
|
+
// before _currentPageTag is set — so we must not drop the slot until the
|
|
217
|
+
// page module has actually been loaded (_currentPageTag !== null).
|
|
218
|
+
// The explicit _cerHydrating.value = false in _doHydrate() fires after
|
|
219
|
+
// _loadPageForPath completes and is the authoritative hydration trigger.
|
|
223
220
|
unsub = router.subscribe((s) => {
|
|
224
221
|
const _isInitialSubscribePush = !_sawInitialRouteState
|
|
225
222
|
_sawInitialRouteState = true
|
|
@@ -227,7 +224,7 @@ component('cer-layout-view', () => {
|
|
|
227
224
|
current.value = s
|
|
228
225
|
return
|
|
229
226
|
}
|
|
230
|
-
if (_cerHydrating.value) _cerHydrating.value = false
|
|
227
|
+
if (_cerHydrating.value && _currentPageTag !== null) _cerHydrating.value = false
|
|
231
228
|
current.value = s
|
|
232
229
|
})
|
|
233
230
|
})
|
|
@@ -152,7 +152,14 @@ export function useHead(input: HeadInput): void {
|
|
|
152
152
|
const rel = link.rel
|
|
153
153
|
const href = link.href
|
|
154
154
|
if (rel && href) {
|
|
155
|
-
|
|
155
|
+
// Canonical and icon links are singletons — find by rel alone so that
|
|
156
|
+
// updating the URL overwrites the existing tag rather than adding a
|
|
157
|
+
// duplicate. All other link types are matched by rel+href (e.g.
|
|
158
|
+
// stylesheets, where multiple hrefs are valid).
|
|
159
|
+
const isSingleton = rel === 'canonical' || rel === 'icon' || rel === 'shortcut icon'
|
|
160
|
+
let el = isSingleton
|
|
161
|
+
? document.querySelector(`link[rel="${rel}"]`)
|
|
162
|
+
: document.querySelector(`link[rel="${rel}"][href="${href}"]`)
|
|
156
163
|
if (!el) {
|
|
157
164
|
el = document.createElement('link')
|
|
158
165
|
document.head.appendChild(el)
|
|
@@ -176,12 +183,27 @@ export function useHead(input: HeadInput): void {
|
|
|
176
183
|
}
|
|
177
184
|
document.head.appendChild(el)
|
|
178
185
|
} else if (innerHTML && !src) {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
186
|
+
const type = rest.type ?? ''
|
|
187
|
+
if (type === 'application/ld+json') {
|
|
188
|
+
// JSON-LD is a singleton — update existing content rather than
|
|
189
|
+
// appending a duplicate on re-render or SPA navigation.
|
|
190
|
+
let el = document.querySelector('script[type="application/ld+json"]')
|
|
191
|
+
if (!el) {
|
|
192
|
+
el = document.createElement('script')
|
|
193
|
+
document.head.appendChild(el)
|
|
194
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
195
|
+
el.setAttribute(k, v)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
;(el as HTMLScriptElement).textContent = innerHTML
|
|
199
|
+
} else {
|
|
200
|
+
const el = document.createElement('script')
|
|
201
|
+
el.textContent = innerHTML
|
|
202
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
203
|
+
el.setAttribute(k, v)
|
|
204
|
+
}
|
|
205
|
+
document.head.appendChild(el)
|
|
183
206
|
}
|
|
184
|
-
document.head.appendChild(el)
|
|
185
207
|
}
|
|
186
208
|
}
|
|
187
209
|
}
|
package/src/types/config.ts
CHANGED
|
@@ -241,6 +241,14 @@ export interface RuntimeConfig {
|
|
|
241
241
|
export interface CerAppConfig {
|
|
242
242
|
mode?: 'spa' | 'ssr' | 'ssg'
|
|
243
243
|
srcDir?: string // defaults to 'app'
|
|
244
|
+
/**
|
|
245
|
+
* The canonical origin of the site (e.g. `'https://example.com'`).
|
|
246
|
+
* No trailing slash. When set, the SSG build automatically:
|
|
247
|
+
* - Injects `<link rel="canonical" href="${siteUrl}${path}">` into every page.
|
|
248
|
+
* - Writes a `robots.txt` to `dist/` (skipped when a `public/robots.txt` already exists).
|
|
249
|
+
* Also available at runtime via `useRuntimeConfig().public.siteUrl`.
|
|
250
|
+
*/
|
|
251
|
+
siteUrl?: string
|
|
244
252
|
/** File-based content layer configuration. Reads from `content/` at the project root by default. */
|
|
245
253
|
content?: import('./content.js').CerContentConfig
|
|
246
254
|
/**
|