Class: Mayu::Environment

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/mayu/environment.rb

Constant Summary collapse

PAGES_DIR =
"pages"
STORE_DIR =
"store"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, metrics) ⇒ Environment

Returns a new instance of Environment.



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
78
79
# File 'lib/mayu/environment.rb', line 43

def initialize(config, metrics)
  @root = T.let(config.root, String)
  @app_root = T.let(File.join(config.root, "app"), String)
  @config = config
  @encrypted_marshal =
    T.let(
      EncryptedMarshal.new(config.secret_key, default_ttl: 30),
      EncryptedMarshal
    )
  # TODO: Reload routes when things change in /pages...
  # Should probably make routes into a resource type.
  @routes =
    T.let(
      Routes.build_routes(File.join(@app_root, PAGES_DIR)),
      T::Array[Routes::Route]
    )
  @reducers =
    T.let(
      State::Loader.new(File.join(@app_root, STORE_DIR)).load,
      State::Store::Reducers
    )
  @resources =
    T.let(
      if @config.use_bundle
        Resources::Registry.load(
          File.read(@config.paths.bundle_filename, encoding: "binary"),
          root:
        )
      else
        Resources::Registry.new(root: @root)
      end,
      Resources::Registry
    )
  @metrics = metrics
  @fetch = T.let(Fetch.new, Fetch)
  @init_js = T.let(nil, T.nilable(String))
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



28
29
30
# File 'lib/mayu/environment.rb', line 28

def config
  @config
end

#encrypted_marshalObject (readonly)

Returns the value of attribute encrypted_marshal.



38
39
40
# File 'lib/mayu/environment.rb', line 38

def encrypted_marshal
  @encrypted_marshal
end

#fetchObject (readonly)

Returns the value of attribute fetch.



36
37
38
# File 'lib/mayu/environment.rb', line 36

def fetch
  @fetch
end

#metricsObject (readonly)

Returns the value of attribute metrics.



40
41
42
# File 'lib/mayu/environment.rb', line 40

def metrics
  @metrics
end

#reducersObject (readonly)

Returns the value of attribute reducers.



32
33
34
# File 'lib/mayu/environment.rb', line 32

def reducers
  @reducers
end

#resourcesObject (readonly)

Returns the value of attribute resources.



34
35
36
# File 'lib/mayu/environment.rb', line 34

def resources
  @resources
end

#rootObject (readonly)

Returns the value of attribute root.



26
27
28
# File 'lib/mayu/environment.rb', line 26

def root
  @root
end

#routesObject (readonly)

Returns the value of attribute routes.



30
31
32
# File 'lib/mayu/environment.rb', line 30

def routes
  @routes
end

Instance Method Details

#create_store(initial_state: {}) ⇒ Object



102
103
104
# File 'lib/mayu/environment.rb', line 102

def create_store(initial_state: {})
  State::Store.new(initial_state, reducers:)
end

#init_jsObject



82
83
84
85
86
87
# File 'lib/mayu/environment.rb', line 82

def init_js
  @init_js ||=
    JSON.parse(File.read(File.join(js_runtime_path, "entries.json"))).fetch(
      "main"
    )
end

#js_runtime_pathObject



95
96
97
# File 'lib/mayu/environment.rb', line 95

def js_runtime_path
  File.join(__dir__, "client", "dist")
end

#load_root(request_path, headers: {}) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mayu/environment.rb', line 111

def load_root(request_path, headers: {})
  path, search = request_path.split("?", 2)
  # We should match the route earlier, so that we don't have to get this
  # far in case it doesn't match...
  route_match = match_route(path.to_s)
  query = Rack::Utils.parse_nested_query(search).transform_keys(&:to_sym)
  params = route_match.params

  # Load the page component.
  component_path = File.join("/", "app", "pages", route_match.template)
  resources.load_resource(component_path).type =>
    Resources::Types::Component => mod_type

  page_component = mod_type.component

  resources.load_resource(File.join("/", "app", "root")).type =>
    Resources::Types::Component => root

  request_info = { path:, params:, query:, headers: }.freeze

  # Apply the layouts.
  # NOTE: Pages should probably be their own
  # resource type and load their layouts.
  route_match
    .layouts
    .reverse
    .reduce(VDOM::H[page_component, request: request_info]) do |app, layout|
      Console.logger.info(self, "Applying layout #{layout.inspect}")

      resources.load_resource(
        File.join("/", "app", "pages", layout)
      ).type => Resources::Types::Component => layout

      VDOM::H[layout.component, app, request: request_info]
    end
    .then { VDOM::H[root.component, _1] }
end

#match_route(request_path) ⇒ Object



150
151
152
# File 'lib/mayu/environment.rb', line 150

def match_route(request_path)
  Routes.match_route(@routes, request_path)
end

#path(name) ⇒ Object



90
91
92
# File 'lib/mayu/environment.rb', line 90

def path(name)
  File.join(@root, @config.paths.send(name))
end