Class: Opal::SimpleServer

Inherits:
Object
  • Object
show all
Defined in:
opal/lib/opal/simple_server.rb

Overview

Opal::SimpleServer is a very basic Rack server for Opal assets, it relies on Opal::Builder and Ruby corelib/stdlib. It's meant to be used just for local development.

For a more complete implementation see opal-sprockets (Rubygems) or opal-webpack (NPM).

Examples:

(CLI)

rackup -ropal -ropal/simple_server -b 'Opal.append_path("app"); run Opal::SimpleServer.new'
... or use the Server runner ...
opal -Rserver app.rb

Constant Summary collapse

NotFound =
Class.new(StandardError)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) {|_self| ... } ⇒ SimpleServer

Returns a new instance of SimpleServer.

Yields:

  • (_self)

Yield Parameters:



22
23
24
25
26
27
28
29
30
# File 'opal/lib/opal/simple_server.rb', line 22

def initialize(options = {})
  @prefix = options.fetch(:prefix, 'assets').delete_prefix('/')
  @main = options.fetch(:main, 'application')
  @builder = options.fetch(:builder, nil)
  @transformations = []
  @index_path = nil
  @builders = {}
  yield self if block_given?
end

Instance Attribute Details

#index_pathObject

Returns the value of attribute index_path.



32
33
34
# File 'opal/lib/opal/simple_server.rb', line 32

def index_path
  @index_path
end

#mainObject

Returns the value of attribute main.



32
33
34
# File 'opal/lib/opal/simple_server.rb', line 32

def main
  @main
end

Instance Method Details

#append_path(path) ⇒ Object



34
35
36
# File 'opal/lib/opal/simple_server.rb', line 34

def append_path(path)
  @transformations << [:append_paths, path]
end

#apply_builder_transformations(builder) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'opal/lib/opal/simple_server.rb', line 86

def apply_builder_transformations(builder)
  @transformations.each do |type, *args|
    case type
    when :append_paths
      builder.append_paths(*args)
    end
  end
  builder
end

#builder(path) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'opal/lib/opal/simple_server.rb', line 58

def builder(path)
  case @builder
  when Opal::Builder
    builder = @builder
  when Proc
    if @builder.arity == 0
      builder = @builder.call
    else
      builder = @builder.call(path)
    end
  else
    builder = Opal::Builder.new
    builder = apply_builder_transformations(builder)
    builder.build(path.gsub(/(\.(?:rb|m?js|opal))*\z/, ''))
  end

  @esm = builder.compiler_options[:esm]
  @directory = builder.compiler_options[:directory]

  builder
end

#cached_builder(path, uncache: false) ⇒ Object

Only cache one builder at a time



81
82
83
84
# File 'opal/lib/opal/simple_server.rb', line 81

def cached_builder(path, uncache: false)
  @builders = {} if uncache || @builders.keys != [path]
  @builders[path] ||= builder(path)
end

#call(env) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'opal/lib/opal/simple_server.rb', line 38

def call(env)
  case env['PATH_INFO']
  when %r{\A/#{@prefix}/(.*?)\.m?js(/.*)?\z}
    path, rest = Regexp.last_match(1), Regexp.last_match(2)&.delete_prefix('/').to_s
    call_js(path, rest)
  else call_index
  end
rescue NotFound => error
  [404, {}, [error.to_s]]
end

#call_indexObject



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'opal/lib/opal/simple_server.rb', line 121

def call_index
  if @index_path
    contents = File.read(@index_path)
    html = ERB.new(contents).result binding
  else
    html = <<-HTML
    <!doctype html>
    <html>
      <head>
        <meta charset="utf-8">
      </head>
      <body>
        #{javascript_include_tag(main)}
      </body>
    </html>
    HTML
  end
  [200, { 'content-type' => 'text/html', 'cache-control' => 'no-cache' }, [html]]
end

#call_js(path, rest) ⇒ Object



49
50
51
52
53
54
55
56
# File 'opal/lib/opal/simple_server.rb', line 49

def call_js(path, rest)
  asset = fetch_asset(path, rest)
  [
    200,
    { 'content-type' => 'application/javascript' },
    @directory ? [asset[:data]] : [asset[:data], "\n", asset[:map].to_data_uri_comment],
  ]
end

#fetch_asset(path, rest) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
# File 'opal/lib/opal/simple_server.rb', line 96

def fetch_asset(path, rest)
  builder = cached_builder(path)
  if @directory
    { data: builder.compile_to_directory(single_file: rest) }
  else
    {
      data: builder.to_s,
      map: builder.source_map
    }
  end
end

#javascript_include_tag(path) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
# File 'opal/lib/opal/simple_server.rb', line 108

def javascript_include_tag(path)
  # Uncache previous builders and cache a new one
  cached_builder(path, uncache: true)

  path += ".#{js_ext}/index" if @directory

  if @esm
    %{<script src="/#{@prefix}/#{path}.#{js_ext}" type="module"></script>}
  else
    %{<script src="/#{@prefix}/#{path}.#{js_ext}"></script>}
  end
end

#js_extObject



141
142
143
# File 'opal/lib/opal/simple_server.rb', line 141

def js_ext
  @esm ? 'mjs' : 'js'
end