woutdp / live_svelte

Svelte inside Phoenix LiveView with seamless end-to-end reactivity
https://hexdocs.pm/live_svelte
MIT License
1.01k stars 38 forks source link

SSR crash #49

Closed dev-guy closed 1 week ago

dev-guy commented 1 year ago

I filed this issue previously but I have since disabled SSR because I've had so many problems with it. Today even the 'counter' example wasn't working at all with SSR enabled (I'm using NodeJS 20.2.0) -- but it inexplicably started working again. The following scenario is consistent, however:

  1. git clone https://github.com/dev-guy/phoenix-ash-svelte-flowbite.git
  2. cd phoenix*
  3. git checkout add-ssr
  4. Follow the Usage section in README.md (ending with mix phx.server). Hopefully you have Postgres installed already.
  5. Go to http://localhost:4000/svelte/mermaid
  6. Go to http://localhost:4000/svelte/mermaid again (refresh the browser)

Result: Error in browser. The following is sent to the console:

[error] #PID<0.1282.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.802.0>, stream id 51) terminated
Server: localhost:4000 (http)
Request: GET /svelte/mermaid
** (exit) an exception was raised:
    ** (NodeJS.Error) got {:node_js_worker_exit, {{:badarg, [{:erlang, :port_command, [#Port<0.70>, "[[\"server/server\",\"ssrRenderComponent\"],[\"Mermaid\",{},{}]]\n"], [error_info: %{module: :erl_erts_errors}]}, {NodeJS.Worker, :handle_call, 3, [file: 'lib/nodejs/worker.ex', line: 102]}, {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 1113]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 1142]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 241]}]}, {GenServer, :call, [#PID<0.1217.0>, {{"server/server", "ssrRenderComponent"}, ["Mermaid", %{}, %{}], [binary: false, timeout: 30000]}, 30000]}}} while retrieving Exception.message/1 for %NodeJS.Error{message: {:node_js_worker_exit, {{:badarg, [{:erlang, :port_command, [#Port<0.70>, "[[\"server/server\",\"ssrRenderComponent\"],[\"Mermaid\",{},{}]]\n"], [error_info: %{module: :erl_erts_errors}]}, {NodeJS.Worker, :handle_call, 3, [file: 'lib/nodejs/worker.ex', line: 102]}, {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 1113]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 1142]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 241]}]}, {GenServer, :call, [#PID<0.1217.0>, {{"server/server", "ssrRenderComponent"}, ["Mermaid", %{}, %{}], [binary: false, timeout: 30000]}, 30000]}}}, stack: nil} (expected a string)
        (nodejs 2.0.0) lib/nodejs/supervisor.ex:80: NodeJS.Supervisor.call!/3
        (live_svelte 0.5.1) lib/ssr.ex:19: LiveSvelte.SSR.render/3
        (live_svelte 0.5.1) lib/component.ex:56: LiveSvelte."render (overridable 1)"/1
        (phoenix_live_view 0.18.18) lib/phoenix_live_view/tag_engine.ex:68: Phoenix.LiveView.TagEngine.component/3
        (kantan 0.1.0) lib/kantan_web/controllers/page_html/mermaid.html.heex:1: anonymous fn/2 in KantanWeb.PageHTML.mermaid/1
        (phoenix_live_view 0.18.18) lib/phoenix_live_view/engine.ex:137: Phoenix.HTML.Safe.Phoenix.LiveView.Rendered.to_iodata/1
        (phoenix_live_view 0.18.18) lib/phoenix_live_view/engine.ex:153: Phoenix.HTML.Safe.Phoenix.LiveView.Rendered.to_iodata/3
        (phoenix 1.7.2) lib/phoenix/controller.ex:1010: anonymous fn/5 in Phoenix.Controller.template_render_to_iodata/4
        (telemetry 1.2.1) /Users/dg/agle/202308/phoenix-ash-svelte-flowbite/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
        (phoenix 1.7.2) lib/phoenix/controller.ex:976: Phoenix.Controller.render_and_send/4
        (kantan 0.1.0) lib/kantan_web/controllers/page_controller.ex:1: KantanWeb.PageController.action/2
        (kantan 0.1.0) lib/kantan_web/controllers/page_controller.ex:1: KantanWeb.PageController.phoenix_controller_pipeline/2
        (phoenix 1.7.2) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5
        (kantan 0.1.0) lib/kantan_web/endpoint.ex:1: KantanWeb.Endpoint.plug_builder_call/2
        (kantan 0.1.0) deps/plug/lib/plug/debugger.ex:136: KantanWeb.Endpoint."call (overridable 3)"/2
        (kantan 0.1.0) lib/kantan_web/endpoint.ex:1: KantanWeb.Endpoint.call/2
        (phoenix 1.7.2) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
        (plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2
        (cowboy 2.10.0) /Users/dg/agle/202308/phoenix-ash-svelte-flowbite/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
        (cowboy 2.10.0) /Users/dg/agle/202308/phoenix-ash-svelte-flowbite/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3

Other Items of Interest

  1. http://localhost:4000/svelte/counter is the classic counter example
  2. http://localhost:4000/svelte/timeline crashes because it says < Accordion> doesn't support SSR. However, SSR works fine with this component when running under SvelteKit. It's also a devDependency (regular dependencies cause problems with SSR). No idea what's going on! Maybe it's esbuild's fault. I need to experiment with vite.
dev-guy commented 9 months ago

81 would Bun fix this?

wtedw commented 4 months ago

Not sure if this is related to your issue, but I've been dealing with a similar crash whenever the render function is called {:node_js_worker_exit, {{:badarg, [{:erlang, :port_command, [#Port<0.69>, "[[\"server\",\"render\"]

Whenever my Svelte component is rendered, it'll trigger a callback function and call live.pushEvent

 viewDidMount: function (info) {
    live.pushEvent("svelte_viewDidMount", info)
  },

However, I think because the Erlang port is in use during the render function, live.pushEvent will try using the same resource to communicate back to Phoenix and cause the crash. (no idea if this is true, just a theory). @woutdp, am I on the right track?

Anyways, I changed the callback function to become async and now there's no issues

viewDidMount: async function (info) {
  // Wrap your asynchronous code in an async function
  async function asyncOperations() {
    // Your async operations here
    await live.pushEvent("svelte_viewDidMount", info);
  }

  // Call the async function
  asyncOperations()
    .then(() => {
      console.log("Async operations completed");
    })
    .catch((error) => {
      console.error("Error in async operations:", error);
    });
},