1

When you access some page in Hyperstack, every model from app/hyperstack/models directory is included and sent to the browser. For the sake of security and performance, is it possible to load (automatically or by some directive) only the required code for the models and not that are used from the components?

Maybe this can be done in a way similar that policies work for data? So I am asking if there is some kind of policy in Hyperstack that restricts the code that is sent to the browser?

cavpollo
  • 4,071
  • 2
  • 40
  • 64
Michail
  • 147
  • 8

1 Answers1

2

There is no nice automatic way of doing this, but it's not too much work to achieve this. You would have to create a shared JS file of anything that's used on every page (opal, hyperstack, react, etc), and then create a separate JS file for every Page/Single Page App.


Here's a very basic example:

Application.js

# app/assets/javascripts/application.rb

require 'webpack/client_only'
require 'components/shared'

Shared JS file

# app/hyperstack/components/shared.rb

require 'opal'

require 'webpack/client_and_server'
require 'hyperstack-config'

# etc...

User Dashboard SPA:

# app/hyperstack/components/user_dashboard.rb

# Require shared models
require './models/user'

# Require shared components
require_tree './components/user_dashboard'

Todo List SPA:

# app/hyperstack/components/todo_list.rb

# Require shared models
require './models/todo'
require './models/user'

# Require shared components
require_tree './components/todo_list'

User Dashboard HTML Layout

# app/views/layouts/user_dashboard.html.erb

<%= javascript_include_tag('application.js') %>
<%= javascript_include_tag('components/todo_list.js') %>

Todo List HTML Layout

# app/views/layouts/todo_list.html.erb

<%= javascript_include_tag('application.js') %>
<%= javascript_include_tag('components/todo_list.js') %>


What I've also done to make it more dynamic is create a helper method in the controller to define the name of the separate JS file to use based on the controller. This also allows you to use only one layout file if desired:

# app/controllers/application_controller.rb

class ApplicationController
  helper_method :spa_asset

  def spa_asset
    params[:controller]
  end
end
# app/views/layouts/application.html.erb

<%= javascript_include_tag('application.js') %>
<%= javascript_include_tag(spa_asset) %>

And then inheriting controller can redefine it if the file name doesn't match the controller name:

# app/controllers/foo_controller.rb

class FooController
  def spa_asset
    'todo_list'
  end
end

Hope this helps!

  • 1
    This answers the real issue here, which is payload size. For security you should use Policies to control all CRUD access to the models regardless of what page the models are used on. If in the model's class description you have constants or other information that should not be viewed on the client, you can wrap it an `if RUBY_ENGINE != 'opal'` conditional, and the compiler will remove the code. – Mitch VanDuyn Jul 10 '19 at 18:04
  • This approach works very well and can minimize time and size of assets to be loaded (production and development -wise). To apply one must first disable autoloading for application code in hyperstck configuration. – Michail Jun 11 '20 at 08:03