-
Notifications
You must be signed in to change notification settings - Fork 781
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
Hyperapp V2 #726
Hyperapp V2 #726
Conversation
Codecov Report
@@ Coverage Diff @@
## master #726 +/- ##
=========================================
- Coverage 100% 16.3% -83.7%
=========================================
Files 1 1
Lines 166 233 +67
Branches 52 69 +17
=========================================
- Hits 166 38 -128
- Misses 0 130 +130
- Partials 0 65 +65
Continue to review full report at Codecov.
|
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.
Typescript definitions appear to be out of date? I copy/pasted the example from the README, and it fails because the .d.ts
has no exported member app
. (looks like a lot of the types were deleted?)
I also noticed there's a block of 3 commented-out functions left behind in the source. |
REAME seems unchanged. As I've not been part of the V2.0 discussion I need a way get context and understand the goals. At least I prefer that before reading code. |
Wow, still single file source. Is that the plan to keep that going forward? |
@okwolf For starters, yeah. I had everything in its own file until the last moment. |
I was really looking forward to seeing it all split up.. I feel the one file things obfuscates different functions reliance on the various globals. You can't get away with that when everything is split up because you have to pass a function everything it needs. Still nice code though. Much more comprehensible that the last one, great job. |
We'd just have a |
Yeh.. I know how it would work. I was looking forward to that structure, that is all. Thought it would make it more clear to people what is going on and what relies on what. It is ok though, I will do it myself sometime as a learning exercise. |
@lukejacksonn Do you think it would be better to split up the code then? |
For sure, but then I misunderstood this:
My point is, while everything is crammed in one file, every function is independent and already expects as input everything it needs to work on and it doesn't rely on stuff which is in the global scope, other than the stuff you'd import to the top-level scope of the module in which the function is declared if it was in a file. In other words, the amount of refactoring needed to put everything into files is minimal, that's what I meant. Sorry, if I said something confusing! 😄 |
You didn't say anything confusing 😅 and I can see that it would easily refactor. I love the single file thing too, but I am starting to wonder if it would be easier to grok in individual files. |
I love the one function per file too. Here, it is like reading a story, you learn how the function works, then, when it is later called, you already know the function and how it works. I was for the individual function files, but now I am thinking about it, I am not sure anymore. |
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.
General thoughts :
- Still not sure about individual files, but I like the way it is in one file.
- Would love the use of
const
for constantes but it is not ES3/5 compliant 🤔 - Did not read so much the patch part (I am not a vdom scientist)
src/index.js
Outdated
for (length = node.length; length--; ) { | ||
rest.push(node[length]) | ||
var EMPTY_OBJECT = {} | ||
var EMPTY_ARRAY = [] |
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 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.
A small optimization, mainly used for text vnodes that don't have children, but still use the same VNode shape.
src/index.js
Outdated
return target | ||
} | ||
|
||
var resolved = typeof Promise === "function" && Promise.resolve() |
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.
So now Promises are used in core ? (if supported)
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.
Nope, this is just a trick to call your callback as quickly as possible.
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.
Why still use var
in 2019? Please use const
. No need to be ES3/5 compliant
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.
@kristianmandrup Check out CONTRIBUTION.md—it's written there. Long story short: because we're not compiling Hyperapp, it's handwritten.
src/index.js
Outdated
var oldChildren = oldNode.children | ||
var children = node.children | ||
return typeof name === "function" | ||
? name(props, (props.children = children)) |
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.
A Component will received children property and children argument ?
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.
Good catch. It's an implementation detail. If you need children
for some reason, use props.children
. I am still open to change this.
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 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.
props.children
definitely cooler then the second argument, see pros and cons here: #569
I am worried only about performance and memoization:
https://github.com/hyperapp/hyperapp/blob/2b3d85625321038ed2369ddb4ecc320a9e20984e/src/index.js#L458
If everything is ok with props.children
would be nice to remove children
from the second argument IMO.
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.
const Component = (props) => <div>{props.children}</div>
app({
init: { children: 'Hello' },
view: (state) => (
<main>
<Component {...state}>World</Component>
<div>{state.children}</div>
</main>
),
container: document.body,
})
Can you guess what this code will render without opening the demo?
<main><div>World</div><div>Hello</div></main>
<main><div>Hello</div><div>World</div></main>
<main><div>Hello</div><div>Hello</div></main>
<main><div>World</div><div>World</div></main>
- throws an error
Demo: https://codepen.io/frenzzy/pen/Zjbqpq/left/?editors=0010
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 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.
Any alternatives? Why can preact get away with the same hack? 🤔
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.
Purity forever! Say NO to mutations :D
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.
Okay, so to clarify, we're back to (props, children)?
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.
Yes!
- no mutations
- no pitfalls for
children
key - simple memoization with
===
src/index.js
Outdated
} | ||
var dispatch = function(obj, data) { | ||
typeof obj === "function" | ||
? dispatch(obj(state, data)) |
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.
Clever.
But the whole codeblock is pretty unreadable 🤔
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 agree. I'm working on a new implementation. 👍
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.
Chaining ternaries is not so bad if you change the formatting a little. I know this is unorthodox, but it definitely helps with clarity.
typeof obj === "function" ?
dispatch(obj(state, data))
: isArray(obj) ?
obj[1].effect(obj[1].props, dispatch, setState(obj[0]))
: obj != null && typeof obj.effect === "function" ?
dispatch([state, obj])
: setState(obj)
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 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.
No can do, we're using prettier.
} | ||
|
||
dispatch(props.init) | ||
} |
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.
return dispatch
?
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.
Yes, I'm still not sure if I should return it or not.
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.
dispatch
doesn't return anything, so it will be undefined
either way, right?
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 is about returning the dispatch
function itself not the dispatch(props.init)
result.
Just commented on this line as this is the last line of the app
function.
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.
How to get the state of your application at specific moment of time? For example for HMR
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.
So should interop be done with subscribe
then?
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.
@frenzzy There is currently no way other than using subscriptions. But I am open to exploring alternatives if need be.
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.
@okwolf Bingo.
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.
Like Elm. But still, if we can think of an alternative, e.g., app.getState(), I am happy to discuss it.
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.
@jorgebucaran we should start by trying to build things that need interop and find where this approach gets ugly.
src/index.js
Outdated
} | ||
*/ | ||
|
||
export function app(props) { |
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.
How about instead of inline exports, using the following block at the top or the bottom of the file
export { h, app }
To make clear that h
and app
will be exported.
I am using this pattern and I found it verry clever. (I learned it from Erlang).
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 could like that. Let me do some research.
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 is definitely more clear when all exports goes near to each other, but I found out that for example webpack generate more noise when you export a name instead of an expression.
src/index.js
Outdated
var dispatch = function(obj, data) { | ||
typeof obj === "function" | ||
? dispatch(obj(state, data)) | ||
: Array.isArray(obj) |
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.
Should this be isArray(obj)
for the sake of consistency?
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 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.
Yup! Good catch and thanks. I'll push updated code soon.
src/index.js
Outdated
var length = arguments.length | ||
var DEFAULT = 0 | ||
var RECYCLED_NODE = 1 | ||
var TEXT_NODE = 2 |
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 seems misleading.
Should your internal constants match the JS spec, or should this be renamed to avoid confusion?
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.
@dangerousdan Haha you do have a point. I'll fix it.
I considered something like it, but I feel now that a mixed approach would break the balance. It's all or nothing. Split the code or not, but not in between is what I mean :) |
src/index.js
Outdated
eventProxy, | ||
isSvg | ||
) { | ||
if (name === "key") { |
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.
Could also be
if(name === "style") {
...
} else if (name !== "key") {
...
}
To avoid an empty if
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'm a fan of the "exit early" pattern
if (name === "key") return
// Do other ifs
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 wonder if this is just personal taste or there's something to this. I mean, my brain finds it a lot easier to think of this as: (if something is true; do nothing), instead of (if not something; do something). Not always, though.
src/index.js
Outdated
: document.createElement(node.name) | ||
|
||
var props = node.props | ||
if (props.onCreate) { |
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.
So lifecycle events are still supported and use camelCase now? 🤔
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 gave in to camelCase :)
...lifecycle events
They're in this branch, for now. I still haven't decided whether to remove them or not. I know we don't need them, but having them can be useful. You can help me decide by adding your feedback to #717.
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.
but having them can be useful.
I'm glad the hooks are still there so I don't yet have to use custom elements and allow this
in my codebase 🤢
Will |
@okwolf Published from master after it's merged (with docs). Future V1 releases will be published from the V1 branch, though. |
} | ||
|
||
dispatch(props.init) |
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.
dispatch(props.init || {})
Providing init
with an empty state permits to omit it in case of concise example or stateless app. We can write like:
app({
view: () => (
<div>
Lorem ipsum dolor si amet
</div>
),
container: document.body
})
instead of:
app({
init: () => ({ }),
view: () => (
<div>
Lorem ipsum dolor si amet
</div>
),
container: document.body
})
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.
props.init
is a function, so it should be
dispatch(props.init || function() {})
or in a more concise way
dispatch(props.init || Function())
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.
Nevermind, dispatch
works with objects too.
(part of the unreadable ternary 🙄 )
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.
Yup.
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.
My major comment is to use as much ES6 as possible to make code simpler, smaller and performant.
package.json
Outdated
"rollup": "^0.57.1", | ||
"typescript": "2.8.1", | ||
"uglify-js": "3.3.16" | ||
"babel-preset-env": "^1.7.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.
Can we use latest babel 7 packages ?
I have recently tried using rollup and parceljs for bundling one of my library and finally i ennded up using webpack 4.15.x because i wanted to use latest babel packages as descibed below:
"@babel/cli": "^7.0.0-beta.51",
"@babel/core": "^7.0.0-beta.51",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.51",
"@babel/plugin-syntax-dynamic-import": "^7.0.0-beta.51",
"@babel/preset-env": "^7.0.0-beta.51",
"@babel/preset-react": "^7.0.0-beta.51",
If rollup is finalised for V2 then ignore this comment.
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.
@jorgebucaran I would not anticipate babel 7 leaving beta soon. They have many open issues.
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.
Thanks for clarifying that! @ggassmann
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.
src/index.js
Outdated
if (state !== newState) { | ||
state = newState | ||
|
||
if (!updateInProgress) { |
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.
What will happen if updateInProgress is true ? Are we ignoring all setState() call till updateInProgress is true ? Just a wild thought of saving it to tempState(keep overwriting till updateInProgress is true) and apply the latest value of tempState once updateInProgress becomes 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.
@k-murakami0609 Are we ignoring all setState() call till updateInProgress is true ?
Nope! We're avoiding patching, that's it. In other words, state updates are pretty much immediate.
cb(element, done) | ||
} else { | ||
done() | ||
export var h = function(name, props) { |
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.
As we are exporting h object here so this source file becomes ES6 module. So why then we are not using all power of ES6. To name a few, using const, Object.assign, spread operator, etc which will make code more readable, smaller (not larger at least) and simple without adding any burden to performance. Making methods will easily become one liners.
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 don't think this file gets transpiled. Rollup supports specifying UMD, which is how this project is configured, which is probably where the export support comes from.
https://github.com/hyperapp/hyperapp/blob/2b3d85625321038ed2369ddb4ecc320a9e20984e/package.json#L27
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.
@kumarabhishek https://github.com/hyperapp/hyperapp/blob/master/CONTRIBUTING.md#style
FYI: We're not losing any performance from not using more ES6 idioms.
But that could change in the future if we start using things like Maps or WeakMaps and they become faster than regular objects? 🤔
src/index.js
Outdated
var listen = function(sub, oldSub, dispatch) { | ||
if (isArray(sub) || isArray(oldSub)) { | ||
var out = [] | ||
var subs = isArray(sub) ? sub : [subs] |
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.
Here you are doing duplicate isArray check for sub which is already done in if condition. So the tradeoff is having to variables to store result of isArray for sub and oldSub versus calling isArray two times. I will consider more variables as cheaper than more function call in runtime. My idea is something like this:
const isArraySub = isArray(sub)
const isArrayOldSub = isArray(oldSub)
if (isArraySub || isArrayOldSub) {
let out = []
let subs = isArraySub ? sub : [subs];
...
}
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.
Well, that won't work with let
, only with var. Var hoists the definition to the top of the scope, so when it's referenced at [subs]
it returns undefined
. But with let
it will throw a ReferenceError, since it is self referencing and won't exist until the line has executed.
I actually think this is a typo and he was intending to ensure that sub
is an array. If that's the case, you can just do:
var subs = [].concat(sub)
Which will ensure that subs
ends up an array and will work if sub
is already an array or just a value.
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.
@TheNando I have already made this suggestions one month ago on Slack
see https://hyperapp.slack.com/archives/C5D86NQ3X/p1529772214000096?thread_ts=1529772214.000096&cid=C5D86NQ3X
If @jorgebucaran made the decision to do not use this implementation, he should have some good reasons.
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.
Thanks, @Swizz. Basically [].concat
is a lot slower.
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.
@jorgebucaran But : [subs]
supposed to be : [sub]
, right?
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.
@TheNando Yes, totally, that's a bug! Fixing it now :)
src/index.js
Outdated
var subscribe = props.subscribe | ||
var subscriptions = [] | ||
var container = props.container | ||
var element = container && container.children[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.
Is container.children always defined and thus container.children[0] is always valid ?
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.
@kumarabhishek Only if container
exists!
container && ...
src/index.js
Outdated
updateAttribute(element, name, attributes[name], null, isSvg) | ||
} | ||
} | ||
var createTextVNode = function(text, element) { |
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.
If you use ES6 default parameter and organise params like below then createTextVNode is not needed at all:
var createVNode = function(name, element, props={}, children=[], key=null, type=TEXT_NODE) {
...
};
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.
Please read this regarding which ES spec we follow.
src/index.js
Outdated
} | ||
} | ||
|
||
var getKey = function(node) { |
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 method will not be needed if we ensure that node.key is by default null. This can be done using default parameter in functions related to node.
src/index.js
Outdated
) { | ||
for (var name in merge(lastProps, nextProps)) { | ||
if ( | ||
(name === "value" || name === "checked" |
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.
Just a matter of taste, i like single quotes for strings in JS and double quotes inside JSX/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.
It's not bad suggestion, in fact I prefer single quotes for strings too.
Even it's supported by prettier https://prettier.io/docs/en/options.html#quotes
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.
But in that case, It's Hyperapp @jorgebucaran preference 😅
@kumarabhishek Regarding using ES6 over ES5...
Simpler, maybe. Smaller, probably not after transpilation. Definitely not more performant. Ultimately, it's per-browser implementation, but in most cases, ES6 is less performant. Declaring arrow functions are a little slower in Chrome and much slower FF. Destructuring is much slower across the board. Classes are slower except in FF. The new loops, generators, map/set, Object.assign, spread...pretty much all slower than es5 implementations. |
Previously, we were using a microtask, but this creates an issue when toggling an element with an event handler causing the event to fire twice (unless we force Hyperapp to create a new element). This is one of several reasons frameworks like React implement a synthetic event system. Hyperapp V1 didn't have this bug, because we were using setTimeout to defer rendering. setTimeout defers callbacks too late, Promise.resolve too early, requestAnimationFrame just right. - Prevents firing events twice (without keys, or e.stopPropagation) - Prevents inputs from going out of sync if typing too fast, or from flickering if one changes input's value, e.g., to prevent the user from entering numbers in it. - Doesn't interfere with effects using requestAnimationFrame to run animations like setTimeout does. - Falls back to setTimeout if requestAnimationFrame is not available. One gotcha about using requestAnimationFrame is that rendering will be effectively paused in when running in background tabs, which is a browser measure to improve perf and battery life. After considering all options, I decided to run with rAF until I can find a better alternative.
- Diff props before creating new elements - Use DOM as source of truth for selected attribute - Add more documentation
src/index.js
Outdated
? document.createTextNode(node.name) | ||
: (isSvg = isSvg || node.name === "svg") | ||
? document.createElementNS("http://www.w3.org/2000/svg", node.name) | ||
: document.createElement(node.name) |
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 support customized built-in elements here? For example:
<p is="word-count">
and
document.createElement("p", { is: "word-count" })
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.
@dennis84 Hyperapp sets attributes/properties after creating the element. This code:
<p is="word-count">
...creates a p
element with an is
attribute exactly as declared. Is that what you needed?
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.
Ah, that doesn't work for custom elements. As Far as I know, you have to pass the "is" attribute as options to the createElement function.
If you run this in the conosle nothing is logged:
class WordCount extends HTMLParagraphElement {
connectedCallback() {
console.log('AAAA')
}
}
window.customElements.define('word-count', WordCount, {extends: 'p'})
var p = document.createElement('p')//, {is: 'word-count'})
p.setAttribute('is', 'word-count')
p.appendChild(document.createTextNode('test'))
document.body.appendChild(p)
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.
@dennis84 Does React/Inferno/Preact/etc. handle this?
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 could only find it in React and Mithril:
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.
@dennis84 Awesome, thanks. I'll figure out what's the best way to add this after V2 is out. Thank you.
- App takes second HoF for dispatch
To consolidate the custom/default payload into one argument, the 2-tuple action-payload pair now accepts a payload creator where you'd normally write the payload. A payload creator is a function that takes the default payload and returns a new payload. You can use it as follows: <input type="text" value={state.value} oninput={[UpdateItem, event => ({ id: todo.id, value: event.target.value })]} /> Also included with this commit: - Inline identity function - Return updated state from setState and dispatch
@jorgebucaran is there going to be a new alpha release with |
@okwolf Yes, working on it! Hang on. :) |
@@ -1,4 +1,4 @@ | |||
# <img height=24 src=https://cdn.rawgit.com/jorgebucaran/f53d2c00bafcf36e84ffd862f0dc2950/raw/882f20c970ff7d61aa04d44b92fc3530fa758bc0/Hyperapp.svg> Hyperapp | |||
# Hyperapp | |||
|
|||
[![Travis CI](https://img.shields.io/travis/hyperapp/hyperapp/master.svg)](https://travis-ci.org/hyperapp/hyperapp) |
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.
Broken link, should point to jorgebucaran/hyperapp
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.
Thanks! Will fix.
README.md
Outdated
## Getting Started | ||
- **Minimal**—We have aggressively minimized the concepts you need to learn to be productive while remaining on par with what other frameworks can do. Dynamic, purely functional frontend applications without the headache. | ||
- **Declarative**–Design your UI as a function of the state, and Hyperapp will efficiently update the DOM as your data changes. Declarative views, managed effects, and subscriptions make your code predictable and easy to debug. | ||
- **Standalone**—Do more with less. Hyperapp includes state management and a [state-of-the-art] Virtual DOM engine that supports keyed updates, functional components & tree memoization—all without dependencies. |
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.
Hyperapp includes state management and a [state-of-the-art] Virtual DOM engine that supports keyed updates, functional components & tree memoization—all without dependencies in one dependency.
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.
Hyperapp itself is a dependency. Is that what you mean? :)
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.
Alternatively you could say all without additional dependencies. But yes.
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 went with "all without extra dependencies". 😅
README.md
Outdated
|
||
Instead of returning a partial state object directly, an action can return a function that takes the current state and actions as arguments and returns a partial state object. | ||
When describing the content of a page, we use the `h` function to create a virtual DOM. A virtual DOM is an object representation of how the DOM should look at any point in time. Hyperapp calls your `view` function to get this object and converts it into real DOM nodes in the browser efficiently. |
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.
Distinguish between virtual DOM and virtual nodes?
? [b[0], b[1], b[0](b[1], dispatch), a && a[2]()] | ||
: a | ||
: a && a[2]() | ||
var patchSubs = function(oldSubs, newSubs, dispatch) { |
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.
Is this code golfed enough? I can almost read it 😆
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.
@okwolf I just pushed to this branch like a few seconds ago. Are you sure you're looking at the right code? :)
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 referring to the new version of patchSubs
being more readable. Hopefully not at the cost of too many bytes 🙃
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.
@okwolf Which one is more readable?
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.
Most folks seem to think the nested ternaries are less readable. I don't think it's by much though 🤷♂
Changes
New Features
Size
|
Summary
👋 V2 is the pet name for the next version (2.0.0) of Hyperapp. Be sure to subscribe to this PR if you want to be informed of the progress towards the release. I'm still open to feedback and ideas, so share your feedback freely!
To learn more about the upcoming architecture changes check the issue list below.
Status Progress
defer
function (setTimeout
to use fasterPromise.resolve
)Dynamic components Self-logging/debug mode #760className
attributeTypingsTry it!