legacy-paperclip icon indicating copy to clipboard operation
legacy-paperclip copied to clipboard

FFI experiment

Open crcn opened this issue 4 years ago • 3 comments
trafficstars

Idea

<repeat each={items} as="item">
  {item}
</repeat>

Then FFI rendering function registered to the engine:

export const render = ({ each, as, children }) => {
  return each.map(v => children({ [as]: v }));
}

export const compilers = {
  react(ast) {
    // compile code here
  }
}

Considerations

  • async rendering
  • FFI that requires DOM calls (like getBoundingClientRect())
  • mixing boundaries between presentational components & React - maybe not such a good idea - keep Paperclip special purpose
  • performance

crcn avatar Feb 05 '21 02:02 crcn

Alternative syntax that may be a bit better:

{#each items as item}
  <div item={item} />
{/}

☝️ syntactically I think it makes more sense to probably separate visual from non-visual elements (or narrowed to transformative elements?). Though, HTML does already kind of do this -- meta tags, link, etc etc.

FFI does make sense, I think. Though, all props need to be fed through the template engine into the FFI code, and the FFI code will basically need the flexibility to load an entire JS bundle which could drag down performance. Or maybe not? If the bundle can be loaded asynchronously as a separate hook into the app, then that may be okay. E.g:

<div component as="Test" controller="controller.js">
</div>

TODO

crcn avatar Jul 03 '21 14:07 crcn

Just a note around this for more color.

We talked about this a bit @zephraph, and I think your intuition is right that this is likely a rabbit hole that's not worth going down (at least anytime soon), but I think it's also something worth exploring to solve a few issues around Paperclip's usage that I've observed over the past year of using it on my team:

  • Some engineers don't write previews and go straight to creating PC components and using them in React + HMR. I think this is okay since PC should really get out of their way, but it's certainly a slower way to build out components.
  • PC previews will PC previews will sometimes rot since once a React component is built, it's much easier to make incremental adjustments to that. This is mostly around larger components.

☝️ this is where I was saying that PC felt incomplete as a tool for creating SPAs (which is my main area of focus since that's what I do on a day-to-day basis and how PC is able to be refined). The solutions I figured could resolve these issues are:

  • FFI so that engineers only need to attach logic and PC can remain the source of truth for the app's appearance. Though, I have lots of thoughts around this how it can be problematic (unintuitive DX, making designer more complex, with compile targets), and implementing this prematurely could really screw up the DSL.
  • Designer so that PC can be the source of truth for low-fi designing (just building block editor for designers and such).

The designer will happen anyways, and my sense is that it could resolve the issues above, so an FFI might not be necessary after all. Certainly worth generating some thoughts as they come up from time-to-time. Some areas that take absolute priority over FFIs are:

  • compiler targets
  • Designer

☝️ I think these need to happen first & need to be mature before looking at FFIs. So, this ticket is likely a veeeeery long ways away. It may actually never happen (my intuition is this).

crcn avatar Sep 23 '21 14:09 crcn

Adding onto this a bit more, I wonder if this can be scoped down to primitive components that act as building blocks for additional functionality that the engineer can create themselves. For example, if a developer wants a repeated block, then they would need to register their own.

<fragment export component as="Repeat" logic="./repeat.tsx" {items}>
  
</fragment>

⚠️ ☝️ there would need to be something like a typed definition file for Paperclip files. ⚠️ this may be a bit sticky for languages that don't have exports, like PHP

The logic for this could look something like:

export const () => ({ children }) => {
}

PC's syntax is slightly problematic where it stands for this to work since children are instances of components. There would need to be some adjustments for this to work - particularly around sending the components themselves. This could be an option:

<Repeat each={items} as="item">
 
  <!-- passing components as children -->
  <div component>
    {item}
  </div>
</Repeat>

👆 this is heading in the right direction, but is still problematic. One thing to point out is the as="item" string: this lives outside of the inferencing engine and cannot be easily typed. It's possible, but this seems like a rabbit hole not worth going down. The other thing worth noting is that this would live outside of PC's preview engine, so engineers would still need to compile their code in order to see it work with the entire app.

Alternatively, we can have Paperclip work with presentational components still, and leave the dynamic bits up to the controller that's at wrapped around the primitive component. For example:

<div export component as="Items" controller="./blah.js">
  {children || <div>I'm a preview element</div>}
</div>

crcn avatar Jan 21 '22 16:01 crcn