Skip to content

Commit a3ecc79

Browse files
committed
chore(astro): Clean up scripts
1 parent 5196122 commit a3ecc79

File tree

2 files changed

+122
-52
lines changed

2 files changed

+122
-52
lines changed

packages/astro/src/integration/create-integration.ts

Lines changed: 22 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
import type { ClerkOptions } from '@clerk/types';
1+
import type { ClerkOptions } from '@clerk/shared/types';
22
import type { AstroIntegration } from 'astro';
33
import { envField } from 'astro/config';
44

55
import { name as packageName, version as packageVersion } from '../../package.json';
66
import type { AstroClerkIntegrationParams } from '../types';
7+
import { buildBeforeHydrationSnippet, buildPageLoadSnippet } from './snippets';
78
import { vitePluginAstroConfig } from './vite-plugin-astro-config';
89

9-
const buildEnvVarFromOption = (valueToBeStored: unknown, envName: keyof InternalEnv) => {
10-
return valueToBeStored ? { [`import.meta.env.${envName}`]: JSON.stringify(valueToBeStored) } : {};
11-
};
12-
1310
type HotloadAstroClerkIntegrationParams = AstroClerkIntegrationParams & {
1411
clerkJSUrl?: string;
1512
clerkJSVariant?: 'headless' | '';
1613
clerkJSVersion?: string;
1714
enableEnvSchema?: boolean;
1815
};
1916

17+
const buildEnvVarFromOption = (valueToBeStored: unknown, envName: keyof InternalEnv) => {
18+
return valueToBeStored ? { [`import.meta.env.${envName}`]: JSON.stringify(valueToBeStored) } : {};
19+
};
20+
2021
function createIntegration<Params extends HotloadAstroClerkIntegrationParams>() {
2122
return (params?: Params): AstroIntegration => {
2223
const { proxyUrl, isSatellite, domain, signInUrl, signUpUrl, enableEnvSchema = true } = params || {};
@@ -95,63 +96,32 @@ function createIntegration<Params extends HotloadAstroClerkIntegrationParams>()
9596
*/
9697

9798
/**
98-
* The above script will run before client frameworks like React hydrate.
99+
* The before-hydration script will run before client frameworks like React hydrate.
99100
* This makes sure that we have initialized a Clerk instance and populated stores in order to avoid hydration issues.
100101
*/
101102
injectScript(
102103
'before-hydration',
103-
`
104-
${command === 'dev' ? `console.log('${packageName}',"Initialize Clerk: before-hydration")` : ''}
105-
import { runInjectionScript } from "${buildImportPath}";
106-
await runInjectionScript(${JSON.stringify(internalParams)});`,
104+
buildBeforeHydrationSnippet({
105+
command,
106+
packageName,
107+
buildImportPath,
108+
internalParams,
109+
}),
107110
);
108111

109112
/**
110-
* The above script only executes if a client framework like React needs to hydrate.
111-
* We need to run the same script again for each page in order to initialize Clerk even if no UI framework is used in the client
112-
* If no UI framework is used in the client, the above script with `before-hydration` will never run
113+
* The page script only executes if a client framework like React needs to hydrate.
114+
* We need to run the same script again for each page in order to initialize Clerk even if no UI framework is used in the client.
115+
* If no UI framework is used in the client, the before-hydration script will never run.
113116
*/
114-
115117
injectScript(
116118
'page',
117-
`
118-
${command === 'dev' ? `console.log("${packageName}","Initialize Clerk: page")` : ''}
119-
import { runInjectionScript, swapDocument } from "${buildImportPath}";
120-
121-
// Taken from https://github.com/withastro/astro/blob/e10b03e88c22592fbb42d7245b65c4f486ab736d/packages/astro/src/transitions/router.ts#L39.
122-
// Importing it directly from astro:transitions/client breaks custom client-side routing
123-
// even when View Transitions is disabled.
124-
const transitionEnabledOnThisPage = () => {
125-
return !!document.querySelector('[name="astro-view-transitions-enabled"]');
126-
}
127-
128-
if (transitionEnabledOnThisPage()) {
129-
// We must do the dynamic imports within the event listeners because otherwise we may race and miss initial astro:page-load
130-
document.addEventListener('astro:before-swap', async (e) => {
131-
const { swapFunctions } = await import('astro:transitions/client');
132-
133-
const clerkComponents = document.querySelector('#clerk-components');
134-
// Keep the div element added by Clerk
135-
if (clerkComponents) {
136-
const clonedEl = clerkComponents.cloneNode(true);
137-
e.newDocument.body.appendChild(clonedEl);
138-
}
139-
140-
e.swap = () => swapDocument(swapFunctions, e.newDocument);
141-
});
142-
143-
document.addEventListener('astro:page-load', async (e) => {
144-
const { navigate } = await import('astro:transitions/client');
145-
146-
await runInjectionScript({
147-
...${JSON.stringify(internalParams)},
148-
routerPush: navigate,
149-
routerReplace: (url) => navigate(url, { history: 'replace' }),
150-
});
151-
})
152-
} else {
153-
await runInjectionScript(${JSON.stringify(internalParams)});
154-
}`,
119+
buildPageLoadSnippet({
120+
command,
121+
packageName,
122+
buildImportPath,
123+
internalParams,
124+
}),
155125
);
156126
},
157127
'astro:config:done': ({ injectTypes }) => {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import type { ClerkOptions } from '@clerk/shared/types';
2+
3+
/**
4+
* Creates a snippet that initializes Clerk before client-side framework hydration occurs.
5+
*
6+
* This script runs before frameworks like React, Vue, or Svelte hydrate their components,
7+
* ensuring the Clerk instance is ready and stores are populated to prevent hydration mismatches.
8+
* It performs a simple, synchronous initialization without handling view transitions.
9+
*
10+
* @param command - The Astro command being run ('dev' or 'build')
11+
* @param packageName - The name of the Clerk package for debug logging
12+
* @param buildImportPath - The import path to the internal Clerk utilities
13+
* @param internalParams - Clerk configuration options including SDK metadata
14+
* @returns A script string to be injected via Astro's 'before-hydration' stage
15+
*/
16+
export function buildBeforeHydrationSnippet({
17+
command,
18+
packageName,
19+
buildImportPath,
20+
internalParams,
21+
}: {
22+
command: string;
23+
packageName: string;
24+
buildImportPath: string;
25+
internalParams: ClerkOptions;
26+
}) {
27+
return `
28+
${command === 'dev' ? `console.log("${packageName}","Initialize Clerk: before-hydration")` : ''}
29+
import { runInjectionScript } from "${buildImportPath}";
30+
await runInjectionScript(${JSON.stringify(internalParams)});`;
31+
}
32+
33+
/**
34+
* Creates a snippet that initializes Clerk on page load with support for Astro View Transitions.
35+
*
36+
* This script handles two scenarios:
37+
* 1. **With View Transitions enabled**: Listens for astro:page-load and astro:before-swap events
38+
* to properly initialize Clerk and preserve its DOM elements during page transitions.
39+
* 2. **Without View Transitions**: Performs standard initialization on initial page load.
40+
*
41+
* This script is necessary for pages without client-side frameworks, as the before-hydration
42+
* script only runs when framework hydration occurs. This ensures Clerk is always initialized,
43+
* regardless of whether UI frameworks are present.
44+
*
45+
* @param command - The Astro command being run ('dev' or 'build')
46+
* @param packageName - The name of the Clerk package for debug logging
47+
* @param buildImportPath - The import path to the internal Clerk utilities
48+
* @param internalParams - Clerk configuration options including SDK metadata
49+
* @returns A script string to be injected via Astro's 'page' stage
50+
*/
51+
export function buildPageLoadSnippet({
52+
command,
53+
packageName,
54+
buildImportPath,
55+
internalParams,
56+
}: {
57+
command: string;
58+
packageName: string;
59+
buildImportPath: string;
60+
internalParams: ClerkOptions;
61+
}) {
62+
return `
63+
${command === 'dev' ? `console.log("${packageName}","Initialize Clerk: page")` : ''}
64+
import { runInjectionScript, swapDocument } from "${buildImportPath}";
65+
66+
// Taken from https://github.com/withastro/astro/blob/e10b03e88c22592fbb42d7245b65c4f486ab736d/packages/astro/src/transitions/router.ts#L39.
67+
// Importing it directly from astro:transitions/client breaks custom client-side routing
68+
// even when View Transitions is disabled.
69+
const transitionEnabledOnThisPage = () => {
70+
return !!document.querySelector('[name="astro-view-transitions-enabled"]');
71+
}
72+
73+
if (transitionEnabledOnThisPage()) {
74+
// We must do the dynamic imports within the event listeners because otherwise we may race and miss initial astro:page-load
75+
document.addEventListener('astro:before-swap', async (e) => {
76+
const { swapFunctions } = await import('astro:transitions/client');
77+
78+
const clerkComponents = document.querySelector('#clerk-components');
79+
// Keep the div element added by Clerk
80+
if (clerkComponents) {
81+
const clonedEl = clerkComponents.cloneNode(true);
82+
e.newDocument.body.appendChild(clonedEl);
83+
}
84+
85+
e.swap = () => swapDocument(swapFunctions, e.newDocument);
86+
});
87+
88+
document.addEventListener('astro:page-load', async (e) => {
89+
const { navigate } = await import('astro:transitions/client');
90+
91+
await runInjectionScript({
92+
...${JSON.stringify(internalParams)},
93+
routerPush: navigate,
94+
routerReplace: (url) => navigate(url, { history: 'replace' }),
95+
});
96+
})
97+
} else {
98+
await runInjectionScript(${JSON.stringify(internalParams)});
99+
}`;
100+
}

0 commit comments

Comments
 (0)