Skip to content
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

Support non-LiveView projects #196

Closed
msaraiva opened this issue Nov 5, 2020 · 3 comments
Closed

Support non-LiveView projects #196

msaraiva opened this issue Nov 5, 2020 · 3 comments

Comments

@msaraiva
Copy link
Collaborator

msaraiva commented Nov 5, 2020

Currently, components built on top of Phoenix.LiveComponent cannot live outside a LiveView/LiveComponent scope, which makes it impossible to use them in a non-LV project.

We have two options:

  1. Create a separate component. Something like Surface.RawComponent or Surface.FunctionalComponent
  2. Make the existing Surface.Component switch implementations accounting to the project (LV or not)

The challenge is to handle contexts consistently since the slot implementation must be completely different.

The best solution from the user PoV is certainly #2 as it would allow them to use the same component on different types of projects. Creating a separate component (#1) would be much easier to implement but will restrict its use to only non-LV projects.

@mcgingras
Copy link

mcgingras commented Dec 24, 2020

Hi @msaraiva, I'm curious how you plan on supporting non-LiveView projects given that Surface is built on top of LiveView.

The internals of Surface are a bit above my level of understanding so stick with me here, but doesn't surface rely on LiveView for rendering components? If you created non-liveview templates, where would you imagine those fitting in to the controller/view/template model?

I really love what you've done with Surface but unfortunately much of the application I'm working on does not necessarily require LV and is already written without it. I've been looking for some sort of component library that supports declarative properties, slots (like in Surface), the ability to pass children through a component etc. but I have not found anything that I particular like. All of what I've found so far are lightweight DSL like Temple.

I realize you must have plenty else to focus on and supporting non-liveview projects might not be a top priority right now. I'd love to take a crack at it myself but I'm a bit lost as to what layer you would put a library like Surface in a non-liveview project such that it fits into the traditional controller/view/template model.

Apologies if GH issues isn't the place for this conversation! Trying to learn as much as I can.

Update: What I am trying to understand is: it seems like Surface is built on top of the LV component API, and I'm unsure what the equivalent would be for non-LV without the component API.

@msaraiva
Copy link
Collaborator Author

Hi @mcgingras!

I'll have to put this on hold until we have a better picture of how Phoenix itself will handle this in the future. There might be some changes in upcoming versions of Phoenix that might force us to take a different direction depending on the chosen design.

I'm closing this issue for now. I'll reopen it and post any decision we make as soon as we have any update on that front.

Cheers.

@Zurga
Copy link
Contributor

Zurga commented Aug 26, 2021

A third option would be to provide a function that can be used in Phoenix.Controllers, maybe render_component(conn, component). This is similar to the approach taken by live_render/3.

I am currently using the following in a personal project (based on the render_surface macro, and not ready for the general public):

def render_component(conn, component) do 
  socket = %Socket{assigns: conn.assigns, changed: %{}, fingerprints: nil} 
  component = Diff.component_to_rendered(socket, component, %{}, socket.assigns)            
  {layout, template} = root_layout(conn) 
  layout = layout.render(to_string(template) <> ".html", Map.merge(%{inner_content: component, conn
  {_, diff, _} = Diff.render(socket, layout, Diff.new_components())              
  html = diff |> Diff.to_iodata() |> IO.iodata_to_binary()
  html(conn, html)
end 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants