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

Define how devs import components and functions #1154

Closed
frehner opened this issue Apr 29, 2022 · 7 comments
Closed

Define how devs import components and functions #1154

frehner opened this issue Apr 29, 2022 · 7 comments
Labels
bug Something isn't working

Comments

@frehner
Copy link
Contributor

frehner commented Apr 29, 2022

Related to #896 and recent discussions, we need to clearly define

  1. what exports for hydrogen look like,
  2. reduce the duplication, and
  3. set a standard for what we want the developer experience to be

In our initial discussions on solving this, we ran into problems: for one example, if we import from @shopify/hydrogen/client, does that mean that:

  • These are "RSC client components/hooks", which can be imported from both server and client components
  • These are "components/hooks that only work in the client environment", which means these will not work when you import them in server components

Additional questions/context:

  • A pure JS function that is meant to be used in the client could be exported as part of /client, but that function will not work when imported in a server function. So would we need to create a separate export for components vs hooks/JS functions?
  • If /client means "only works in the client env", then RSC client components cannot be exposed from /client because you can import an RSC client component in the server
  • Does any of this change when thinking about hydrogen and/or hydrogen-ui?

Tagging @blittle

@frehner frehner added the bug Something isn't working label Apr 29, 2022
@frehner frehner changed the title Define package exports Define how devs import components and functions Apr 29, 2022
@frehner
Copy link
Contributor Author

frehner commented Apr 30, 2022

Also @mcvinci and @gfscott would like to know your thoughts on this too.

@mcvinci
Copy link
Contributor

mcvinci commented Apr 30, 2022

@frehner I'm not sure if this is still a valid approach that we can take, but I really liked @jplhomer's suggestion about just telling developers to import everything from @shopify/hydrogen. From what I understand, on our end, we could use a transformation plugin to rewrite to /client on the fly.

If we can take away the decision-making of having developers choose between @shopify/hydrogen and @shopify/hydrogen/client, I think we'd be making vast improvements to the developer experience, and significantly simplifying their lives as they build on Hydrogen. This section in the docs (which is still relatively confusing!) also wouldn't need to exist. 😄

Having/client mean that these are RSC client components/hooks that can be imported from both server and client components feels the most intuitive to me. It also seems like it's a more flexible approach to take, in that there are fewer constraints when importing in server components. I recognize that there are complexities with this approach as well, of course -- and I probably don't have enough context to comment on this meaningfully. 😅

For whatever direction we choose to take, I think there's an opportunity here as well to improve our error messaging when it comes to importing functionality in Hydrogen. Surfacing constraints and limitations, and providing avenues to solve problems (potentially by linking to a "troubleshooting" section in the docs), in-context of building on Hydrogen, will be critical to developer success.

@gfscott
Copy link
Contributor

gfscott commented May 2, 2022

Re the desired developer experience, I agree with the approach of always trying to follow the same import pattern:

import { thing } from '@shopify/hydrogen'

I recently had cause to use Keystone and I found its approach to imports challenging, precisely because it splits them up as separate concerns, so you end up with a situation like:

import { config } from '@keystone-6/core'
import { a, b, c } from '@keystone-6/fields'
import { x, y z } from '@keystone-6/fields-document'
import { imageStuff } from '@keystone-6/cloudinary'

So now instead of one discovery layer — what { things } can I import? — I now have two. What can I import, and from where? And figuring that out can be quite a chore. I think it reduces the cognitive load and the documentation complexity if you're always just importing from Hydrogen, without having to worry about spelunking the project file structures. (Intellisense could, I suppose, lighten the load here, but better IMO to cut out the need for it in the first place.)

There's surely some overhead in making this approach a reality, but I think it's preferable to move the necessary complexity into Hydrogen, instead of externalizing it to the user.

While we're on the subject, would love to think about how we make that first discovery layer (import { what_can_I_import? }) intuitive and helpful.

@frehner
Copy link
Contributor Author

frehner commented May 2, 2022

Would it be correct to say it sounds like both of you are less concerned about whether an import works or not (e.g. "if I import a server component in a client component it breaks, so help me prevent that") and that we should focus more on just importing everything from a single place to lessen the cognitive load on figuring out where to import from?

@gfscott
Copy link
Contributor

gfscott commented May 2, 2022

I'd agree with that. In practice, import discovery can be quite ambiguous and dispersed, and leans heavily on documentation and tutorial content, so whatever we can do to reduce complexity up front is worthwhile.

In contrast, component breakage is obvious and immediate — you'll see it right away in your browser, dev tools, and terminal, and we can build error patterns across all those surfaces that make debugging, diagnosis, and recovery easier.

@mcvinci
Copy link
Contributor

mcvinci commented May 2, 2022

I'd agree as well, and +1 to Graham's thoughts!

@frehner
Copy link
Contributor Author

frehner commented May 2, 2022

One additional consideration:

Currently, RSC relies on the fact that client components end in client.js and server components end in server.js and shared components end in .js. This is an area that there has been a lot of back and forth, but in the end that is what the current status is.

If we have to follow that convention, then having a single import path like

import {ClientComp, ServerComp} from '@shopify/hydrogen'

either doesn’t work or requires additional tooling in order to get working correctly. So for the time being it may not even be feasible to have a “single” import path, or may not be possible for GA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants