-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Packages: Singleton pattern prone to duplicate, distinct module scopes #8981
Comments
Why not just always use |
@coderkevin Yes this is one of the solutions on the table (for the data module at least) but it's not a simple switch:
These have solutions (probably injecting these APIs using inline scripts and forbidding their usage in the packages themselves) but it's not smallish :) |
Yes, internally the data module operates on single registries, but also defines a "default" registry, which was specifically intended to improve usability by plugins in a WordPress context (by calling |
So, if one uses a plugin and sets the value in the provider, I am a bit biased as I tend to eschew globals whenever possible. But my preference is for reasons such as this, and for testing as well. |
No, if a developer uses the provider, any descendents using gutenberg/packages/data/src/components/with-select/index.js Lines 124 to 131 in ec1fd21
See also #7453 as an example of providing a custom registry via provider to create an embedded editor experience. |
FWIW, I think this sort of confusion is quite natural with a double-edged (explicit/default) approach like this ( I don't really have a horse in this race, but I think the purported better developer ergonomics that the global/default registry is supposed to give is set off by the potential errors one makes when trying to migrate to the |
Did you consider using Some reading: |
There are many There are projects like Calypso or Jetpack that depend on many Assume, for example, that our project depends on Now let's upgrade Normally, such duplication only inflates the size of your code (you ship one thing twice), but in case of the We'd rather if In our example, Which packages should be peer dependencies?
There are other packages that register a data store and provide various services for the app:
If these packages are NPM dependencies anywhere, they should be also peers. But the consumers don't usually import anything from these packages -- they are accessed through the registered data store, e.g.: dispatch( 'core/notices' ).createNotice( ... ); and not with: import { createNotice } from '@wordpress/notices';
createNotice( ... ); What if we removed the singletons, e.g., If the app (e.g., import { DataProvider } from '@wordpress/data';
ReactDom.render( <DataProvider registry={ registry }><App /></DataProvider> ); and a component uses the context consumer: import { DataConsumer } from '@wordpress/data';
export default function Component() {
return <DataConsumer>
( registry ) => { ... }
</DataConsumer>
} then the provider and consumer must come from the same package. If the consumer imports from a duplicate, then it's two different contexts (two different results of The same reasoning applies for |
Another case where a dependency should always be a peer is when the consumer imports a One example is the |
For the record, there is a convention that a package should declare another package as a NPM dependency even if it merely uses a store registered by it, without doing any |
With It's a bit unclear if Lerna would be capable of handling them as expected. To better illustrate it let's take an example: gutenberg/packages/edit-post/package.json Line 35 in 87fa5f5
During the publishing process, Lerna replaces the local path with the latest version of @wordpress/data that exists. So the question is whether Lerna would replace the path with a version number in the first place. If it would, what would be the version specified and if it makes things any better. In general, it requires some experimentation.
To be clear, all packages that use a given datastore should import it in the entry point by convention. It's something that could be improved because if it's missed it might indeed cause errors. At the moment, there is no simple way to validate it happens. Example: gutenberg/packages/edit-post/src/index.js Lines 4 to 10 in 87fa5f5
|
@gziolo If I understand correctly, your concerns are:
These are both good questions and I don't know the answers at this moment. Totally worth testing. It might invalidate the entire |
@jsnajdr, a very good summary of what I shared. I don't have answers as well, we need to investigate all that. |
I started a quick PR that could help to mitigate the issue with import statements for the packages that expose stores used in the package. In the long run, it isn't solid enough, which I was able to confirm by only testing one package |
@gziolo I finally have some answers to the npm7 and Lerna questions 🙂 npm 7 installing peer dependencies by default If my project has only
Doing the same install with npm 7 will automatically install It gets more interesting when my
Here npm 6 installs both npm 7 is much more strict with this scenario. It detects the incompatibility, refuses to install an extra copy of
Therefore, declaring If Lerna replacing In short, peer dependencies version range should be as loose as possible, and removing previously compatible versions from the bottom of the range is a major semver change. Because the peer range is part of the module's public API. And the upgrade is no longer a drop-in replacement, but requires upgrades of other packages. Therefore, we should declare peer dependencies on, e.g., |
Thanks for diving in @jsnajdr declaring peer dependencies definitely seems like a step in the right direction in that case. |
@jsnajdr, it all sounds very promising. Great work exploring all options. It makes me wonder if we could automate ourselves the process for keeping One challenge I can think of is how we ensure that we always bump a minimum required version when we use the newly introduced API method which isn't a breaking change for the peer package, but would be for the package that is consuming it if it isn't using the version that contains it. To give an example:
Is it a correct assumption? |
Yes! Additionally, We have a recent practical example of this: data stores created by |
Hi @jsnajdr Jarda. What can do to help the issue and PR along? |
It isn’t actively developed. |
Discussed today in the Core JavaScript meeting: https://wordpress.slack.com/archives/C5UNMSU4R/p1534251793000100
Originally raised at: Automattic/wp-calypso#26438 (comment)
An original issue was observed with
@wordpress/data
, where multiple registries could be simultaneously present due to independent versioning of packages having different dependencies upon the specific version of@wordpress/data
.Some observations include...
@wordpress/data
, and could affect anything which behaves in a global / singleton fashion:@wordpress/hooks
,@wordpress/filters
,@wordpress/blocks
Options for moving forward considered include...
@wordpress/data
)@wordpress/data
)cc @jsnajdr @gziolo @adamsilverstein @youknowriad
The text was updated successfully, but these errors were encountered: