Module: Isorun::ViteAppHelper

Defined in:
app/helpers/isorun/vite_app_helper.rb

Instance Method Summary collapse

Instance Method Details

#isorun_vite_app(id, options = nil, ctx: {}) ⇒ String

The isorun_vite_app helper is the most convenient way to server-side render a JavaScript application built with vite, including state extraction and automatic rehydration. The helper tries to render the application and will also inject the client-side code immediately after the rendered result.

Examples:

Renders a JavaScript application

<html>
<body>
  <%= isorun_vite_app("my_app") %>
</body>
</html>

Parameters:

  • id (String)

    An ID representing both, the asset bundle, and by convention, the target node (e.g. <div id="my_app">)

  • options (Hash) (defaults to: nil)

    All valid tag options can also passed as options to this method

  • ctx (Hash, nil) (defaults to: {})

    Pass variables to render context

Returns:

  • (String)

See Also:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'app/helpers/isorun/vite_app_helper.rb', line 25

def isorun_vite_app(id, options = nil, ctx: {})
  ActiveSupport::Notifications.instrument "start.render.isorun", { ts: Time.current }

  # if id has a file extension, we extract the extension and reduce the ID
  # to the basename
  extension = (File.extname(id) || ".js").delete_prefix(".")
  id = File.basename(id, ".*")

  module_path = Isorun.config.module_resolver.call(id)

  ssr_html = Isorun::Context.create(receiver: Isorun.config.receiver) do |context|
    render_context = { environment: Rails.env.to_s }.merge(ctx)
    render_function = context.import.from(module_path)

    if render_function.blank?
      Rails.logger.warn("[ISORUN] the requested app does not exist or " \
                        "does not have a server entrypoint. Please " \
                        "check if an asset with filename " + "
                           `public/vite-ssr/ssr.js` exists.")
      return ""
    end

    html = render_function.call(render_context)

    ActiveSupport::Notifications.instrument "finish.render.isorun", { ts: Time.current }
    ActiveSupport::Notifications.instrument "stats.isorun", Isorun.stats

    html
  end

  html = if ssr_html.present?
           options ||= {}
           options[:id] = id

           tag.div(**options) do
             ssr_html.html_safe # rubocop:disable Rails/OutputSafety
           end
         else
           Rails.logger.warn("[ISORUN] The server-side rendered result is empty.")
           ""
         end

  html += "\n"
  case extension
  when "js", "jsx"
    html += vite_javascript_tag("#{id}.#{extension}")
  when "ts", "tsx"
    html += vite_typescript_tag("#{id}.#{extension}")
  else
    Rails.logger.warn("[ISORUN] unsupported client application extension: `#{extension}`")
  end
  html.html_safe # rubocop:disable Rails/OutputSafety
end