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

Add solid #3327

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open

Add solid #3327

wants to merge 17 commits into from

Conversation

Nvos
Copy link

@Nvos Nvos commented Jul 23, 2023

Resolves #3303

Summary

Add new urql-solid package implementing solid-js bindings.

Api is nearly same as for react/preact with difference being that some props are passed as union of value and accessor.

Set of changes

Adds following solid-js hooks

  • createQuery
  • createMutation
  • createSubscription

@Nvos
Copy link
Author

Nvos commented Jul 28, 2023

Seems that CI is failing on typecheck in project root, given that solid requires different jsx and jsxImportSource than react typecheck with current configuration will fail as solid package extends base tsconfig and base tsconfig includes all packages thus runs typecheck with jsx set to react and without jsxImportSource.

It might be good idea to run each sub package commands instead e.g. pnpm run -r {cmd} or use monorepo tools (turbo/nx) to run commands in sub packages.

Comment on lines 233 to 238
const got = unwrap(result);
if (got.fetching) {
return;
}

resolve(got);
Copy link
Member

Choose a reason for hiding this comment

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

I don't quite feel this will be the best approach to be honest. Especially, since the inputs can change while we're waiting to resolve a promise.

I also haven't checked this in detail, but I'm very hesitant to use this approach of resolving + re-triggering this as per the refetch call. This seems a little brittle to me.

You can see how the vue bindings do this:

const promise = new Promise<UseQueryState<T, V>>(resolve => {
if (!source.value) return resolve(state);
let hasResult = false;
sub = pipe(
source.value,
subscribe(() => {
if (!state.fetching.value && !state.stale.value) {
if (sub) sub.unsubscribe();
hasResult = true;
resolve(state);
}
})
);
if (hasResult) sub.unsubscribe();
});

The only difference is that we wouldn't necessarily want to check for stale. That depends on how background fetches should be handled.

Maybe it does make sense though to include this, since not using suspense would be the escape hatch here. But since in these bindings there's no concept of conditionally using the resource, it's likely better not to check for stale

The important part here is that the promise actually only reacts to the result. While the source isn't shared in the Vue implementation and instead relies on the semaphore logic in the Client, it's also fine to try to share it

Copy link
Author

@Nvos Nvos Aug 12, 2023

Choose a reason for hiding this comment

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

Tried to implement it in similar way as in vue, technically it seems to be working (you can take a look at 604c6a5). Thought after working a bit on it I'm not sure if this is good idea as it results in dependency on subscription order as subscription to fetch data has to be made before subscription in createResource fetcher.

Furthermore I'm not 100% sure if there wont be cases where order is different

Copy link
Author

Choose a reason for hiding this comment

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

Order should be fine after some testing I don't think there should be any edge cases

packages/solid-urql/src/createQuery.ts Outdated Show resolved Hide resolved
packages/solid-urql/src/createQuery.ts Outdated Show resolved Hide resolved
packages/solid-urql/src/createQuery.ts Outdated Show resolved Hide resolved
@kitten
Copy link
Member

kitten commented Aug 2, 2023

This is only a preliminary review, but I'll get back to the details once we get closer to having a final implementation. I'm fine with fixing up the Vitest and TypeScript configs to be inline with what we'd expect in this repo, but I'll get back to that closer to having it done as a last step ✌️

@Nvos
Copy link
Author

Nvos commented Aug 7, 2023

Thanks, will work on those comments this weekend

@Nvos
Copy link
Author

Nvos commented Sep 20, 2023

Is there anything else from my side to do to push this PR forward?

@kitten
Copy link
Member

kitten commented Sep 20, 2023

@Nvos: Hiya 👋 Sorry for the delay. Mainly, what I got stuck on here is the setup. While I haven't normalised, rebased and checked everything for discrepancies yet, I started with aligning some of the setup changes.

Firstly, the tsconfig changes are pretty trivial and we can even avoid JSX to not have to deal with it that often. React is a little special in that regards and Typescript doesn't have many great options to isolate builds without becoming the “sole/primary build tool”

Anyway, from a Vitest standpoint, the config for it for Solid should obviously not be a snowflake and unique. Having it all run as one thing (besides some of the E2E tests which are mostly to prevent common regressions instead; added as an experiment) would be neat.

That said, the tests are failing now and I don't have too much time right now to debug this myself (Sorry!)
One thing I discovered is that there's several waitFor checks that aren't await-ed properly. I didn't get rid of these in any test besides createQuery's.

When I'm looking at the tests triggering effects, the primary thing I'm noticing is that Solid's test framework lacks an act function or another mechanism of flushing effects. Even waiting for a random timeout or micro-tick doesn't seem to really convince it to consistently execute effects in a predictable manner that I'd expect from tests. It's a little puzzling.

On a side-note, we're missing a small change that tests that the createSubscription scan function actually executes. But that's a small detail.
Overall, I haven't tried this in a Vite sandbox, and set up an example yet, but from the tests, my confidence right now in them isn't particularly high until I can understand how Solid expects effects to flush in tests 😅

Here's a commit with the relevant changes: 584d58d

@Nvos
Copy link
Author

Nvos commented Sep 20, 2023

I aggree that having 1 vitest config is good, thought thought I still would like to have solid plugin in vitest instead of using solid-js/h maybe it would be good idea to merge main config if some changes are required:

// other imports...
import rootConfig from '../../vitest.config';

export default mergeConfig(
  rootConfig,
  defineProject({
    plugins: [solidPlugin()],
    test: {
      globals: true,
    },
  })
);

Though plugin is required only to handle JSX, we could remove those tests (those are only required to test suspense) and instead introduce some E2E tests via playwright/cypress. I could write playwright tests, as for cypres would require to do some research as didn't use it for long time now.

I'm not that proficient in writing unit tests in solid. Tests in this PR were based on my initial research. Though I noticed that there's test helper testEffect which might be what we need. I'll take a look at what we can do in regard to handling effects in tests this week.

In regard to:

That said, the tests are failing now and I don't have too much time right now to debug this myself (Sorry!)

Do you mean CI or tests were failing when running locally?

@changeset-bot
Copy link

changeset-bot bot commented Oct 2, 2023

⚠️ No Changeset found

Latest commit: 9d6836e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@Nvos
Copy link
Author

Nvos commented Oct 2, 2023

Updated all tests to use testEffect, it should be more reliable now.

Tried few things and as for now I'm not sure how to handle running test and check from repository root without larger changes as those do not respect configurations in nested packages.

Tried to change to use solid/h as you did on your branch but for some reason reactivity was not working inside components. Will take a look at it this weekend as it seems to be only way to use vitest.config from repository root

@Nvos
Copy link
Author

Nvos commented Oct 8, 2023

After some research I come to conclusion that with current setup it seems unlikely to run solid tests from project root via test script due to vite-plugin-solid seemingly being necessary to run hook tests (seems that createResource reads sharedConfig.context.id and context is never set without plugin). I have tried to handle this in 2 ways:

  • vitest workspaces - I'm not exactly sure why but it seems that dependencies are not resolved correctly when running solid tests inside vitest workspace. Will try to research it bit more
  • using vite-plugin-solid in main vitest.config.ts using plugin includes which doesn't work as well due to conflicting configurations which break preact and react tests: resolve.conditions and esbuild

From my perspective best way to handle such cases globally would be to switch from running tests via single config with includes to respective configs in sub-packages which could be ran by pnpm or preferably turbo. There could be single base config which could be used as default if there's no changes needed.

Another way could be handling solid-urql separately by excluding it from current config and running it along side current tests but this makes solid-urql special case which might not be preferable

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.

RFC: Add solid
2 participants