jorgebucaran / hyperapp

1kB-ish JavaScript framework for building hypertext applications
MIT License
19.06k stars 781 forks source link

What documentation would you like to see here? #531

Closed jorgebucaran closed 6 years ago

jorgebucaran commented 6 years ago

The goal of this issue is to collect feedback about what stuff should be covered in the official documentation.

frenzzy commented 6 years ago

First of all I think it is important to have short installation instruction (getting started) and browser support list on the front page (the main README.md I mean). Also could be useful to have documentation TOC there too, make introduction for users as useful as possible, you still may keep readme short by using [more] links to docs.

Few uncovered things in docs I can imagine right now:

SteveALee commented 6 years ago

Having recently read several projects docs as a newbie I must say Vue have been the quickest to digest and left me with the least number of open questions.

rajaraodv commented 6 years ago

How to create reusable modules, how to share, how to make ensure it doesn't break someone else's app if they use your module.

SteveALee commented 6 years ago

The open questions I have for Hyper App having read around and looked at the samples are

Hope that helps

Ch4s3 commented 6 years ago

I would like a more detailed explanation of hydration, the current docs don't make it clear how you should set up html to be used by hyperapp.

timjacobi commented 6 years ago

Since the library is so small and I understand a major goal is to keep it that way I would like to see annotated source code like for underscore.js. This will greatly help new users/contributors dive into the codebase and figure out how things work or identify bugs.

selfup commented 6 years ago

@timjacobi That's really cool! I never knew that was a thing haha ๐ŸŽ‰

jorgebucaran commented 6 years ago

@Ch4s3 How much clear the hydration docs would need to be? The process is extremely simple, hence the extremely simple docs. What (part) wasn't clear?

Ch4s3 commented 6 years ago

@JorgeBucaran Yeah, I think I get the idea, but in practice it didn't seem to work when I tried it. The example html in the docs is presently:

<html>
<head>
  <script defer src="bundle.js"></script>
</head>

<body>
  <main>
    <h1>0</h1>
    <button>โ€“</button>
    <button>+</button>
  </main>
</body>
</html>

Should the contents of bundle.js be exactly what's in the Hello World example?

import { h, app } from "hyperapp"

const state = {
  count: 0
}

const actions = {
  down: () => state => ({ count: state.count - 1 }),
  up: () => state => ({ count: state.count + 1 })
}

const view = (state, actions) => (
  <main>
    <h1>{state.count}</h1>
    <button onclick={actions.down}>-</button>
    <button onclick={actions.up}>+</button>
  </main>
)

export const main = app(state, actions, view, document.body)

Can I render to just a div that contains <main></main> and not replace the whole page body? Say for example my hyperapp is just a component of an otherwise mostly plain SSR html page, and I want to prerender the html and have HyperApp take over that div, will it work?

jorgebucaran commented 6 years ago

@Ch4s3 Should the contents of bundle.js be exactly what's in the Hello World example?

Yes.

Can I render to just a div that contains <main></main> and not replace the whole page body?

Yes. The given example replaces the page body because the given container is document.body, but you can target a different container, that's why there isn't a default one.

// This is your server side rendered HTML. 
document.body.innerHTML = `
  <div id="app"><main><p>foo</p></main></div>
`

// And this is in your bundle.js
app(
  state,
  actions,
  state => h("main", {}, [h("p", {}, "foo")]),
  document.getElementById("app") // <= Any container you want!
)

I want to prerender the html and have ~HyperApp~ Hyperapp take over that div, will it work?

Yes. Imagine your SSR HTML looks like this:

<div>
  <div id="reactapp">
    ...
  </div>
  <div id="vueapp">
    ...
  </div>

  <div id="hyperapp">
    <main>
      <h1>0</h1>
      <button>โ€“</button>
      <button>+</button>
    </main>
  </div>
</div>

All you need is pass document.getElementById("hyperapp") as a container to the app() call.

Ch4s3 commented 6 years ago

Awesome, thanks @JorgeBucaran.

SteveALee commented 6 years ago

Hey @Ch4s3 how about a PR adding that info to the docs? :)

jorgebucaran commented 6 years ago

@SteveALee If it can be better re-worded and re-written, that would be ๐Ÿ’ฏ

kosirm commented 6 years ago

Working examples with playground like Try Elm which is centrally/regularly updated, because examples allover the internet are mostly non-working... Architecture diagrams, tutorials, video tutorials. Yes I know how much resources this requires... Just saying ๐Ÿ˜„

jorgebucaran commented 6 years ago

@kosirm Thanks for your feedback. Do you have something more specific in mind? The question is what kind of documentation would you like to see on this repo, but your suggestion sounds more like the kind of learning resources you wish were available, which is fine, but not the kind of feedback I am trying to collect.

SteveALee commented 6 years ago

Oh, I see Higher Order Apps (wrappers?) are a thing. Need documenting

kosirm commented 6 years ago

@JorgeBucaran

your suggestion sounds more like the kind of learning resources you wish were available

sorry for misunderstanding topic... Thanks for understanding ๐Ÿ‘

kenOfYugen commented 6 years ago

I have been using hyperapp for a while now, and I find the current documentation to be more than good enough. It's simple and to the point, as it should be. So thanks @JorgeBucaran and the rest.

What I would like to see, is a "cookbook" style of document. What I mean by that is e.g the usage of a helper getState function in actions documented. Such minor real-life applications can be most helpful, especially to newcomers. I am not certain about instructing the separation of modules in a certain way for scalability, as that's very dependent upon the domain itself.

So my suggestion basically boils down to the addition of a separate document, where all common tasks related to various use-cases can be appended incrementally. Thus, alleviating the pain of developers coming from other frameworks, as well as those accustomed to non-functional programming paradigms.

BTW, state mutation is bad, should it be allowed in the awesome list?

jorgebucaran commented 6 years ago

Thanks @kenOfYugen! ๐Ÿ˜Œ

They caught you @marcusasplund! ๐Ÿš” ๐Ÿ˜‰

marcusasplund commented 6 years ago

@kenOfYugen Thx for the heads up, please review

SamP692 commented 6 years ago

Maybe something on the approach to node checking (#378)? I imagine something small in the Virtual Nodes or Component section would suffice.

infinnie commented 6 years ago

When no validation is needed, I might as well use jQuery events for forms.

mightyplow commented 6 years ago

I think it would be helpful to mention that the return value of app() is the wiredActions object. I didn't want to pass all the actions down the tree and in the code I found that I can just use the result of app() to export this object and use these wired actions in my components via importing them.

Also an example for this would be helpful. At least I couldn't find that in the docs.

jorgebucaran commented 6 years ago

@mightyplow I admit it could be much better, but it's there. :)

mightyplow commented 6 years ago

@JorgeBucaran sorry, my bad. Well done! ;)

Siilwyn commented 6 years ago

Explain the different type of actions, why are async actions wrapped in an extra function?

because actions are usually just event handlers like onclick={action} and we don't know with which amount of arguments it will be called, maybe action(event) or maybe action(a, b, c), where the state argument should go? - @frenzzy

jorgebucaran commented 6 years ago

@Siilwyn This should be better documented, but API symmetry is one of the reasons. I want to call actions the same way that I define them.

const actions: {
  myAction: data => ...
}

so

actions.myAction(data)
infinnie commented 6 years ago

But then why do actions take only one argument? What if one were to pass extra parameters?

SkaterDad commented 6 years ago

@infinnie, to pass multiple values to an action currently, you will need to pass them as an object.

okwolf commented 6 years ago

@infinnie I'm not sure if you're familiar with Redux, but there's some similarities between the actions from Redux and ours.

Hyperapp actions don't require a type property since they are referenced to by the name of the property they are attached to within the actions object.

infinnie commented 6 years ago

However to someone who is not a Redux user that would just seem unintuitive.

jorgebucaran commented 6 years ago

But then why do actions take only one argument? What if one were to pass extra parameters?

Just pass an object.

lukejacksonn commented 6 years ago

I once tried coming up with a description for the two types of actions when models were around:

  • Static: like set which has the signature payload => model
  • Dynamic: like sum which has the signature payload => model => model

Use static actions to insert new data directly into the model. Use dynamic actions when updating the existing model or performing other (potentially async) operations before calling another action.

Siilwyn commented 6 years ago

Slightly off topic, I would love to see docs linked to a specific version using an existing well working system like Read the Docs. (example docs)

If any help is needed I'd be happy to help setting that up.

rhbecker commented 6 years ago

Would "principles" or "best practices" be an appropriate way to frame some notes or a collection of links to address stuff you should and shouldn't do?

For example, @kenOfYugen said "state mutation is bad". Ok. Why?

And what else should I know to be a good hyperapp developer?

In my first encounters with hyperapp, it occurs to me that I could probably make a mess for myself by putting the wrong things in the wrong places - putting stuff that should go in actions in state, etc.

kenOfYugen commented 6 years ago

@rhbecker state mutation is in general a potential source of errors. For hyperapp check this out #501. Practically what you are saying is what my proposal was about.

For the time being, I suggest reading all the current documentation, and replicating the examples on your own. You' ll be fine! There is no such thing as a good hyperapp developer. Because the API is minimal there is nothing new to learn, the complete opposite of e.g Angular. Just study JS from a functional language point of view, learn a new programming language and become a good programmer ๐Ÿ˜„!

Siilwyn commented 6 years ago

I also keep grabbing the following code snippet for reference, would be good to see in the actions documentation:

const actions = {
  setter: data => data,
  getter: () => state => state,
  reducer: () => state => state.count + 1,
  notmutating: () => { ... },
  async: () => (_, actions) => { actions.done() }
}

by @Swizz

okwolf commented 6 years ago

@lukejacksonn Use static actions to insert new data directly into the model. Use dynamic actions when updating the existing model or performing other (potentially async) operations before calling another action.

I do think we need to document the two different action signatures a lot better. I'm not sure I agree with static vs dynamic for the naming since both take a dynamic data argument. IMHO static would be either () => ({ ...newState }) or () => () => ({ ...newState }) where the results really are static and don't depend on any of the inputs.

We also need to make more than a single casual reference to state immutability in the actions section:

Every state update is immutable and produces a new object

I believe this should be super prominent and mentioned as part of state.

rhbecker commented 6 years ago

@kenOfYugen: Sorry if this was unclear from my last post. I wasn't literally asking why state mutation is bad. The point I was trying to make is that there are presumably some principles behind hyperapp - the arrangement of implementation into state, action, view, what ideally belongs in each of these, and what does not, etc.

So far, existing docs seem light on the why.

If I arrive here from some other framework or library that uses a different paradigm, and I don't understand the why of hyperapp, I might end up doing things I don't realize are incompatible with that why.

jorgebucaran commented 6 years ago

I am working on a couple of articles to improve the documentation ecosystem and maybe some of that will find its way into the official documentation as well. I was also thinking it would be nice to have a User's Guide, that teaches you only how to use Hyperapp without bogging down on details, like what is a VDOM, etc.

@rhbecker Hyperapp is probably one of the least intrusive "frameworks" out there, and this is not accidental but by design! ๐Ÿ˜‰

Iโ€™ve always been unenthusiastic to learning a big framework. Not because they arenโ€™t great, but on the fact that I like to know how things work "beneath the surface" and that I'm coding my own JavaScript, not the JavaScript \<insert framework here> wants me to use. The meat of it is I want to grow skills in JavaScript, not skills into frameworks.

Especially when that framework may be replaced in a few of years (if not months ๐Ÿ˜ฎ). I want transferable skills, not obsolete skills.

rhbecker commented 6 years ago

I'm not certain how much of @JorgeBucaran's last reply was in response to what I've said. FWIW, I'm reading everything after mention of me as such.

It's great that hyperapp is "minimal", "simple", "non-intrusive", "light on opinion" and all the rest. You already do a great job marketing that aspect. It's what piqued my interest, and why I'm here trying to answer the original question of this thread.

But you know what's smaller than 1 KB? 0 KB. And what's even less opinionated? No opinion at all.

There's a reason to use hyperapp, instead of nothing, right? There's a reason you've chosen to arrange your applications into state, actions, and views. You whittled it down to the smallest amount of opinion you felt was necessary - so why is what is still there still there?

There's a reason @kenOfYugen said:

BTW, state mutation is bad, should it be allowed in the awesome list?

And that @JorgeBucaran followed that with:

They caught you @marcusasplund!

Are you expecting @marcusasplund to be the last hyperapp user to make such a mistake? Providing some insight for how to deal with state isn't intrusive. It helps users of hyperapp understand why they are bothering with hyperapp, and helps them use it more effectively - helps them get the most value out it.

The README says:

Hyperapp's design is inspired by The Elm Architecture. Create scalable browser-based applications using a functional paradigm.

Ok, but why? What about The Elm Architecture is commendable? Why should using a functional paradigm be appealing to me, as someone surveying my options?

It might be the case that you're expecting your audience to find you after already coming to the same realizations you did when you decided to make hyperapp. In that case, maybe the why is superfluous. But at least some folks are gonna happen upon hyperapp without understanding why any of this is good. In my opinion, the current state of the documentation does not get into that enough to satisfy that sort of audience.

Does that make any sense?

jorgebucaran commented 6 years ago

Are you expecting @marcusasplund to be the last hyperapp user to make such a mistake?

I was just playing with Marcus. Don't take it so seriously. ๐Ÿ˜‰

In my opinion, the current state of the documentation does not get into that enough to satisfy that sort of audience.

IMO the current documentation is not very good, that's why I created this issue, and I appreciate your feedback.

jorgebucaran commented 6 years ago

Why should using a functional paradigm be appealing to me?

Telling you why FP is nice is out of the scope of Hyperapp's documentation. Talking about that is better suited for an opinionated blog post.

What about The Elm Architecture (TEA) is commendable?

Telling you what parts of TEA we embrace and what not would be a good idea. In the future, however, I want to stop marketing this so heavily, since we have diverged considerably from TEA. Right now I see Hyperapp as a "pragmatic TEA-inspired approach to state management + built-in VDOM engine".

But to answer your question, TEA inspired the very successful Redux as well as many similar spinoffs architectures, e.g., Vuex. Aso, from Elm's guide:

The Elm Architecture is a simple pattern for architecting webapps. It is great for modularity, code reuse, and testing. Ultimately, it makes it easy to create complex web apps that stay healthy as you refactor and add features.

SteveALee commented 6 years ago

Even so knowing the design decision is very interesting to know and can be educational when writing our own code using ha.

But I agree it should not be part of the core doc. Part of the extras or a linked blog post

daz4126 commented 6 years ago

@JorgeBucaran I came to Hyperapp after reading your post on SitePoint. It came at just the right time because I had been learning React and just been reading about Redux and why it was useful. The Redux site introduction did a good job about explaining why having a state object as a single source of truth and dispatching actions being the only way of updating that state. It made sense, but wiring Redux up to React seemed like quite a bit of work, especially for a simple app.

Then I read your blog post and saw a tiny JS library that seemed to do what React + Redux did in less code and a simple to use API. I'm not sure I would have appreciated what you had done if I hadn't read the Redux pages though.

Given this - I'd second what @rhbecker said - it would be nice to have something similar to the Redux pages for Hyperapp that explains the motivation behind the principles used by Hyperapp and some common use cases.

zaceno commented 6 years ago

Havent read the whole thread, so don't know if it's been mentioned already, but: Actions are such a core concept of the API, there really should be a main section dedicated to them, like we have for Virtual DOM and Lifecycle events.

algebraic-brain commented 6 years ago

Hi, I would like to see more explanations about actions. Sometimes I don't understand how they work. For example with this action

const myaction = () => async state => //blahblah...

page does not refresh and nothing happens, no error, just nothing. I'm looking for a reason for an hour and then spontaneously remove async keyword -- now it works. If you would have some more documentation and rules about implementationof actions it would help.

SkaterDad commented 6 years ago

@algebraic-brain In the case of your async function, it returns a Promise, and not a partial state object. Actions which return a Promise do not trigger re-renders. or update the state (since Hyperapp doesn't support automatically merging what the Promise resolves). Here is a link to the relevant code in hyperapp.

When you define an async action, you need to call regular, synchronous actions to update the app state & trigger re-draws. The "Gif Search" tutorial in the docs is a good example -- see the downloadGif action. https://github.com/hyperapp/hyperapp/blob/master/docs/tutorials/gif-search.md

Hope that clears things up for you! :smile:

algebraic-brain commented 6 years ago

@SkaterDad Thanks a lot, but my idea is that your explanation should be located directly in the documentation. Of course i've seen the "gif search" example but I was unable to deduce right understanding from that tutorial. Or i missed something?

jorgebucaran commented 6 years ago

@SkaterDad Thanks for explaining. @algebraic-brain I added it to the docs and will push this soon with a few other changes. I hope future arrivers will not go through this pain. Thank you, both!