-
Notifications
You must be signed in to change notification settings - Fork 324
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
Refactor [breaking change]: Separate hydrogen UI into own package #628
Conversation
@@ -1,9 +1,8 @@ | |||
{ | |||
"lerna": "4.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer needed in v4
"packages": [ | ||
"packages/*" | ||
], | ||
"version": "0.10.1", | ||
"version": "independent", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HUI is going to be versioned completely different than the rest, so this is necessary.
@@ -0,0 +1,20 @@ | |||
import {StrictMode} from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mainly just a thing from Vite, we can remove this file if we want.
"name": "@shopify/hydrogen-ui", | ||
"version": "2022.04.0-alpha", | ||
"description": "Components for modern custom Shopify storefronts", | ||
"homepage": "https://github.com/Shopify/hydrogen#readme", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Above this comment: placeholders
], | ||
"main": "./dist/hydrogen-ui.umd.min.js", | ||
"module": "./dist/hydrogen-ui.es.min.js", | ||
"exports": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package exports!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you get this working with Jest and TypeScript 😮
We have this PR Shopify/hydrogen#263 that is blocked by those two. I've recently found some kind of unofficial resolver for Jest that works with package exports, I should try that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For TS, in my very simple example the types were working correctly when using H-UI in the example repo. This is because I defined a types
property in package.json, and TS will use that to look for typedefs. No need for TS to understand package exports in this case.
However, based on the conversation below about getting more complex with our package exports, I'll have to test this again once we have separate builds (assuming that's the route we go), to see if we can still get that to work or not.
Regarding Jest, I didn't test that. Would Jest necessarily need to understand package exports, or could people mock out the H-UI package to get around that? (And for tests within H-UI itself, all the file resolution would just be relative paths, right? ...I'm probably missing something, though)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About Jest, if you import any component from H-UI in your app, Jest won't know how to resolve it. So you can only test your app if you mock all H-UI components, which is a lot and maybe misses the point of testing 🤔
In any case, I think we could try https://github.com/k-g-a/jest-node-exports-resolver
} | ||
}, | ||
"types": "types/index.d.ts", | ||
"sideEffects": false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VERY important to get tree shaking to work. As we add components, we'll have to go through them and make sure to add them to an array here, if they have side effects. (Note: things inside of useEffect()
are fine, this is more about global side effects such as adding to window
or something like that. e.g. Boomerang stuff?)
"resolveJsonModule": true, | ||
"isolatedModules": true, | ||
"declaration": true, | ||
"emitDeclarationOnly": true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have TS only emit declarations; the rest of the work is done by Vite.
"isolatedModules": true, | ||
"declaration": true, | ||
"emitDeclarationOnly": true, | ||
"declarationDir": "./types", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little bit easier to put the compiled types into a types/
folder than into the dist/
folder, since Vite cleans the dist folder on build. I could change that up, and put it all into the dist/ folder, but this was easier in the moment. Not a big deal to change up if so desired.
@@ -35,6 +35,7 @@ | |||
"dependencies": { | |||
"@headlessui/react": "^1.4.1", | |||
"@shopify/hydrogen": "^0.10.1", | |||
"@shopify/hydrogen-ui": "^2022.04.0-alpha", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just testing that this worked, and it does. Currently it doesn't do anything in the PR because I removed that code.
@@ -0,0 +1,12 @@ | |||
<!DOCTYPE html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In conjunction with the ComponentPlayground file above; can be removed.
"homepage": "https://github.com/Shopify/hydrogen#readme", | ||
"license": "MIT", | ||
"engines": { | ||
"node": ">=14" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably move this to 16?
packages/hydrogen-ui/package.json
Outdated
"module": "./dist/hydrogen-ui.es.min.js", | ||
"exports": { | ||
".": { | ||
"import": "./dist/hydrogen-ui.es.min.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to have "prod" and "dev" builds for this library? I can make that work if we want to, but for the time being I just left it as a prod build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 super great. I really appreciate the time you put into documenting this PR with comments 😍
+1 to what Josh said. Those comments are really considerate and helped me a lot. Thanks! |
@frehner Great, excited to see progress on this! And thanks so much for the comments! Perhaps it's is just because this is an empty boilerplate but it seems this intends to bundle all components in That wouldn't work in RSC because it depends on file extensions ( An alternative would be bundling in 1 file for other non-RSC frameworks but provide a different import path that gets the source files so we can use them in Hydrogen framework. Maybe we can even use an alias in the framework so it's transparent to users ( |
You're correct.
This is interesting, and I honestly don't know if it's been figured out yet or not. Does the community at large have an answer to this question? For example, are any other UI libraries bundling for RSC, and if so, what are they doing and how are they doing it? When looking at the RFC, one specific section seems to be called out as a potential solution to this (and a more detailed section below that): a conditional packages exports called The example they have there: "exports": {
".": {
"react-server": {
"browser": "./debugger-polyfill.server.js",
"node": "./native-impl.server.js"
},
"default": {
"browser": "./browser-impl.client.js",
"node": "./node-polyfill.client.js"
}
}
} Here's my interpretation of that doc and the files, let me know if you think I've gone wrong anywhere: We would make two different bundles: a
With all that said... does this seem like it would work? Is that the correct path forward? Would love your thoughts @frandiox @jplhomer (and anyone else) Side note regarding this custom |
Yeah, that makes sense @frehner. This is definitely an untrodden path, so it's on us to come up with some opinions that will help inform the React ecosystem at large. A couple thoughts:
|
Agreed. All of this is new ground. I don't think anyone substantial in the community is yet building for RSC. I think we should explore some of the ideas here and answer the questions. Then come up with community guidelines. |
We should still be able to build out to multiple files; it's just not what Vite does by default (and what I have happening now). But by getting into the Rollup config through Vite, I'm pretty sure I can get that working fairly easily and this won't be a concern. (To clarify: we'll still have a single entry point file for .server and .client, but each component will be separated out into their own files from there)
I think if we need to explore this route, that we can use package export paths ( If I'm understanding you correctly here. |
This is my last update on this for a bit, since our plan has changed and this work will be shelved for a tiny bit. I made some updates to this PR, to work with different package exports for server/client. My initial impression is that, instead of trying to be magical, we can perhaps be more specific and have our package exports be like With this setup with have two different entry points, and two different outputs: Anyway, with this latest commit the static values are correctly imported, but ESLint doesn't like it so we have to put eslint ignore comments there. The components that I import, however, appear to potentially be breaking by our Vite plugin; I get this error:
Anyway, not something I don't think we have to pay attention to at the moment, since this is being put on the backburner for a bit. As noted above in another comment I had with Fran, with this updated setup the TS types don't work yet either; that relies on TS support for package exports. (It was working before with a single file build, but that's not valid for us here now) Anyway, fun times. Gives me something to think about as I work on other things for a bit. |
For the record, our implementation of RSC + Vite is not relying on Node's conditions (
That's why relying on package exports and Node conditions is not an option unless we change how our RSC+Vite implementation works. There's more information about all of this here. Aside from that, we are using Vite's glob imports to find all the client components in the filesystem. We need to pass the path to hydrogen-ui to the RSC plugin here. After analyzing the content of this path, Vite will create separate bundles for every file that matches
I think you are getting that error because even though the server has imported and generated component IDs, the client doesn't have a proper Vite import map. You'll need to provide |
Makes sense, I agree. I didn't really like that solution either when I started working on it on the package side of things.
To be clear, when you say "source code" are you referring to the actual, original source files? If so: is that a sustainable practice for when libraries start getting built specifically for RSC? In other words, the node ecosystem very rarely publishes the actual source code to npm, and instead publishes compiled code; would RSC libraries have to change that to where they publish their source code to npm?
Yeah, agreed again that package exports AND node conditions just doesn't seem right here. To be clear, though, package exports themselves should still be ok, right? All they really do is just map a name to a file, so I'm not sure why we wouldn't want to support that.
Let me see if I understand this correctly: every library that supports RSC would have to be manually pass their path to our plugin in order to work correctly? If so: is that sustainable in the long-term? But I could be completely misunderstanding here.
Ok, so I do provide a Thanks Fran, I appreciate all your feedback! |
I'm going to use this as a reference, but start from scratch just due to how different the repo is at this point. |
Description
Part of #66
Additional context
Currently I haven't actually pulled over any of the components yet; I have focused mainly on getting the build settings, lerna config, etc. all correct as much as possible. That said, I have tested importing the ui library into the example repo and it works, so there's that.
Before submitting the PR, please make sure you do the following:
Unreleased
heading in the package'sCHANGELOG.md
fixes #123
)