Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(astro,shared): Move functions that can be reused by different SDKs #3681

Closed

Conversation

wobsoriano
Copy link
Member

@wobsoriano wobsoriano commented Jul 9, 2024

Description

This PR tackles ECO-4 and aims to share functions that are currently being duplicated by official and community SDKs.

The ff. functions in the PR are present in the React SDK:

  1. loadClerkJsScript - Duplicated by the ff. community SDKs:

Our work-in-progress Clerk SDK approach and requirements requires Clerk to be hotloaded and having this function shared is a no brainer.

  1. deriveState - While different frameworks have different approaches to SSR, this function is also duplicated across SDKs (Vue, SvelteKit, Astro) and is used to set initial value of a user (data coming from server) even when Clerk is not yet loaded in the client.

All the shared functions above will initially be used by the Astro integration and adopted by different SDKs later.

Checklist

  • npm test runs as expected.
  • npm run build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Copy link

changeset-bot bot commented Jul 9, 2024

🦋 Changeset detected

Latest commit: 1235e8d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 15 packages
Name Type
@clerk/astro Patch
@clerk/shared Patch
@clerk/backend Patch
@clerk/chrome-extension Patch
@clerk/clerk-js Patch
@clerk/elements Patch
@clerk/clerk-expo Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/nextjs Patch
@clerk/clerk-react Patch
@clerk/remix Patch
@clerk/clerk-sdk-node Patch
@clerk/tanstack-start Patch
@clerk/testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

packages/shared/src/loadClerkJsScript.ts Dismissed Show dismissed Hide dismissed

const deriveFromSsrInitialState = (initialState: InitialState) => {
const userId = initialState.userId;
const user = initialState.user as UserResource;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to typecast some properties in this function?

Copy link
Member Author

@wobsoriano wobsoriano Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Thanks for pointing this out! It was adapted from the React SDK, and I maintained the original structure (including typecasts).

My guess is we want to narrow the types if InitialState is provided? And also some of them are typed as strings (i.e. orgRole, orgPermissions) and typecasting it just for semantics / future-proofihng? Maybe @panteliselef can help me answer this question 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked because then I think initialState should be typed correctly in the first place 😊

Maybe spend a little bit of time checking if we can fix this on a holistic level, otherwise the type-casts will be fine for now (if other things break)

packages/shared/src/loadClerkJsScript.ts Show resolved Hide resolved
test(astro): Test script loader version

test(astro): Add main script loader test
@wobsoriano wobsoriano force-pushed the rob/eco-4-move-or-use-utilities-from-clerkshared branch from edc52b1 to 401cc89 Compare July 10, 2024 19:34
Copy link
Member Author

@wobsoriano wobsoriano Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is extracted directly from the React SDK. The only difference is that the versionSelector is removed, which may not be needed for most cases in other SDKs (?) and uses a compile-time env variable (PACKAGE_VERSION).

I'm thinking of putting it back and it moving to shared as well, but remove the compile-time variable. What do you think @LekoArts @panteliselef?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loadClerkJsScript function needs to behave exactly like the the React SDK one, including the versionSelector functionality. Otherwise things like our snapshot command won't work since the SDK will load the incorrect version of clerk-js on the client.

With some changes it'll also ensure that the correct major version of clerk-js is loaded for the major version of the SDK. With the current hardcoded 5 version you could run into the problem of mismatched versions.

If versionSelector is moved to the shared package we'll need to change the packageVersion = PACKAGE_VERSION fallback in the args and most likely need to change it to JS_PACKAGE_VERSION. Test this!
Reason: clerk-react currently has the same major version as clerk-js, so the logic is sound here. But shared is separate from that, so we should probably replace it to that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking some time to answer this @LekoArts! This makes sense to me.

I have a question for this one - is there gonna be a time that clerk-js and clerk-react will have different versions (other than snapshots)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the fact that versionSelector will be framework specific i think we need to come up with a better way of setting it. I believe each framework should be able to specific its own logic.

@wobsoriano It could happen, for example let's say we wanna a new major for clerk-react because we are switching to react19 and using some of the new features. In that scenario we wouldn't have to cut a new major for clerk-js.

Comment on lines -282 to -285
if (__HOTLOAD__) {
controller.enqueue(hotloadScript);
}

Copy link
Member Author

@wobsoriano wobsoriano Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are no longer attaching the hotload script to the Response since we're using the loadClerkJsScript shared function in client instead.

If for some reason the current implementation is performant than this one, we can adjust to 3-4 commits back where I only used the script builders to clean up some repeating logic but still build the hotload script on the server

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely prefer the current implementation because it will result in faster loading times.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can still use loadClerkJsScript in the client but we will expect to read the existing script.

@wobsoriano wobsoriano marked this pull request as ready for review July 11, 2024 02:45
packages/astro/src/client/index.ts Outdated Show resolved Hide resolved
@@ -14,7 +17,10 @@ export const createClerkInstance = runOnce(createClerkInstanceInternal);
export async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams) {
let clerkJSInstance = window.Clerk;
if (!clerkJSInstance) {
await waitForClerkScript();
await loadClerkJsScript({
clerkJSVersion: HARDCODED_LATEST_CLERK_JS_VERSION,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to remove this, I'll explain it in https://github.com/clerk/javascript/pull/3681/files#r1672868119

await waitForClerkScript();
await loadClerkJsScript({
clerkJSVersion: HARDCODED_LATEST_CLERK_JS_VERSION,
...(options as any),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The as any is a code smell, ideally the options has the correct type, could be a footgun in the future

proxyUrl: paramProxy || import.meta.env.PUBLIC_ASTRO_APP_CLERK_PROXY_URL,
domain: paramDomain || import.meta.env.PUBLIC_ASTRO_APP_CLERK_DOMAIN,
publishableKey: paramPublishableKey || import.meta.env.PUBLIC_ASTRO_APP_CLERK_PUBLISHABLE_KEY || '',
// eslint-disable-next-line turbo/no-undeclared-env-vars
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Use block comments (https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) because then it's more concise


const deriveFromSsrInitialState = (initialState: InitialState) => {
const userId = initialState.userId;
const user = initialState.user as UserResource;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked because then I think initialState should be typed correctly in the first place 😊

Maybe spend a little bit of time checking if we can fix this on a holistic level, otherwise the type-casts will be fine for now (if other things break)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loadClerkJsScript function needs to behave exactly like the the React SDK one, including the versionSelector functionality. Otherwise things like our snapshot command won't work since the SDK will load the incorrect version of clerk-js on the client.

With some changes it'll also ensure that the correct major version of clerk-js is loaded for the major version of the SDK. With the current hardcoded 5 version you could run into the problem of mismatched versions.

If versionSelector is moved to the shared package we'll need to change the packageVersion = PACKAGE_VERSION fallback in the args and most likely need to change it to JS_PACKAGE_VERSION. Test this!
Reason: clerk-react currently has the same major version as clerk-js, so the logic is sound here. But shared is separate from that, so we should probably replace it to that

packages/shared/src/loadClerkJsScript.ts Dismissed Show dismissed Hide dismissed
packages/shared/src/versionSelector.ts Dismissed Show dismissed Hide dismissed
Copy link
Member Author

@wobsoriano wobsoriano Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @LekoArts suggested here, the loadClerkJsScript should behave the same way like the React SDK (with the use of versionSelector) because commands like snapshot won't work since the SDK will load an incorrect version of clerk-js.

The default packageVersion prop is now set to the clerk-js version (JS_PACKAGE_VERSION) instead of the clerk-react version (PACKAGE_VERSION).

With this, all SDKs should use the same clerk-js version, unless clerkJsVersion is provided. Thanks!

@wobsoriano wobsoriano marked this pull request as draft July 11, 2024 20:57
@wobsoriano
Copy link
Member Author

Closing this but it will be tackled in the future at a more relaxing pace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants