Skip to content
This repository was archived by the owner on Dec 10, 2024. It is now read-only.

feat: Attempt to bring back virtual modules #144

Merged
merged 3 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/spotty-books-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro-clerk-auth": patch
---

Experiment with virtual modules
2 changes: 1 addition & 1 deletion apps/playground-with-package/src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const { title } = Astro.props;

import { Image } from "astro:assets";
import logo from "../assets/Clerk-Purple-Logo.png";
import { SignedIn, SignedOut } from "astro-clerk-auth/components/control";
import { SignedIn, SignedOut } from "astro-clerk-auth/components/react";
import { UserButton } from "astro-clerk-auth/components/interactive";
import { LanguagePicker } from "../components/LanguagePicker";
import GithubIcon from "../components/GithubIcon.astro";
Expand Down
20 changes: 10 additions & 10 deletions apps/playground-with-package/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import Install from "../components/Install.astro";

<Layout title="Welcome to Astro.">
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
<SignedIn>
<OrganizationSwitcher
appearance={{
elements: {
organizationPreview__organizationSwitcherTrigger: "text-white",
organizationSwitcherTriggerIcon: "text-white",
},
}}
afterSelectOrganizationUrl="/organization"
/>
<SignedIn>
<OrganizationSwitcher
appearance={{
elements: {
organizationPreview__organizationSwitcherTrigger: "text-white",
organizationSwitcherTriggerIcon: "text-white",
},
}}
afterSelectOrganizationUrl="/organization"
/>
<SignOutButton />
</SignedIn>

Expand Down
49 changes: 19 additions & 30 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 2 additions & 12 deletions packages/astro-clerk-auth/src/client/react/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
import type { Store, StoreValue } from 'nanostores';
import { useCallback, useSyncExternalStore } from 'react';
import { $authStore, $clerk, $csrState } from '../../stores/internal';
import { authAsyncStorage } from '../../server/async-local-storage';
import { getClerkAuthInitState } from 'clerk:astro';

type CheckAuthorizationSignedOut = undefined;
type CheckAuthorizationWithoutOrgOrUser = (params?: Parameters<CheckAuthorizationWithCustomPermissions>[0]) => false;
Expand Down Expand Up @@ -251,16 +251,6 @@ function useStore<T extends Store, SV extends StoreValue<T>>(store: T): SV {
* If you omit this argument, rendering the component on the server will throw an error.
*/

/**
* When this runs on the server we want to grab the content from the async-local-storage.
*/
if (typeof window === 'undefined') {
return authAsyncStorage.getStore();
}

/**a
* When this runs on the client, during hydration, we want to grab the content the store.
*/
return get();
return getClerkAuthInitState() as SV;
});
}
8 changes: 8 additions & 0 deletions packages/astro-clerk-auth/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ interface ImportMetaEnv {
interface ImportMeta {
readonly env: ImportMetaEnv;
}

declare module 'virtual:astro-clerk/internal/als' {
export const authAls: import('node:async_hooks').AsyncLocalStorage<import('astro-clerk-auth/server').GetAuthReturn>;
}

declare module 'clerk:astro' {
export const getClerkAuthInitState: () => import('astro-clerk-auth/server').GetAuthReturn;
}
60 changes: 60 additions & 0 deletions packages/astro-clerk-auth/src/integration/create-integration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,43 @@
import type { AstroClerkIntegrationParams } from '../types';
import type { AstroIntegration } from 'astro';
import { name as packageName, version as packageVersion } from '../../package.json';
import type { Plugin } from 'vite';

const VI_INTERNAL_ALS_ID = 'virtual:astro-clerk/internal/als';
const VI_ID = 'clerk:astro';

export default function virtualImport({
nameCount,
id: virtualModuleId,
content,
context,
}: {
nameCount: number;
id: string;
content: string;
context: string;
}): Plugin {
const resolvedVirtualModuleId = '\0' + virtualModuleId;

return {
name: `astro-clerk-${nameCount}`, // required, will show up in warnings and errors
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id, options) {
if (id === resolvedVirtualModuleId) {
const _context = options?.ssr ? 'server' : 'client';

if (context === _context) {
return content;
}
}
return;
},
};
}

const buildEnvVarFromOption = (valueToBeStored: unknown, envName: string) => {
return valueToBeStored ? { [`import.meta.env.${envName}`]: JSON.stringify(valueToBeStored) } : {};
Expand Down Expand Up @@ -59,6 +96,29 @@ function createIntegration<P extends { mode: 'hotload' | 'bundled' }>({ mode }:
...buildEnvVarFromOption(clerkJSVersion, 'PUBLIC_ASTRO_APP_CLERK_JS_VERSION'),
__HOTLOAD__: mode === 'hotload',
},
plugins: [
virtualImport({
nameCount: 1,
id: VI_INTERNAL_ALS_ID,
content: `import { AsyncLocalStorage } from "node:async_hooks"; export const authAls = new AsyncLocalStorage();`,
context: 'server',
}),
virtualImport({
nameCount: 2,
id: VI_ID,
content: `import { authAls } from ${JSON.stringify(VI_INTERNAL_ALS_ID)};
export const getClerkAuthInitState = () => authAls.getStore();`,
context: 'server',
}),
virtualImport({
nameCount: 3,
id: VI_ID,
content: `
const auth = JSON.parse(document.getElementById('__CLERK_ASTRO_DATA__')?.textContent || '{}');
export const getClerkAuthInitState = () => auth`,
context: 'client',
}),
],

// We need this for top-level await
optimizeDeps: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { CreateClerkInstanceInternalFn } from '../client/types';
import { $initialState } from '../stores/internal';
import { AstroClerkIntegrationParams } from '../types';
import { mergeEnvVarsWithParams } from './merge-env-vars-with-params';
import { getClerkAuthInitState } from 'clerk:astro';

function createInjectionScriptRunner(creator: CreateClerkInstanceInternalFn) {
async function runner(astroClerkOptions?: AstroClerkIntegrationParams) {
const ssrDataContainer = document.getElementById('__CLERK_ASTRO_DATA__');
if (ssrDataContainer) {
$initialState.set(JSON.parse(ssrDataContainer.textContent || '{}'));
}
// Sync SSR initState to the store
// @ts-ignore missing user, organization, session objects but this is expected
$initialState.set(getClerkAuthInitState());

await creator(mergeEnvVarsWithParams(astroClerkOptions));
}
Expand Down
12 changes: 0 additions & 12 deletions packages/astro-clerk-auth/src/server/async-local-storage.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/astro-clerk-auth/src/server/clerk-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { APIContext } from 'astro';
import { createCurrentUser } from './current-user';
import { isRedirect, setHeader } from './utils';
import { serverRedirectWithAuth } from './server-redirect-with-auth';
import { authAsyncStorage } from './async-local-storage';
import { authAls } from 'virtual:astro-clerk/internal/als';
import { buildClerkHotloadScript } from './build-clerk-hotload-script';

const CONTROL_FLOW_ERROR = {
Expand Down Expand Up @@ -80,7 +80,7 @@ export const clerkMiddleware: ClerkMiddleware = (...args: unknown[]): any => {
* For React component, in order to avoid hydration errors populate SSR store and do not depend on the component being wrapped ClerkLayout.
* For now this is only needed for control components like SignedIn/SignedOut
*/
return authAsyncStorage.run(context.locals.auth(), async () => {
return authAls.run(context.locals.auth(), async () => {
/**
* Generate SSR page
*/
Expand Down
6 changes: 0 additions & 6 deletions packages/astro-clerk-auth/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,3 @@ export { createRouteMatcher } from './route-matcher';
* This will be used to define types of Astro.Locals inside `env.d.ts`
*/
export type { GetAuthReturn } from './get-auth';

/**
* Export async storage for astro component to use directly
*/
import { authAsyncStorage } from '../server/async-local-storage';
export const __internal_authAsyncStorage = authAsyncStorage;
2 changes: 1 addition & 1 deletion packages/astro-clerk-auth/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export default defineConfig(() => {
bundle: true,
sourcemap: true,
format: ['esm'],
external: ['astro', 'react', 'react-dom', 'node:async_hooks'],
external: ['astro', 'react', 'react-dom', 'clerk:astro', 'virtual:astro-clerk'],
};
});
Loading