-
Notifications
You must be signed in to change notification settings - Fork 3
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
feat(lib): export useFieldPlugin react hook #224
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@@ -37,6 +37,7 @@ | |||
"build:lib": "yarn workspace @storyblok/field-plugin build", | |||
"build:cli": "yarn workspace @storyblok/field-plugin-cli build", | |||
"build:container": "yarn build:lib && yarn workspace container build", | |||
"build:helpers": "yarn workspaces foreach --include \"helper-*\" run 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.
Starting the package names with helper-
is useful in this case.
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc && vite build", | ||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --resolve-plugins-relative-to ." |
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.
Something I've learned:
I added --resolve-plugins-relative-to .
to the eslint command because eslint was traveling up to the root of this repository to gather all the eslint configs. By applying this parameter, it forces eslint to only look for the configs and plugins within this folder.
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.
Would it be possible to set "root": true
in the eslint config file? https://eslint.org/docs/latest/use/configure/configuration-files#cascading-and-hierarchy
external: ['react', 'react-dom', '@storyblok/field-plugin'], | ||
output: { | ||
globals: { | ||
react: 'React', | ||
'react-dom': 'ReactDOM', | ||
'@storyblok/field-plugin': 'FieldPlugin', | ||
}, | ||
}, |
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.
Although we're depending on these 3 libraries, we're excluding them in the final bundle output.
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 part is a bit unclear to me...are we excluding the dependencies because we are bundling it together with the field plugin package and therefore they are already bundled there?
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'll show you this on Wednesday. Don't forget to ask! :)
This is something I have very little knowledge about, but I wonder if the tree shaking is working correctly here, like if I am using react I do not want to get the vue code also being a part of the code. |
@BibiSebi Feel free to ask a ton of questions until you get comfortable enough with implementing the next one :) (We could even have a call if you want) Anyway, because of
If someone imports only from import { useFieldPlugin } from '@storyblok/field-plugin/react'; They didn't import |
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.
Thank you for your work on this one! let's merge it and on wednesday talk trough the vue part :) also thank you so much for the explanations. They were super helpful! 🙏
external: ['react', 'react-dom', '@storyblok/field-plugin'], | ||
output: { | ||
globals: { | ||
react: 'React', | ||
'react-dom': 'ReactDOM', | ||
'@storyblok/field-plugin': 'FieldPlugin', | ||
}, | ||
}, |
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 part is a bit unclear to me...are we excluding the dependencies because we are bundling it together with the field plugin package and therefore they are already bundled there?
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.
There's another approach we could take:
Write javascript files and separate typescript definition files, and annotate the JavaScript files with the @type tag with JSDoc.
In this way, we
- avoid a build step
- get full TypeScript support within the source code (while developing)
- get full TypesScript support when importing the library
- make it easy to maintain
I also wonder if the "helpers" should be part of the field-plugin package?
packages/field-plugin/helpers/react
Also, maybe "helper" is not descriptive enough. Not sure what would be a better wording though... maybe "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.
Can we rename this to FieldPluginProvider.ts
?
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.
sure
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.
Can we rename this to FieldPluginContext.ts
?
@johannes-lindgren thanks for your feedback. Actually "Approach 2" was about this, writing type definition manually (which could also be automated by jsdoc as you said). But still it comes to a problem that you have to include dev dependencies for eslint configs for react, vue, ... within the |
@johannes-lindgren As you initially worried about bloating the field-plugin package and as I agreed with it, I separated them as separate packages, and wrote a script to merge them during the build time. And "helper" is obviously not my favorite part 😂 It's not visible to end-users, but we get to see this name in the codebase. Feel free to suggest any other name, since we can always rename it without introducing breaking changes to users. |
@eunjae-lee Yeah What do you think about grouping them into a common directory such as Do you think it would be a good idea to move these workspaces somewhere into Here is an idea: keep each export in a separate workspace while at the same time skipping the compilation step by having type declaration files and non-compiled JavaScript files. So like approach 2, it lacks a compilation step; and like approach 3, it has multiple workspaces. I don't have practical experience setting up a project like this, so I haven't learned the "best practices" (if there is such a thing). |
@johannes-lindgren yeah we could have them under
I'm not sure if I understand this. What do you mean by non-compiled JavaScript files? You mean just plain JavaScript files that don't need compilation? Yes, we can do that. The only downside to this approach is that we cannot have eslint config for the specific helper if we don't have build process. Or, do you mean to have eslint configs per each helper, but just not have compilation? |
I mean the last sentence (I think):
Each helper would have its own package and there would be no compilation of the JavaScript and type definition files. Each "helper" would have its own directory, for example:
Something like {
"files": ["helpers"],
"exports": {
"./react": {
"import": "./helpers/react/src/index.js",
"types": "./helpers/react/src/index.d.ts"
},
} maybe this will work: {
"files": ["dist", "helpers"],
"exports": {
"./*": {
"import": "./helpers/*/src/index.js",
"types": "./helpers/*/src/index.d.ts"
},
} |
## What? This adds `@storyblok/field-plugin/vue2` submodule. Related: - #228 - #224 ## Why? JIRA: EXT-1828 <!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? Are there any linked issues? --> ## How to test? (optional) <!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
@johannes-lindgren okay, I see your point. I mostly agree with what you said, and I wonder why you want to exclude compilation step while you keep its own eslint config, etc. |
@eunjae-lee my hope is that it would simply the build process, so it will be easier to make modifications and there would be less edge-cases where things don't simply work. For example, now that I work on #241, I'd like to run in development mode while I am working on modifications. But when I run yarn workspace @storyblok/field-plugin dev It does not automatically compile the Neither does this work: yarn build Because the current Of course, there are ways to work around all of these issues one-by-one (especially now when our memories are fresh), but maybe in a few years, it will be hard to make changes if the complexity of the project is too great. Though I don't know what the best approach is here -- I haven't developed a library with multiple exports before. Maybe if we try to use type declaration files and JSdocs, we'll encounter other unexpected issues... Though maybe it's worth a try? |
At the root package.json, we have this:
So anyone running And in the package.json of
I don't see this as issues that we're working around, but it's that we're introducing a new thing here and encountering initial bugs or misconfigurations.
But the react helper simply cannot export
vs.
and suggesting the latter? |
What?
This enables users to import
useFieldPlugin
directly from the library instead of embedding the code within the templates.As you can see, we're importing it from the submodule of the library. Not
@storyblok/field-plugin
but@storyblok/field-plugin/react
.Why?
JIRA: EXT-1804
We exposed the actual implementation of useFieldPlugin inside the template for many reasons, but I think the most important part was because it wasn’t finished back then.
Now that they’re getting stable, we could include them within the library. It makes our templates cleaner. Also, users will be able to receive updates if we publish new feature or fix to those hooks.
Implementation Details
There are different ways to implement this. Let me list the approaches and explain how I chose one. From now one, let's call this react specific code "react helper".
Approach 1
I put the react helper directly inside
packages/field-plugin/src
folder. It was something like:And I updated
yarn build
to automatically copyreact-helper
folder intodist/
(without any bundling or transpiling).`Then I added something like this to the package.json:
Although this
react
submodule is exporting a typescript fileindex.ts
, it worked well because the template is using vite and vite is able to resolve this typescript file with no problem.However, TypeScript complained that there is no type definition for
@storyblok/field-plugin/react
. That's a problem .. that this approach cannot solve.Approach 2
We could manually write a type definition for the react helper. It's not going to change much in the future, but still having to maintain it by hand might be cumbersome (we also need to support vue, ..)
What if we want to generate type definition out of the
react-helper/index.ts
? It's possible, but then it means we need to have proper dev dependencies, tsconfig, vite config, etc within thisstoryblok/field-plugin
package. It's going to be a nightmare because, what about other frameworks? This package is going to be bloated.Approach 3
This is the one I chose in this pull-request. I created
This react helper package is its own library bundled with vite. However, it will be too much to maintain if we release it as
@storyblok/field-plugin-react
.Instead, when building
@storyblok/field-plugin
, it also builds this react helper, and copies the dist of the react helper over to the dist of@storyblok/field-plugin
.The main upsides about this approach are
(a) we can generate type definition with proper tooling
(b) react helper can have its own eslint config, tsconfig, etc.
In face, the previous "Approach 1" couldn't cover (b).
Conclusion
I took the approach 3, but if you have another approach to try, let me know :)
How I Added the React Helper
First of all, the folder name and package name are
helper-react
(not react-helper) to see all the helpers in the folder tree alphabetically. Let me know what you think.Basically I ran this command:
and started configuring the helper package. More details will be left as comments.