@authhero/widget 0.8.6 → 0.9.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 +130 -0
- package/dist/authhero-widget/authhero-widget.esm.js +1 -1
- package/dist/authhero-widget/index.esm.js +1 -1
- package/dist/authhero-widget/p-30808298.entry.js +1 -0
- package/dist/cjs/authhero-node.cjs.entry.js +55 -4
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/collection/components/authhero-node/authhero-node.js +56 -5
- package/dist/collection/components/authhero-widget/authhero-widget.js +2 -2
- package/dist/components/authhero-node.js +1 -1
- package/dist/components/authhero-widget.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/p-DITKGXA_.js +1 -0
- package/dist/esm/authhero-node.entry.js +55 -4
- package/dist/esm/index.js +1 -1
- package/hydrate/index.js +55 -4
- package/hydrate/index.mjs +55 -4
- package/package.json +7 -3
- package/dist/authhero-widget/p-072b155c.entry.js +0 -1
- package/dist/components/p-C_j5g_sG.js +0 -1
package/README.md
CHANGED
|
@@ -57,6 +57,136 @@ const html = await renderToString(`
|
|
|
57
57
|
`);
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
+
## SSR and Hydration
|
|
61
|
+
|
|
62
|
+
The widget is built with StencilJS and includes full server-side rendering (SSR) support with client-side hydration. This enables fast initial page loads while maintaining full interactivity.
|
|
63
|
+
|
|
64
|
+
### How It Works
|
|
65
|
+
|
|
66
|
+
1. **Server-Side Rendering**: The server renders the widget to HTML using `renderToString()` from `@authhero/widget/hydrate`. This produces static HTML with Declarative Shadow DOM that displays instantly without JavaScript.
|
|
67
|
+
|
|
68
|
+
2. **Client-Side Hydration**: When the browser loads the page, the widget's ESM bundle "hydrates" the server-rendered HTML, attaching event listeners and enabling interactivity without re-rendering the content.
|
|
69
|
+
|
|
70
|
+
3. **Progressive Enhancement**: Users see content immediately (even with JavaScript disabled), and interactivity is added once the JavaScript loads.
|
|
71
|
+
|
|
72
|
+
### Rendering Options
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { renderToString } from "@authhero/widget/hydrate";
|
|
76
|
+
|
|
77
|
+
const result = await renderToString(
|
|
78
|
+
`<authhero-widget screen='${JSON.stringify(screen)}'></authhero-widget>`,
|
|
79
|
+
{
|
|
80
|
+
// Return only the widget HTML, not a full document
|
|
81
|
+
fullDocument: false,
|
|
82
|
+
|
|
83
|
+
// Use Declarative Shadow DOM for SSR (recommended)
|
|
84
|
+
serializeShadowRoot: "declarative-shadow-dom",
|
|
85
|
+
|
|
86
|
+
// Optional: Remove unused styles for smaller payload
|
|
87
|
+
removeUnusedStyles: true,
|
|
88
|
+
|
|
89
|
+
// Optional: Format HTML for debugging
|
|
90
|
+
prettyHtml: false,
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// result.html contains the rendered HTML string
|
|
95
|
+
// result.diagnostics contains any warnings or errors
|
|
96
|
+
const widgetHtml = result.html;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Shadow DOM Serialization Modes
|
|
100
|
+
|
|
101
|
+
The `serializeShadowRoot` option controls how shadow DOM is rendered:
|
|
102
|
+
|
|
103
|
+
- **`"declarative-shadow-dom"`** (default): Uses the browser's native Declarative Shadow DOM feature. This is the most efficient option as the shadow DOM is part of the initial HTML.
|
|
104
|
+
|
|
105
|
+
- **`"scoped"`**: Renders content as scoped CSS without shadow DOM. The shadow DOM is then created during client-side hydration.
|
|
106
|
+
|
|
107
|
+
- **Mixed mode**: You can mix both approaches for different components:
|
|
108
|
+
```typescript
|
|
109
|
+
serializeShadowRoot: {
|
|
110
|
+
'declarative-shadow-dom': ['authhero-widget'],
|
|
111
|
+
scoped: ['some-other-component'],
|
|
112
|
+
default: 'declarative-shadow-dom'
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Complete SSR Example (Hono)
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { Hono } from "hono";
|
|
120
|
+
import { renderToString } from "@authhero/widget/hydrate";
|
|
121
|
+
|
|
122
|
+
const app = new Hono();
|
|
123
|
+
|
|
124
|
+
app.get("/login", async (c) => {
|
|
125
|
+
// Fetch screen configuration from your backend
|
|
126
|
+
const screen = await getLoginScreen();
|
|
127
|
+
const branding = await getBranding();
|
|
128
|
+
|
|
129
|
+
// Server-side render the widget
|
|
130
|
+
const widgetResult = await renderToString(
|
|
131
|
+
`<authhero-widget
|
|
132
|
+
screen='${JSON.stringify(screen).replace(/'/g, "'")}'
|
|
133
|
+
branding='${JSON.stringify(branding).replace(/'/g, "'")}'
|
|
134
|
+
auto-submit="true"
|
|
135
|
+
auto-navigate="true"
|
|
136
|
+
></authhero-widget>`,
|
|
137
|
+
{
|
|
138
|
+
fullDocument: false,
|
|
139
|
+
serializeShadowRoot: "declarative-shadow-dom",
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Return complete HTML page
|
|
144
|
+
return c.html(`
|
|
145
|
+
<!DOCTYPE html>
|
|
146
|
+
<html>
|
|
147
|
+
<head>
|
|
148
|
+
<meta charset="UTF-8">
|
|
149
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
150
|
+
<title>Login</title>
|
|
151
|
+
<script type="module" src="/widget/authhero-widget.esm.js"></script>
|
|
152
|
+
</head>
|
|
153
|
+
<body>
|
|
154
|
+
${widgetResult.html}
|
|
155
|
+
</body>
|
|
156
|
+
</html>
|
|
157
|
+
`);
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Edge Runtime Compatibility
|
|
162
|
+
|
|
163
|
+
The hydrate module works on edge runtimes like Cloudflare Workers. For compatibility, ensure the global `window` object exists:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Essential for some internal Stencil checks in edge runtimes
|
|
167
|
+
if (typeof globalThis.window === "undefined") {
|
|
168
|
+
globalThis.window = globalThis;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const { renderToString } = await import("@authhero/widget/hydrate");
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Avoiding Hydration Mismatches
|
|
175
|
+
|
|
176
|
+
To prevent hydration errors (where server and client HTML differ):
|
|
177
|
+
|
|
178
|
+
1. **Use the same data**: Ensure the `screen` and `branding` props match between server and client
|
|
179
|
+
2. **Avoid client-only conditionals**: Don't conditionally render based on `window` or browser APIs
|
|
180
|
+
3. **Serialize consistently**: Use the same JSON serialization on server and client
|
|
181
|
+
4. **Handle edge cases**: Escape special characters in JSON attributes (`'` → `'`)
|
|
182
|
+
|
|
183
|
+
### Performance Benefits
|
|
184
|
+
|
|
185
|
+
- **Instant Display**: Users see the login form immediately without waiting for JavaScript
|
|
186
|
+
- **Reduced Layout Shift**: Content dimensions are known from the server response
|
|
187
|
+
- **Better SEO**: Search engines can index the rendered content
|
|
188
|
+
- **Improved Core Web Vitals**: Lower LCP (Largest Contentful Paint) and CLS (Cumulative Layout Shift)
|
|
189
|
+
|
|
60
190
|
## UI Schema (Auth0 Forms API)
|
|
61
191
|
|
|
62
192
|
The widget renders UI based on Auth0's Forms API schema for universal login flows.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{p as a,b as e}from"./p-ARKBiJrR.js";export{s as setNonce}from"./p-ARKBiJrR.js";import{g as t}from"./p-DQuL1Twl.js";(()=>{const e=import.meta.url,t={};return""!==e&&(t.resourcesUrl=new URL(".",e).href),a(t)})().then((async a=>(await t(),e([["p-
|
|
1
|
+
import{p as a,b as e}from"./p-ARKBiJrR.js";export{s as setNonce}from"./p-ARKBiJrR.js";import{g as t}from"./p-DQuL1Twl.js";(()=>{const e=import.meta.url,t={};return""!==e&&(t.resourcesUrl=new URL(".",e).href),a(t)})().then((async a=>(await t(),e([["p-30808298",[[513,"authhero-node",{component:[16],value:[1],disabled:[4],passwordVisible:[32]}]]],["p-3ae71c86",[[513,"authhero-widget",{screen:[1],apiUrl:[1,"api-url"],baseUrl:[1,"base-url"],state:[1025],screenId:[1025,"screen-id"],authParams:[1,"auth-params"],statePersistence:[1,"state-persistence"],storageKey:[1,"storage-key"],branding:[1],theme:[1],loading:[1028],autoSubmit:[4,"auto-submit"],autoNavigate:[4,"auto-navigate"],_screen:[32],_authParams:[32],_branding:[32],_theme:[32],formData:[32]},null,{screen:[{watchScreen:0}],branding:[{watchBranding:0}],theme:[{watchTheme:0}],authParams:[{watchAuthParams:0}]}]]]],a))));
|