-
-
Notifications
You must be signed in to change notification settings - Fork 928
[rewrite] Rest of the API #1044
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
Comments
Given the amount of
I'm working on a very rough-n-tumble version of what I think this should look like in a branch. |
@isiahmeadows Maybe is a stupid question haha but just to be sure. for example: var m = require("mithril/render/hyperscript"); |
As for multiple mount points, we could instead do this:
For remounting, there are these properties/methods:
The old API could be roughly replicated with this (the breaking part is that it doesn't return the vdom state): function mount(root, component) {
if (component == null) {
m.mount().clear()
} else {
m.mount(root, component)
}
} |
Currently, even though it's been modularized, and you will have the option of requiring individual parts, there will be a global build of everything and just specific parts. This issue is mostly focused on starting down that direction, since not much thought has yet to be put in it. |
ahhh ok!! Thank you for explaining to me 😌 ! |
FYI, I started doing some work on exposing a 0.2.x-like API to help @tivac test. Currently there's m, render, trust, a rough mount, route, request and redraw and a version of threadit.js running from the bundle. It pretty much has the same API except for config: m.route and the new state / lifecycle API. I'll push it when I get back to my desktop so you guys can take a look There's only one issue that I would consider major wrt post-request redraws, that I need to do some work on |
@tivac https://github.com/lhorie/mithril.js/blob/rewrite/examples/threaditjs-bundle/app.js The mountpoint now looks like 0.2.x: https://github.com/lhorie/mithril.js/blob/rewrite/examples/threaditjs-bundle/app.js#L178 and post-request redraws still need to be called manually (but the m.redraw hook does work) https://github.com/lhorie/mithril.js/blob/rewrite/examples/threaditjs-bundle/app.js#L34 The only other caveat is that currently, The bundle can be regenerated by running Oh, and now, |
@lhorie Wow, that's... comprehensive. I'll try to dig into it some this weekend! |
I agree with @tivac wrt Other thoughts:
I say all this, but I think I'd need to actually try writing something using the new API/code to have a more informed view-point. |
@lhorie Finally got a chance to play w/ the compat shim, thanks for that. Yours is much cleaner than my attempt!
|
@tivac Awesome, glad to hear that! Items 2) and 3) are still in the list of things to do. I'm specially open to suggestions re: cancelling redraws. The two options on the table currently are:
The second option could be abstracted w/ a function, e.g. |
Based on anecdotal evidence from gitter/GH I think
|
Just pushed #1047 as my attempt to address the over-redrawing issue. |
@tivac I'm taking a crack at writing some tests for the limiter right now. I sometimes see redraws firing before 16ms in your scrolling test in Chrome, need to figure out what's going on. |
@lhorie Seems pretty likely that my very simple logic does something incorrect, will fix it asap and flesh out w/ more tests once I know where you want 'em! |
I think the logic is fine but the issue is related to the (lack of) precision of the Date API. When it's under 16ms, it's usually somewhere around 15.8ms. Maybe that's acceptable |
The I just had a go at reproing and didn't see any immediately concerning behavior in Chrome using either |
Hi, I'm using mithril in a big project (https://github.com/veloce/lichobile) so I'm following this closely :) I have a suggestion for the rate limiter. Would it not be better to separate the logic of The frame budget of 16ms is in theory what we should attain but it's actually better to rely only on the browser to debounce input handlers, because in some cases (low battery, hidden tab, etc.) the browser may change According to the google perf guide // First render, OR if the time since the last render is greater
// than the frame budget
// just immediately render
if(!last || now - last > FRAME_BUDGET) {
last = now;
return render()
} This block of code is causing problem because it renders synchronously. The google guide says visual changes should be always performed async to avoid long running input handlers. The other problem is that the rate limiter function currently mixes a synchronous rendering with an async one (the Under some conditions, the browser, just after the first synchronous The solution to this problem, when That's why my suggestion is to separate the I don't know mithril's internal enough to know if a pure async redraw function would cause problems in some cases. In that case imo, the best option would be an api that redraws async all the time by default with the possibility to render synchronously when needed. |
In the 0.2 API, these two are functionally identical, mod the contagious // 1.
var value = m.prop(promise)
// 2.
var value = m.prop()
promise.then(value) That's why I'm +1 on removing the promisification of |
@veloce IMHO all rendering by Mithril should be async. I won't have the final say on whether that will even happen, but I'm hoping it does. 😄 |
@isiahmeadows I hope too. And it's probably easier to have all rendering async by default with a synchronous one on demand than the contrary ;) |
The rationale for having synchronous rendering at all is related to video playing in iOS, i.e. triggering |
@tivac re: tests, the thing that is proving difficult to test is the size of FRAME_BUDGET, because |
@isiahmeadows, right, I completely forgot about using prop like that. In that case I'm +1 for simplifying |
I'm not opposed to changing the rendering logic, this was a simple port of what existed in @lhorie I was thinking that it'd probably make sense for everything that isn't |
@tivac yeah that's what I was thinking too. On a semi-related note, since you're pretty much driving this effort, do you want me to give you commit access? |
@lhorie I'm still going to do everything via PR but sure, that'd probably help me annoy you a bit less 😆 |
Cool, just made you a collaborator |
Ok thanks, let me take a look |
Working on an API similar to the one I proposed earlier in my api-proposal branch. Currently looking like this: // v0.2.x style usage
var m = require("mithril");
// OR
// piecemeal usage
var m = require("mithril/api/m")
var mount = require("mithril/api/mount")
var redraw = require("mithril/api/redraw")
var prop = require("mithril/api/prop")
// etc The default |
For the piecemeal usage, the reason I suggested //
// setup.js
//
var m = require('mithril/custom')
m.request = require('some-request-lib')
m.route = require('some-router-lib')
m.route.link = ...
//
// file-one.js
//
var m = require('mithril/custom')
m.request(...)
m('h1', 'hello')
//
// file-two.js
//
var m = require('mithril/custom')
m.request(...)
m('a', { oncreate: m.route.link }) This is to avoid, for example, |
if you're going to have a setup file, why not just copy index.js and remove the stuff you don't want? |
I don't think aliasing third party libraries to mithril method names makes any sense at all. Just require the lib and use it. I'm not planning on using pieces of mithril, fwiw. Mithril is small enough that ignoring the bits we don't want is more cost effective than trying to customize it. |
cause then you'd have to do relative requires like
Sorry for the contrived example. A more realistic one would be initializing And hey, given the option, I go the extra mile in cutting out kb when possible :) |
If you don't want to split mithril into separate packages, at least make requires standardized, and comfy to use. So So make it |
@darsain sure, this is just a POC. I don't like littering the repo root w/ random files in general so was avoiding it until there was some consensus on whether or not that experiment was worthwhile. |
@tivac you don't have to litter the repo root with anything. Just set up a build for npm. What's published to npm doesn't have to match the repo. |
@darsain I find it utterly confusing when I encounter such a package and try to match the |
Were the |
Current Status (as best I can figure) based on this issue and Leo in gitter today
|
that was @barneycarroll's proposal here: #1014 |
I really don't like the idea of using the return value of a mount point for granular redraws. How about redrawing components by referencing their controller / state object? |
Will there be a replacement for Also, an unrelated comment: doesn't putting route query parameters on |
@s3ththompson To my knowledge, yes. As for the details of that, I'll refer you to @tivac and @lhorie. |
The polymorphic
|
@pygy 👍🏻 I should add that to the migration guide. |
@tivac while you're at it, perhaps add:
|
Opened #1090 for a place to track overall rewrite status. Discussion should continue here or in other, smaller issues on a per-topic basis. |
Bikeshedding a bit here, but |
@pygy 👍 It's already obvious enough, and it would fit better with the rest of the API, which also uses more concise naming conventions. |
Since we're starting to get to that point, I think it's a good idea to start thinking of the rest of the high-level API. Here's some of my ideas:
Mithril.m(type, attrs?, ...children)
The familiar
m()
hyperscript API.var trust = Mithril.trust
var mountpoint = Mithril.mount(window = global.window)
Ideally, this should return an object you can use to do
m.redraw()
-like things and have multiple independent roots. The argument is for easy mocking, and effectively nullifiesm.deps
.mountpoint.window
This is the window value argument passed to
Mithril.mount()
, defaulting to the global window. You can also use a JSDOM window if you want to use it in Node.var promise = mountpoint.redraw()
This should do the equivalent of 0.2's async
m.redraw()
, but return a Promise.mountpoint.redrawSync()
This should do the equivalent of 0.2's sync
m.redraw(true)
, and return nothing.mountpoint.redrawStrategy = "all" | "diff" | "none"
This fufulls the same purpose as
m.redraw.strategy()
. It might not be necessary with the lifecycle methods, though.var promise = mountpoint.compute(callback: () => Promise | void)
This should take the place of
m.startComputation
andm.endComputation
. It is roughly equivalent to the following code:Mithril.prop(init?, observer?)
m.prop
is popular enough that it should probably stay in core. I do believe it should lose the Promise absorbing semantics, though, and it should be optionally observable.Mithril.withAttr(value, callback, thisArg)
m.withAttr
also seems popular enough that it could remain in core, with few modifications (mostly removing compat bloat).The rest are generally not necessary/needed in the core distribution.
m.route
can be implemented on top ofm.mount
in a third-party module.m.component
can (and should) die.m.request
should be go away in favor of the native Fetch API, and there is an XHR-based polyfill if you need one. IMHO, redraw after request should be explicit, anyways.m.deferred
andm.sync
should go away in favor of native Promises. If necessary, there's a ton of libraries and polyfills for that./cc @tivac @lhorie
The text was updated successfully, but these errors were encountered: