gadicc / meteor-famous-views

Famous, the Meteor Way (with Reactive Blaze Templates/Views)
http://famous-views.meteor.com/
GNU Lesser General Public License v3.0
333 stars 27 forks source link

API for adding custom components. #166

Open trusktr opened 9 years ago

trusktr commented 9 years ago

If you could abstract this away with some new API so that someone making a plugin for fview doesn't have to worry if it works just in app mode or not.

I imagine that making a plugin should ideally be super simple. For example, famous-views could require components to be RenderNodes at the top level (I think you mentioned that they are in another conversation) which are the basis for constructing the render trees, then devs could do something like the following with their custom components:

// if their component is, extends, or imitates a RenderNode:
FView.registerComponent(MyComponent /*a class*/, "FviewComponentName" /*template name*/, true /*accepts children?*/);

// if their component is not, does not extend, or does not imitate, a RenderNode:
FView.registerComponent({
  component: MyComponentThatDoesntHaveARenderNodeAPI, // whatever it is, who knows.
  create: function(component, templateOptions) { // the create function describes how to set up a RenderNode containing the desired 3rd party component.
    return (new RenderNode).add((new componentClass()).foo.bar.modifier); // somewhere in the component is the base modifier of the component, for example, who knows.
    // create must always return a RenderNode (or something that extends or imitates it).
  }
}, "FviewComponentName", true);

then in the template

+FviewComponentName
  +ChildComponent

If someone's component isn't a RenderNode or isn't extending a RenderNode at the top level, they could easily adapt by using an Object literal to specify the component and create function that must return a RenderNode.

If the user wants add sub components to his component, f.e.

+MyComponent(foo="...")
  +Modifier
    +Surface(prop="...")
  +SomeOtherComponent(blah="...")

then that's no problem. Since the FView.registerComponent method is used to specify a RenderNode or how to create a RenderNode, then by default FView can just call RenderNode.add for each of the sub components. Ultimately, it will be vanilla Famo.us under the hood determining if those calls to .add are valid (i.e. checking if you have a Modifier or Surface (or things that imitate them) inside the RenderNode). But just in case the component has specific logic for adding things, the object literal could also accept a add property that specifies a function describing how to add things to the component, in which case FView behind the scenes calls this alternate add method instead of the RenderNode's add method when all sub components are instantiated. For example, extending the previous example:

// if their component is not, does not extend, or does not imitate, a RenderNode:
FView.registerComponent({
  component: MyComponentThatDoesntHaveARenderNodeAPI,
  create: function(component, templateOptions) {
    return (new RenderNode).add((new component()).foo.bar.modifier);
  },
  add: function(myComponentInstance, children) { // subComponents is an array of RenderNodes (or objects with the RenderNode API).
    children.forEach(function(child) {
      // f.e. the dev's component might only accept Surfaces with it's API, who knows:
      if (child._object instanceof Surface) {
        myComponentInstance.foo.bar.addChild(child._object);
      }
      // non-Surface children are simply ignored by this function, and should ultimately be garabage collected (when MixedMode fixes the currently infamous memory leak).
    });
  }
}, "FviewComponentName", true)

Lastly, as you see in the previous jade snippet, the custom component accepts attributes (e.g. the foo="..."). That is what the create method's templateOptions parameter is for. The dev can do what he wants with them, for example, inside the create function:

    return (new RenderNode).add((new component(    templateOptions    )).foo.bar.modifier);

where templateOptions is an object literal containing each attribute, e.g. { foo: "..." }. It could be possible to manipulate templateOptions with other FView methods before passing them into the component constructor, etc, etc, whatever the dev desires.

With just these three properties in the object literal passed into registerComponent, we pretty much have everything we need to define custom components with a single, easy-to-use, consistent API, and users don't need to worry about app mode or not, their components just work.

This is all just an idea, but something this simple (complexity behind the scenes of famous-views) would be nice.

gadicc commented 9 years ago

Hey, saw the comment first. My reply from there:

Hey. Unfortunately we can't abstract away things like whether a plugin works in appMode or not. If not in appMode and there's no mainCtx, what does fview-lagometer attach to? It's meant to just work out the box. Obviously for multiple contexts, yeah, we'd like to be able to do a +Lagometer in the markup, that's the "doesn't work for now..." part in the error :>

Otherwise, I think everything you described already exists? See http://famous-views.meteor.com/views/README. Don't worry about the "view" name :) You can override the create() function too, that's not in the docs but I'll add it now: https://github.com/gadicc/meteor-famous-views/blob/master/lib/views.js#L22.

Let's continue the discussion here. There is also other stuff we could add too, like some hooks for plugins to all use at the same time, and maybe custom loggers which show the plug name, etc.

trusktr commented 9 years ago

@gadicc

Re: registering views

I just read http://famous-views.meteor.com/views/README. Doh! I should've looked first, but yeah, basically that. We were thinking the same thing. xD Let me actually try it before giving more ideas so they're more meaningful. :>

Re: appMode and stuff

Unfortunately we can't abstract away things like whether a plugin works in appMode or not

Why not? Just create a convention like famous-angular does. Their convention is that there's only one way to make a context: <fa-app>. If you want a "full page" app, then you just put an <fa-app> inside the <body>, and make it take up the full size of the body. Every <fa-app> has it's own div with a context on it, even if it's the only child in the body template.

You could do the same thing with famous-views by requiring a +famousContext and (IMHO) deprecating (or better yet, entirely dropping) the old app mode. It makes sense for widely established libraries to maintain backwards compatibility with their stable APIs, but famous-views is brand new, so there's no need to be backwards compatible with APIs that are been stepping stones towards what a stable API should be.

Following this convention, fview components would always need to be inside a famousContext:

+famousContext
  +Lagometer(size="[200,200]")

The docs for fview-lagometer can explain that a Modifier gets created, with it's size set to [200,200], and inside that is the lagometer.

If you just drop "app mode", and make +famousContext a requirement, like what famous-angular does with <fa-app>, everything will be easier to understand and work with. Using the famousContext convention would be super beneficial for the API: it'd make fview-plugin component registration clean, precise, and universal; users won't have ifs, ands, or buts about how to use famous-views; and developers won't have concerns or confusion about which "mode" to make their fview-plugin will work with (one? the other? both?). Devs will have a single way to create plugins that work in a single environment (inside +famousContext), concisely and precisely. Sure, you might have to make some code changes, but it's worth it. It will avoid fragmentation where some plugins work on ly in app mode, other only inside famousContext, etc. That's friction that no end user should have to deal with.

Famous-views isn't widely adopted yet (all the plugins @PEM-- and you have recently added are super awesome, but they are brand new and testing the waters of the API), so people should expect changes to the maturing API before it becomes completely stable and out of beta state.

Anyways, whatever you decide to do I will gladly live with. :)

trusktr commented 9 years ago

Adding to the idea of reducing friction for end users, I think that all the default Famo.us views shouldn't need to be registered manually by the end user. Users should be able to do +Scrollview without having register it with FView.registerView('Scrollview', famous.views.Scrollview);. It's understandable that this should be required for custom views that aren't shipped with Famo.us, but supporting all the default Famo.us views out of the box would expected.

Those are my humble opinions on reducing friction for developing fview-plugins, and developing with fview.

trusktr commented 9 years ago

In https://github.com/gadicc/meteor-famous-views/issues/113#issuecomment-64985025 you said

Also since mixed mode gets rid of modifiers, definitely makes sense to drop registerModifier and registerView for just register).

A single method makes sense. Ultimately it doesn't matter what Famo.us decides can be inside a RenderNode (no more Modifiers, now Surfaces and Planes among other things). The overarching idea is that we have a tree of RenderNodes, so a nice convention would be to require myViewClass in FView.registerView('MyView', myViewClass, {...}) to be a RenderNode, but if it's not a RenderNode then require the create method to return a RenderNode. (I'm repeating this part of my original comment a little). This will make development of plugins precise, because after all, we're creating render trees ultimately when we make a +component.

If this._view is a RenderNode, then

  // If exists, called to instantiate the famo.us class
  create: function(options) {
    return new this._view.constructor(options);
  },

would work, and would be useful for special initialization steps. If this._view isn't a RenderNode, then you'd need to do something like

  // If exists, called to instantiate the famo.us class
  create: function(options) {
    return (new RenderNode).add(new this._view.constructor(options));
  },

If your plugin isn't going to have anything to do with the explicit creation of a sub-rendertree (f.e. famousEach doesn't explicitly create a node, it just loops and adds multiple of them) then there can be another method for that, which brings me to the following idea:

Idea: perhaps have two methods: registerNode and registerHelper. As the names imply, registerNode is for explicitly registering a RenderNode that has whatever sub-rendertree you wish, and registerHelper is for when you want to register a +component that will not create a sub-tree, but will receive references to all it's children or it's template so it can manipulate them somehow (e.g. registerHelper('famousEach', ...).

Relating to your comment at https://github.com/gadicc/meteor-famous-views/issues/113#issuecomment-64985025, maybe the term then could be "nodes"? Ultimately that's what a part of a render tree boils down to: a (render) node.

trusktr commented 9 years ago

(Note: I put my original comment from https://github.com/gadicc/fview-lagometer/commit/c2a4e0dd05399e0530f2ca9dc6d5394741acd5ce#commitcomment-8754938 at the top of this thread, so it's easier to reference.)

trusktr commented 9 years ago

Does my registerNode vs registerHelper idea make sense? I'm more interested in registerNode. In fact, I'd be fine with just having that single method, as I could return a RenderNode with all sorts of functionality attached to it (for example something like mjn:fview-animate). RenderNodes don't actually have to contain subtrees, they could just be an empty RenderNode (without a Modifier, Surface, or etc in it). F.e., if I registerNode('MyComponent', MyCompClass, ...) and MyCompClass is an empty RenderNode that does nothing, or the create method returns an empty RenderNode that does nothing, then the following two examples would be equivalent in outcome to the end user of the app:

+Modifier(...)
  +MyComponent
    +MyComponent
      +MyComponent
        +MyComponent
          +MyComponent
            +Surface(...)

behaves exactly the same as

+Modifier(...)
  +Surface(...)

But I could see registerHelper being useful for taking advantage of templating features like how +famousEach does, so, wait, yeah, a method other than registerNode would be needed. I really need to start playing with registering my components as fview-plugins. I have a blocker right now in that I need to make a dist of my project that contains compiled ES5 which would then make it easier to start wrapping my stuff for meteor, then start putting things in fviews.

gadicc commented 9 years ago

Haha wow you wrote a lot here :)

Ok so appMode isn't a famous-views thing, it's a famous thing. To be clear, we are now promoting the convention now of explicitly putting a +famousContext in body, with id="mainCtx" being a special attribute that turns on appMode (see QuickStart, API docs, and draft university pages, etc).

appMode means that we have a single "main" context which occupies the full viewport and handles everything. I don't think it's reasonable to ask the user to set up all this CSS on their own (equivalent of .famous-root class on html,body, i.e. full width/height, overflow:hidden, no margins, no padding and preserve-3d. I'd like users to know that if they set up a main context, that's all they have to do to have an app work as a full page app without any additional work.

The idea with lagometer is that the user can install the plugin and have it work out the box. They just meteor add gadicohen:fview-lagometer and can use it straight away without adding extra mark up. And remove it at any time without extra markup. If it detects a main context, it can just add itself automatically. If there's no main context, then it's not clear where it should go, and will require the user to put +Lagometer somewhere (which as mentioned, is not implemented yet but is planned -- a little more complicated since fview-lagometer is never deployed). This is what I mean when you can't get rid of checking whether appMode is on or not... if we check, we can make it super easy for the dev to integrate if they're doing a full page app, and a little extra work if they're not. I really think this is a winning pattern for ease-of-use. Especially when potentially lots of plugins are involved. It's a chore to add/remove extra markup in the page for every install/uninstall.

Will reply to the "node" thing in the other thread. What you say about renderNodes makes sense, but as I said, I'd like to save these kinds of changes for when mixed mode comes out. The current way of doing things makes sense for the current version of famo.us and is quite commonly used... I'd like to save all the big changes for a single big version upgrade. It's not only plugin authors that are using the API, but all our users too. As it is, with our very small changes until now but fast development pace, we get some issues with that.

gadicc commented 9 years ago

Last thing, still looking very forward to seeing fview versions of your components :) When can we expect them? :)

trusktr commented 9 years ago

Yeah, I can't wait to try it!! It's hard to say how long. I'm just learning a lot of jspm experimenting with the architecture of my site. I want to try compiling things for "production", both my site and my components. At that point I'll try getting them into fviews. Can't wait. :D

I forgot about the mainCtx context thing. I remember you mentioning it.

appMode isn't a famous-views thing, it's a famous thing

I know it's how vanilla famous works, but famous-angular gets rid of it, so one must use fa-app anytime they want a context, and that context never takes over the body. I actually think this is very nice, and better than Famo.us' default assumption that Famo.us should just take over the whole page, when in fact it's not necessary. For example, look at the Famo.us University Angular tutorials. The contexts aren't on the body, but the demos appear to be "full page" as far as the end user is concerned.

I don't think it's reasonable to ask the user to set up all this CSS on their own (equivalent of .famous-root class on html,body, i.e. full width/height, overflow:hidden, no margins, no padding and preserve-3d.

Indeed, it is totally unreasonable. Famous-angular is solving this by applying the CSS to the div containers that it creates. The container created by <fa-app> has a default width and height of 100%, so when it's in the body, it takes up the whole space of the body, thus it's a whole page app without putting the context on the <body>. So basically, if using the same method as famous-angular, then "all they have to do to have an app work as a full page app without any additional work" is:

body
  +famousContext

and it just fills the body. If a dev doesn't want it to be full page, then the dev could put it inside some element, or just set it's size:

body
  +famousContext(width="200", height="200")

and `id="mainCtx"' wouldn't be required and would reduce some usage friction.

If it detects a main context, it can just add itself automatically

Aah, I see what you've done. Nice idea! What about not worrying about there being a mainContext anywhere in the registration process, then, just having the plugin create a new context entirely and making sure that this new context is on top of the other elements on the page (including other contexts) with zindex:1000000, then putting the lagometer in there? Then it wouldn't matter any contexts exist at all. Since all contexts run on a single Engine, this should work. So you could still do this even if there's only a single type of context (no mainCtx).

I'm not entirely sure, but it seems like what gets returned from the create method will be set() into the MeteorFamousView render node. Theoretically, if a dev keeps up with Famo.us as it changes to mixed mode, then the dev can return anything that's acceptable in a RenderNode and it should be fine for when Mixed Mode comes out, assuming you're not creating any Modifers behind the scenes, but this might be limiting since the new RenderNodes can have more than one thing in them last I saw. If you force the dev to return a RenderNode from create, then the dev could put whatever he wants into the RenderNode before returning it, so famous-views wouldn't have to worry about Mixed Mode, only the dev would before returning the eventual RenderNode. I think the RenderNode.add and .set API will remain the same, it's just what you put in the RenderNodes that makes the difference. But yeah, so if an official convention is to return a RenderNode from create (or enforce it by throwing an error if it's not a RenderNode), then it would be up to devs to keep up with Famo.us, as far as the component registration process goes.

trusktr commented 9 years ago

@gadicc

Last thing, still looking very forward to seeing fview versions of your components :) When can we expect them? :)

Well, I've recently finally added my components to npmjs.org: https://www.npmjs.com/package/infamous

I've gotta make it compatible with ES5 (a build step with traceur that puts it in a dist folder as ES5? Or perhaps load es6-module-loader and traceur? Any ideas?), then I should be ready to start trying to get them into famous-views. :)

trusktr commented 9 years ago

@PEM-- @gadicc Happy new year guys! I've finally gotten my UI components up on GitHub and consumable by anyone (hopefully) even if they aren't using ES6 and no matter what module system they use. With what little free time I have, I'd now like to focus on pumping out components and updating the README with usage for each component. It'd be nice to get the components into famous-views now too! Alright, off I go to fix my PushMenuLayout so that the options can be passed into the constructor instead of hard coded.

PEM-- commented 9 years ago

Just starred it :star: :smile: Sounds like a new set of famous-views plugins are on their way!

trusktr commented 9 years ago

Almost there guys!!! I made it consumable by browserify, and webpack. I'm adding a jspm worflow, and I might also add a bower+requirejs workflow, along witha global build. After having handled consumability of my lib, then I'd like to focus making components and/or getting it running in meteor. Slowly but surely. xD @PEM-- @gadicc

trusktr commented 9 years ago

Are you guys on http://gitter.im yet?

trusktr commented 9 years ago

I opened http://gitter.im/trusktr/famous just a few moments ago, for the time being until if/when famous makes one. No one's there yet. xD

trusktr commented 9 years ago

@gadicc @PEM-- Alright, I'm (finally) going into Famo.us today to start making more things. I'd like to think about model-view binding. I'd like for it to be doable programmatically with my components, but also with famous-views. @kof made cyclic, and with famous-views it relies on Meteor's stuff. Mind taking a look at infamous, try installing it with one of those workflows in the README, and possibly thinking of a direction we could take so that as I make components, they are easy to use with famous-views? I can add a fview-infamous repo to the infamous org. Yeah, I think I'll do that. :D

trusktr commented 9 years ago

@gadicc @PEM-- Ok, I added you guys to https://github.com/infamous/meteor. I also made https://atmospherejs.com/infamous, but on accident it's a developer account, so I'm trying to see if I can switch it an org. ALso @gadicc, https://atmospherejs.com/famous seems to be taken, but unused. We might be able to ask if we can take it over, then that can be the official famous integration. meteor install famous:views, and @mcbain could put mjn:famous at famous:src or something.

trusktr commented 9 years ago

@gadicc @PEM-- I changed the name to meteor-famous-views. I think that is better to show the relation. :D I want to get started with it real soon. I suppose I should first make the wrapper for infamous on Atmospherejs first. Maybe I can copy what @mcbain did with mjn:famous? Then make the fviews plugin after that, and perhaps call it infamous:fviews? What do you guys think? Is there an install hook I can take advantage of to convert ES6 to ES5? Or should I just make a repo specifically for the atmosphere version that contains the pre-built ES5?

trusktr commented 9 years ago

@gadicc @PEM-- Wait! I changed it one last time. fview-infamous. Muuuuch better.

PEM-- commented 9 years ago

Yeah, much better :+1:

gadicc commented 9 years ago

Hey guys, sorry, I'm back from Thailand and have my laptop again but I still have a bit of travel ahead of me. I promise this will get my full attention as soon as I'm able, although realistically that might only be next week. Appreciate the patience and hope to come back from this holiday with a lot of energy :)

trusktr commented 9 years ago

sweeeeeet. Have fun!!

gadicc commented 9 years ago

@trusktr, here we go, got you started :)

https://github.com/gadicc/fview-infamous

I couldn't fork and PR since infamous/fview-infamous was empty. Maybe delete that and fork mine, unless you already have something going on there.

For any discussion, let's open another issue (maybe on that repo). I'm probably not around for the rest of today though.

Just for mjn:famous for now.

trusktr commented 9 years ago

Oops, I previously meant to add you to the org. Invite sent!

Thanks for doing this!! This is awesome, a great starting point for me to learn from. Thank you! :D

How would I dev with this locally? Is there something similar to npm link for meteor?

gadicc commented 9 years ago

Cool. Pushed to infamous org repo and deleted the gadicc one. Added CONTRIBUTING.md - hope it's all clear and works like I'm expecting :> Let me know if you run into any trouble. I just did the square demo from the snippets.

gadicc commented 9 years ago

Oh also trusktr.io is down and the whois says pendingDelete?

trusktr commented 9 years ago

Sweet, thanks a ton for this! It's a lot easier than I thought to get deving. I've added two methods to PushMenuLayout, setMenu and setContent, so now I'd like to figure out how to make this work:

+PushMenuLayout(...)
  +menu
    +AnythingYouWantHere
    +AnythingYouWantHere
  +content
    +AnythingYouWantHere

so that menu and content are like an interface to both add methods. Oh man, can't wait to see it working!! :D

I had to renew trusktr.io (for $200 because that's what happens when you fail to renew a .io domain more than 5 days prior to the expiration date), now I gotta set up the new https, so it's a red https until this weekend. :)

gadicc commented 9 years ago

Damn thieves all over this internet! :(

Yeah it's super easy to integrate vanilla famo.us stuff, the hardest part is actually just getting it to work with both mjn:famous and raix:famono. If it was just famono, you could include the upstream lib straight from bower/github. Although either way, if you wrap something in the package you have to bundle the wrapped component code in the package too... there are ways around it but they're not so convenient for the dev. Anyways :) Most important thing is how the wrapper itself works, those other issues will all get solved eventually.

Re PushMenuLayout, maybe you could do something similar to the approach I used for HeaderFooterLayout (docs, wrapper):

+PushMenulayout
  +SequentialLayout target="menu" direction="Y"
    +Surface etc
    +Surface etc
  +Modifier target="content"
    +Surface etc

and then

   FView.registerView('PushMenuLayout', Infamous.PushMenuLayout, {
    add: function(child_fview, child_options) {
      var target = child_options.target;
      if (!target)
        throw new Error('PushMenuLayout children must specify target="menu/content"');
      var method = 'set' + target.substr(0,1).toUpperCase() + target.substr(1);
      this.view[method](child_fview);
    }
  });
trusktr commented 9 years ago

Hi @gadicc! I'm trying to get the fview-infamous demo working, but no luck. I've updated build.sh to this:

#!/bin/sh

mkdir build

# TODO, check for
#npm install -g browserify 6to5

npm install infamous army-knife

mv node_modules/ build/

It didn't have mv node_modules/ build/ before. So after node_modules are in build, then I

cd demo
meteor

which launches it on port 3000, then in the browser I see this:

screen shot 2015-03-30 at 10 55 24 pm

Any ideas?

Side question: When I publish it to Atmosphere, how do the steps of build.sh get carried out? Do we need to npm install before publishing to Atmosphere so the package contains all the dependencies?

gadicc commented 9 years ago

Oh oops, yeah, that should be in the build in the directory.

The problem is that you have a new dep in the Infamous code, var simpleExtend = require("./utils").simpleExtend; - where is it coming from? Don't see it in the repo either. You need to include the source code in the package.

Yeah, build.sh does everything in advance and then the actual package is published with all the necessary files. Meteor does actually allow "real" npm dependencies, but for node/server code... I'm not really sure how to use npm for client code. Also, Meteor are currently working on native 6to5 support, which will also ease this whole process for us in the future.

trusktr commented 9 years ago

@gadicc Hey, I have no job now, so I have more free time! Woo!

I'm using ES6 modules with webpack by compiling my entry point that lives outside of my meteor app folder into a bundle placed inside my meteor app folder so that Meteor loads it. It's nice!

I really dislike how we have to api.addFiles to our project (i.e. it means I have to solve that simpleExtend problem you noticed in your last comment), so with webpack I'm trying to write an entry point like this (without using the fview-infamous package):

import                               'famous/core/famous.css'

import Molecule                 from 'infamous/Molecule'
import Plane                    from 'infamous/Plane'
import DoubleSidedPlane         from 'infamous/DoubleSidedPlane'
import Grid                     from 'infamous/Grid'

import Calendar                 from 'infamous/Calendar'
import Cube                     from 'infamous/Cube'
import PushMenuLayout           from 'infamous/PushMenuLayout'

Logger.setLevel("famous-views", "info");

FView.registerView('Molecule', Molecule);
FView.registerView('Plane', Plane);
FView.registerView('DoubleSidedPlane', DoubleSidedPlane);
FView.registerView('Grid', Grid);

FView.registerView('Calendar', Calendar);
FView.registerView('Cube', Cube);
FView.registerView('PushMenuLayout', PushMenuLayout);

and now the dependencies are all managed with npm/webpack so simpleExtend is there, and we didn't have to write our own require function as that is all handled by webpack!

Then inside the meteor app folder I have something like

head
  title awesome
  meta(name="viewport" content="width=device-width, maximum-scale=1, user-scalable=no")
  script(src="/app.js")

body
  +famousContext(class="context" perspective="1000")
    +Plane(
      template="title"
      size="[200,200]"
      content="Hello."
      properties='{"backfaceVisibility":"visible","background":"pink","padding":"5x"}'
    )

template(name="title")
  h1 Scrollview Example

It's not working yet though. I'm getting a single error in the console:

Uncaught TypeError: Cannot read property 'commit' of undefined     famous-global.js:1114

My project structure is like

.git/
meteor/
  both/
  server/
  client/
node_modules/
src/
  app.js
  folderWithES6Modules/
  otherFolderWithES6Modules/
package.json
webpack.config.js

where webpack.config.js can look like

module.exports = {
    entry: "./src/app.js",
    output: {
        path: './meteor/client',
        filename: "app.js" // Meteor simply loads the bundle
    }
}

Everytime I change source code outside of the meteor app folder, webpack compiles into Meteor's folder and Meteor hot-pushes.

The problem I already see is that there's the famous library code imported by famono or mjn:famous that is required by famous-views, and then there's the famous library code that I'm importing in my bundle, so double the famous code.

I don't know if that related to the aformentioned error. The famous classes are not coupled, so in theory I should be able to FView.registerView my stuff using the second famous' classes.

I pushed what I have to a repo: https://github.com/trusktr/meteor-with-webpack.

To start the app:

# in one terminal
npm install
webpack --watch

# in another terminal
(cd meteor && meteor)

Do you get the same error in browser?

trusktr commented 9 years ago

@gadicc Famo.us Mixed Mode is soooo much nicer than 0.3.5. It's got the same concept of RenderTree and RenderNodes, but the way you construct your tree is just totally different. Things live outside of rendernodes, and communicate via a RenderNode's Dispatcher (as opposed to current RenderNodes containing things like Modifiers or Surfaces). It's changing a lot still, but by this summer there should be a stable release.

trusktr commented 9 years ago

Would you like to make a Gitter room for famous-views so we can chat there? Or perhaps have a video chat on Hangouts or Skype?

gam-ragnar commented 9 years ago

Lets make a gitter!

gadicc commented 9 years ago

@trusktr, that's very good news (kinda hehe). Thanks also for the update re mixed mode, is there anything out public yet about any of this?

Re webpack, I don't know anything about it, unfortunately. But in general, to be honest, I don't think it's a good idea to use npm install and a webpack --watch process outside of the Meteor toolchain. The dependency management in Meteor native is excellent, but I agree it's not as finegrained and very problematic currently mixing with require.js / ES6 imports. From a brief search about this it seems like you're on top of all the community attempts around this :>

Incidentally, it's no problem using famono and require and to bring everything in bower, if using famous via famono... but for fview-* packages we have to support famono AND mjn:famous (well, let's say, "and everything else"), so we try package it up as a "regular" Meteor package too. This makes it very accessible to everyone, to just add as a regular meteor package with 1 line and no extra work.

However, while this is inconvenient for the developer (as a trade off for ease of use for users), it's not really that hard (but no, not ideal) to add all the dependencies in the required order. And yes I do hope in the long term we'll have a better way to handle this. But don't dismiss the pros of Meteor's package system because of this one issue (notably, the version constraint solver).

Re gitter, I'm happy for one to opened but I might be conspicuously absent. I am super behind on famous-views and struggling to juggle my job, famous-views and other open source projects. Any time I do have for the project is going to go straight into coding and existing issues. Although in the future I'd love to be around for something like that.

I'm away for the weekend, let's chat more on Monday. Have a good one! And thanks always for your ongoing enthusiasm about and contributions to the project :)

trusktr commented 9 years ago

@gadicc Mixed Mode is very likely to be released this summer from what I hear! :D

dependency management in Meteor native is excellent

Indeed dependency resolution is very good, but the purpose of Meteor's dependency resolution is to figure in what order to load files; it doesn't provide files/modules the means to import direct references exported from any other files/modules (f.e. like what require()/module.exports and import/export do for you in other environments). It seems (I haven't read the isobuild code) that the only way things are exported from Meteor packages is that exports are added to global scope and those packages are simply load before packages depending on those globals, so it's not quite the same type of dependency handling. It quite contrary to the norm everywhere outside of Meteor and might not be inline with the ES6 Module future.

but for fview-* packages we have to support famono AND mjn:famous (well, let's say, "and everything else"), so we try package it up as a "regular" Meteor package too. This makes it very accessible to everyone

Very accessible to everyone inside the Meteor ecosystem*. I've imagined a way to use webpack inside the Meteor packages here (you might have stumbled on it). Atmosphere packages that depend on the base package (username:webpack or something) would all be written with CJS or ES6 modules. I have it all mapped out in my mind based on what know of webpack and Meteor so far, and it will work for sure. There might be a better way but I'm not sure what that is yet.

I've forked famous-views, and I will be making a port of it to CommonJS for npm. It will depend on Famous from npm, etc, so I can build it into my webpack bundle. I'm using ES6 Modules in general which I really don't want to drop for Meteor's packaging system. The nice thing is that all of Meteor's APIs are available once the bundle gets loaded!

I'm happy for one to opened but I might be conspicuously absent.

Yeah, just sign up on http://gitter.im, it only takes a click to log in with GitHub! You don't know what you're missing out on yet!

trusktr commented 9 years ago

I just checked out the black magic in Famono (cc: @raix). It's amazing, but it's very AMD-specific and the JavaScript community in general is moving away from AMD. Famous may switch to ES6 Modules soon, based on what I've heard.

Will a global version of Famous still be in the picture with Mixed Mode @TheAlphaNerd? :point_left:

trusktr commented 9 years ago

@gadicc Okay, so I've looked through it, and it seems that to make famous-views work how I want it the best way to do it is to just dive in and make the idea I suggested here, then update my fork of famous-views to use the new webpack package so it can depend on Meteor packages and npm packages.

Using this new package will prevent us from having to write things like:

// Load as ealry as possible, and keep trying
if (typeof(famous) !== 'undefined') {
  log.debug("Starting up.  famous global found while loading package, great!");
  FView.startup();
}
else
  Meteor.startup(function() {
    if (typeof(famous) !== 'undefined') {
      log.debug("Starting up.  famous global found during Meteor.startup()");
      FView.startup();
    } else {
      log.debug("No famous global available in Meteor.startup().  Call FView.startup() when appropriate.");
    }
  });