alfonsogarciacaro / fable-vue

Fable bindings for Vue.js
35 stars 2 forks source link

Allow composability of components #1

Closed Zaid-Ajaj closed 6 years ago

Zaid-Ajaj commented 6 years ago

Description

Shows how to compose small components with self-contained html template into bigger components instead of registering them globally

Usage

DraggableHeader.fs

module DraggableHeader

// implementation of init and update here 

// then "export" a component 
let draggableHeader = Vue.componentBuilder init update [
    Vue.computed "headerPath" headerPath
    Vue.computed "contentPosition" contentPosition
    Vue.template (importAll "./DraggableHeader.html")
]

DraggableHeader.html

<div class="draggable-header-view"
    @mousedown="startDrag" @touchstart="startDrag"
    @mousemove="onDrag" @touchmove="onDrag"
    @mouseup="stopDrag" @touchend="stopDrag" @mouseleave="stopDrag">
    <svg class="bg" width="320" height="560">
      <path :d="headerPath" fill="#3F51B5"></path>
    </svg>
    <div class="header">
      <slot name="header"></slot>
    </div>
    <div class="content" :style="contentPosition">
      <slot name="content"></slot>
    </div>
</div>

Then use draggableHeader from a bigger component, App.fs

let app = Vue.componentBuilder init update [
    // child components
    Vue.components [
        "draggable-header-view", DraggableHeader.draggableHeader
    ]

    Vue.template (importAll "./App.html") 
]

with App.html

<draggable-header-view>
  <template slot="header">
    <h1>Elastic Draggable SVG Header</h1>
    <p>with <a href="https://vuejs.org">Vue.js</a> + <a href="http://dynamicsjs.com">dynamics.js</a></p>
  </template>
  <template slot="content">
    <p>Note this is just an effect demo - there are of course many additional details if you want to use this in production, e.g. handling responsive sizes, reload threshold and content scrolling. Those are out of scope for this quick little hack. However, the idea is that you can hide them as internal details of a Vue.js component and expose a simple Web-Component-like interface.</p>
  </template>
</draggable-header-view>

At last, mount app onto a root

Vue.mountApp "#root" app 

Loaders

using raw-loader to load the html at compile-time as a the template string

Changes

Changes the library name Fable.VueJs and the main module name to Vue

Problems

I have no idea how to communicate data between the two, i.e. with props, at least I haven't tried to get working

Also having to define dummy init and update when I don't need them

type Model = { Content : obj option }  
let init() = { Content = None }

type Msg = Msg of int
let update state = function 
    | Msg _ -> state
alfonsogarciacaro commented 6 years ago

This looks beautiful, thanks a lot! We can polish the details later :+1:

Zaid-Ajaj commented 6 years ago

Thanks! there is still a lot to do before this becomes usable. Btw, is it just me or did the compilation become a lot faster with the new fable-loader, it is still running and communicating with a daemon?

alfonsogarciacaro commented 6 years ago

I haven't benchmarked it but Fable is now a subprocess of Node (the other way around) and the communication is done through stdin-stdout so it's possible it's faster than the TCP daemon. The startup is (or at least feels) much faster now, because the dotnet cli tool took a few seconds to start.

Zaid-Ajaj commented 6 years ago

Very interesting, the compilation does feel a bit lighter now! Does this also mean you need to publish a new fable-loader/splitter whenever you update the compiler itself?

alfonsogarciacaro commented 6 years ago

Yeah, we'll have to rethink a bit the compiler version management for 2.1. Right now is a (hidden) dependency of fable-loader@next which only pins the minor version: fable-compiler-dotnet: ~2.1.0. It seems running npm update won't update fable-compiler-dotnet if fable-loader hasn't changed, so users will have to know about it to update it explicitly... or maybe it's better to just put the binaries directly in the fable-loader/fable-splitter packages and indeed pushing a new version every time the compiler, but this can be a problem to sync version when there are changes in fable-loader/fable-splitter themselves (not the compiler) 🤔