Comments (15)
PR created: #34
I think we should also discuss how deeply we should add in support for Signals
.
As I mentioned in some of the other issues, there are some APIs that are a perfect fit for Signals (e.g. DOM is_ready()
, getting the current URL for the Router, and many more in the future)
With the proposed system, that is easy to do: we just create a signal
submodule, which lives alongside the callback
, future
, and stream
submodules.
from gloo.
I've written 'FRP' style code (using RxJS) and it's phenomenal to develop and maintain. It does have a slight conceptual learning curve however in my experience it's paid off as well as that of Rust itself.
from gloo.
Thanks for starting this discussion, @Pauan, I think this is something we should definitely come to consensus on, and document in CONTRIBUTING.md
.
So when we are faced with this choice between mid-level and high-level, what should we choose? I think we should have a consistent approach across the Gloo ecosystem.
+1 for being consistent.
I propose that we always expose the high-level APIs (
Future
,Stream
, etc.) and then have a submodule which exposes the mid-level APIs.
What I care about more than exactly how it is done is exposing all layers of the onion as reusable pieces:
-
-sys
bindings (which gloo is not responsible for, since they are injs-sys
andweb-sys
) - the direct translation of the JS API into a Rust API (e.g.
FnOnce
callback-basedset_timeout
API; I believe this is what you are proposing forraw
modules) - the version for if-we-were-going-to-design-this-same-abstraction-level-API-in-rust (e.g. using
Future
s for timeouts andStream
s for intervals)
and then optionally, maybe, sometimes:
- a version of the API at an even higher-level abstraction than what the web exposes (e.g. vdoms, or building couchdb-esque thing on top of indexed db, etc). I think this should have a much higher bar to pass before we include it in Gloo, maybe we wouln't even include these APIs in Gloo since they should probably be experimented with outside Gloo before we canonicalize it within Gloo, and it is a bunch fuzzier in my mind since it is very case-by-case specific by nature.
As far as how to expose the different layers of the onion, I think these are our choices:
expose every layer in the rootWe don't want to do this by design, since we have an explicit goal of spinning things out into reusable crates.gloo
crate.- Expose every layer for the
whatever
API in the root of the samegloo-whatever
crate. This is what the proof-of-conceptgloo-timers
crate is currently doing. - Expose the layers of the
whatever
API with some sort of module scheme in thegloo-whatever
crate. A variant of this approach is being suggested by @Pauan and theraw
module, IIUC. - Expose the layers of the
whatever
API in different crates with some sort of naming scheme, e.g.gloo-whatever-raw
,gloo-whatever-futures
, etc.
I don't have any strong opinion here, but I'd note that the last has the best compile times for users (e.g. if they only used gloo-whatever-raw
and weren't using futures, then they wouldn't need to compile futures) and the highest maintenance overhead for us. Throwing everything into the top-level of a crate has teh least maintenance burden for us, but the coarsest grain for users and would force someone who wasn't using futures to compile the futures crate and the futures+timers integration, for example.
from gloo.
Instead of raw
, should we do a context specific name?
E.g. for timers we would have a callbacks
module and a futures
module?
from gloo.
I think we all seem to be in agreement here except maybe some bike shedding on exact naming of modules? Given that, would you like to make a PR that formalizes this stuff in CONTRIBUTING.md
, @Pauan? After we merge that, then we can also update the gloo-timers
crate to match the decided upon conventions.
from gloo.
We could have dedicated utility crate that wraps common/verbose web_sys
features, which the bulk of the modules (I agree they should be high-level) can call. Eg:
/// A convenience function for logging to the web browser's console. See also
/// the log! macro, which is more flexible.
pub fn log<S: ToString>(text: S) {
web_sys::console::log_1(&text.to_string().into());
}
/// Convenience function to avoid repeating expect logic.
pub fn window() -> web_sys::Window {
web_sys::window().expect("Can't find the global Window")
}
/// Convenience function to access the web_sys DOM document.
pub fn document() -> web_sys::Document {
window().document().expect("Can't find document")
}
/// Simplify getting the value of input elements; required due to the need to cast
/// from general nodes/elements to HTML__Elements.
pub fn input_value(target: &web_sys::EventTarget) -> String {
if let Some(input) = target.dyn_ref::<web_sys::HtmlInputElement>() {
return input.value();
}
if let Some(input) = target.dyn_ref::<web_sys::HtmlTextAreaElement>() {
return input.value();
}
if let Some(input) = target.dyn_ref::<web_sys::HtmlSelectElement>() {
return input.value();
}
"".into()
}
These could be used either internally to Gloo modules/crates, or exposed in APIs.
from gloo.
@David-OConnor I had thought of that, but that causes extra maintenance burden for everyone: crate authors and crate users. Putting the APIs as a submodule is much easier for everyone.
I'm not against it, though I think there'd have to be a compelling argument to justify the extra complexity.
If you meant that we should have a single utility crate, I don't think that's a good idea either: it will just end up as a jumbled mess of unrelated APIs.
Keep in mind that even though right now the APIs are small and easy to manage, that won't be true forever: as Gloo becomes larger and more APIs are built, proper maintenance and API layering becomes very crucial.
from gloo.
@fitzgen I generally agree with everything you said.
I don't have any strong opinion here, but I'd note that the last has the best compile times for users (e.g. if they only used gloo-whatever-raw and weren't using futures, then they wouldn't need to compile futures) and the highest maintenance overhead for us.
If we used Cargo features
, could we achieve similar fast compile times even with my raw
submodule idea?
Throwing everything into the top-level of a crate has teh least maintenance burden for us, but the coarsest grain for users and would force someone who wasn't using futures to compile the futures crate and the futures+timers integration, for example.
Indeed, I think the raw
submodule has a relatively nice balance between making things easy for us, and making things easy/fast for end users. I'm not sure how well it will work out in practice, though.
from gloo.
If we used Cargo
features
, could we achieve similar fast compile times even with myraw
submodule idea?
Correct. Again, at the cost of maintenance on our end (although probably less than a whole new crate, and neither is that much of a burden anyways...)
from gloo.
One thing I'm curious about is how often we'd be able to distinguish a middle/high layer to abstract here (e.g. how many places it'd make sense to have a raw
submodule). The true 'raw' to me is the *-sys
crates, and then something like a FnMut
vs Stream
for setInterval
is less clear as to which is high and which is mid. For example the "most optimal" Stream
implementation might not actually use the FnMut
one but rather the raw web_sys
apis.
I suppose this also affects the compile time points you brought up @fitzgen because if the high level apis don't build on mid-level apis, then there's compile wins to be had for sure. If high builds on mid, though, I'm not sure crate separate will make much of a difference.
from gloo.
@fitzgen Regarding
- a version of the API at an even higher-level abstraction than what the web exposes (e.g. vdoms, or building couchdb-esque thing on top of indexed db, etc)
I think that
maybe we wouln't even include these APIs in Gloo since they should probably be experimented with outside Gloo before we canonicalize it within Gloo
is wise. Identifying those needs and putting out a request-for-implementations to the community for each would likely produce sufficient variety for experimentation while retaining gloo contributor resources for focusing on the core layers.
from gloo.
@alexcrichton For example the "most optimal" Stream implementation might not actually use the FnMut one but rather the raw web_sys apis.
It's not about internal details, it's about the API that is exposed to the user. From the user's perspective, a callback API is clearly lower level than a Future/Stream based API.
I agree that there might be some gray areas where there isn't a clear division, but in the case of callbacks vs Future/Stream, it seems quite clear to me.
If high builds on mid, though, I'm not sure crate separate will make much of a difference.
That's a good point. Personally, I think the high level APIs generally should be built on top of the mid level APIs, and if they aren't then that indicates the mid level APIs are designed poorly.
@fitzgen E.g. for timers we would have a callbacks module and a futures module?
The downside is that it doesn't make it clear that Futures are the "blessed" way of doing things... but maybe that's actually not a downside?
Maybe Gloo should be more unopinionated and just present both APIs fairly, and let the user decide. So I rather like that idea.
from gloo.
I like the idea of just providing uniform representations of APIs across components, and having a common interface (ish) for both callback and futures-based primitives seems like a good idea. Sharing as many idioms across crates would be great (aka naming and API decision)
from gloo.
Personally, I think the high level APIs generally should be built on top of the mid level APIs, and if they aren't then that indicates the mid level APIs are designed poorly.
Strong agree.
from gloo.
Closing this issue for now, since I think we came up with a general plan for how to support different bits of the ecosystem in our crates. I think the question of whether to integrate with a specific crate/ecosystem can move into dedicated issues, for example the FRP/signals discussion should continue in #33
Thanks everyone!
from gloo.
Related Issues (20)
- `gloo_net`'s `RequestBuilder` is not public
- Use OnceCell for gloo-history HOT 2
- gloo-histroy Support custom query decoder / encoder HOT 9
- Retries for EventSource HOT 1
- async wasm tests don't seem to actually do anything HOT 2
- [history] BrowserHistory: Loaded wrong state HOT 2
- gloo-net: Allow RequestBuilder.query to accept a struct that implements serde::Serialize as an argument HOT 1
- How to close a WebSocket after calling `.split()` ?
- Cloning gloo-worker bridges does not assign new HandlerIds
- Not working with recent yew-0.21.0 HOT 1
- Blob & ObjecUrl generate invalid dowload link HOT 3
- Allow calling `terminate` on workers
- [history] Inconsitent type between gloo_history and gloo_utils HOT 10
- Remove event in another event HOT 2
- Complete gloo-worker webassembly example running in a browser HOT 2
- Feature request: MissedTickBehavior for gloo_timers::future::IntervalStream
- Documentation - broken method reference
- Error `closure invoked recursively or after being dropped` when opening `ObjectUrl` via `window().open_with_url()`
- [`gloo_history::HashHistory`] Assertion failed when calling `HashHistory`'s `location()`
- TryFrom<JsValue> for JsError panics in the NotJsError case if the JsValue isn't a string HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gloo.