proscenium 0.1.0.alpha2-x86_64-linux → 0.1.0.alpha3-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +158 -29
  3. data/bin/esbuild +0 -0
  4. data/bin/parcel_css +0 -0
  5. data/config/routes.rb +1 -1
  6. data/lib/proscenium/compilers/esbuild/compile_error.js +145 -0
  7. data/lib/proscenium/compilers/esbuild/css_plugin.js +76 -0
  8. data/lib/proscenium/compilers/esbuild/env_plugin.js +6 -4
  9. data/lib/proscenium/compilers/esbuild/http_bundle_plugin.js +53 -0
  10. data/lib/proscenium/compilers/esbuild/import_map.js +59 -0
  11. data/lib/proscenium/compilers/esbuild/resolve_plugin.js +38 -35
  12. data/lib/proscenium/compilers/esbuild/setup_plugin.js +23 -22
  13. data/lib/proscenium/{cli → compilers}/esbuild/solidjs_plugin.js +5 -4
  14. data/lib/proscenium/compilers/esbuild.bench.js +7 -3
  15. data/lib/proscenium/compilers/esbuild.js +60 -19
  16. data/lib/proscenium/helper.rb +2 -2
  17. data/lib/proscenium/middleware/base.rb +13 -3
  18. data/lib/proscenium/middleware/esbuild.rb +14 -0
  19. data/lib/proscenium/middleware/parcel_css.rb +30 -3
  20. data/lib/proscenium/middleware.rb +3 -0
  21. data/lib/proscenium/railtie.rb +16 -18
  22. data/lib/proscenium/runtime/component_manager/index.js +7 -7
  23. data/lib/proscenium/runtime/component_manager/{render_component.js → render_component.jsx} +9 -13
  24. data/lib/proscenium/version.rb +1 -1
  25. metadata +8 -14
  26. data/lib/proscenium/cli/argument_error.js +0 -24
  27. data/lib/proscenium/cli/builders/index.js +0 -1
  28. data/lib/proscenium/cli/builders/javascript.js +0 -45
  29. data/lib/proscenium/cli/builders/react.js +0 -60
  30. data/lib/proscenium/cli/builders/solid.js +0 -46
  31. data/lib/proscenium/cli/esbuild/env_plugin.js +0 -21
  32. data/lib/proscenium/cli/esbuild/resolve_plugin.js +0 -136
  33. data/lib/proscenium/cli/js_builder.js +0 -194
  34. data/lib/proscenium/cli/solid.js +0 -15
  35. data/lib/proscenium/cli/utils.js +0 -93
@@ -1,35 +1,45 @@
1
1
  import { join, resolve } from 'std/path/mod.ts'
2
- import {
3
- parseFromString as parseImportMap,
4
- resolve as resolveFromImportMap
5
- } from 'import-maps/resolve'
2
+ import { resolve as resolveFromImportMap } from 'import-maps/resolve'
6
3
 
7
4
  import setup from './setup_plugin.js'
8
5
 
9
6
  const baseURL = new URL('file://')
10
- const importKinds = ['import-statement', 'dynamic-import', 'require-call']
7
+ const importKinds = ['import-statement', 'dynamic-import', 'require-call', 'import-rule']
11
8
 
12
9
  export default setup('resolve', (build, options) => {
13
- const { runtimeDir } = options
10
+ const { runtimeDir, importMap } = options
14
11
  const cwd = build.initialOptions.absWorkingDir
15
12
  const runtimeCwdAlias = `${cwd}/proscenium-runtime`
16
- const importMap = readImportMap()
17
13
 
18
- return {
19
- onResolve: {
14
+ return [
15
+ {
16
+ type: 'onResolve',
20
17
  filter: /.*/,
21
18
  async callback(args) {
22
- // Remote modules
19
+ if (args.path.includes('?')) {
20
+ const [path, query] = args.path.split('?')
21
+ args.path = path
22
+ args.suffix = `?${query}`
23
+ args.queryParams = new URLSearchParams(query)
24
+ }
25
+
26
+ // Mark remote modules as external.
23
27
  if (args.path.startsWith('http://') || args.path.startsWith('https://')) {
24
28
  return { external: true }
25
29
  }
26
30
 
27
31
  // Proscenium runtime
28
32
  if (args.path.startsWith('@proscenium/')) {
29
- return {
30
- path: `${args.path.replace(/^@proscenium/, '/proscenium-runtime')}/index.js`,
31
- external: true
33
+ const result = { suffix: args.suffix }
34
+
35
+ if (args.queryParams?.has('bundle')) {
36
+ result.path = join(runtimeDir, `${args.path.replace(/^@proscenium/, '')}/index.js`)
37
+ } else {
38
+ result.path = `${args.path.replace(/^@proscenium/, '/proscenium-runtime')}/index.js`
39
+ result.external = true
32
40
  }
41
+
42
+ return result
33
43
  }
34
44
 
35
45
  if (args.path.startsWith(runtimeCwdAlias)) {
@@ -43,7 +53,8 @@ export default setup('resolve', (build, options) => {
43
53
  }
44
54
  },
45
55
 
46
- onLoad: {
56
+ {
57
+ type: 'onLoad',
47
58
  filter: /.*/,
48
59
  namespace: 'importStylesheet',
49
60
  callback(args) {
@@ -67,7 +78,7 @@ export default setup('resolve', (build, options) => {
67
78
  return result
68
79
  }
69
80
  }
70
- }
81
+ ]
71
82
 
72
83
  // Resolve the given `params.path` to a path relative to the Rails root.
73
84
  //
@@ -76,7 +87,7 @@ export default setup('resolve', (build, options) => {
76
87
  // './my_module' -> '/.../app/my_module.js'
77
88
  // '/app/my_module' -> '/.../app/my_module.js'
78
89
  async function unbundleImport(params) {
79
- const result = { path: params.path }
90
+ const result = { path: params.path, suffix: params.suffix }
80
91
 
81
92
  if (importMap) {
82
93
  const { matched, resolvedImport } = resolveFromImportMap(params.path, importMap, baseURL)
@@ -108,7 +119,17 @@ export default setup('resolve', (build, options) => {
108
119
  // throw `${resolveResult.errors[0].text} (resolveDir: ${cwd})`
109
120
  }
110
121
 
111
- result.path = resolveResult.path.slice(cwd.length)
122
+ // If bundle queryParam is defined, return the resolveResult.
123
+ if (params.queryParams?.has('bundle')) {
124
+ return { ...resolveResult, suffix: result.suffix }
125
+ }
126
+
127
+ if (resolveResult.path.startsWith(runtimeDir)) {
128
+ result.path = '/proscenium-runtime' + resolveResult.path.slice(runtimeDir.length)
129
+ } else {
130
+ result.path = resolveResult.path.slice(cwd.length)
131
+ }
132
+
112
133
  result.sideEffects = resolveResult.sideEffects
113
134
 
114
135
  if (
@@ -119,27 +140,9 @@ export default setup('resolve', (build, options) => {
119
140
  // We're importing a CSS file from JS(X).
120
141
  result.namespace = 'importStylesheet'
121
142
  } else {
122
- // Requested path is a bare module.
123
143
  result.external = true
124
144
  }
125
145
 
126
146
  return result
127
147
  }
128
-
129
- function readImportMap() {
130
- const file = join(cwd, 'config', 'import_map.json')
131
- let source
132
-
133
- try {
134
- source = Deno.readTextFileSync(file)
135
- } catch {
136
- return null
137
- }
138
-
139
- return parseImportMap(source, baseURL)
140
- }
141
148
  })
142
-
143
- function isBareModule(path) {
144
- return !path.startsWith('.') && !path.startsWith('/')
145
- }
@@ -1,35 +1,36 @@
1
1
  export default (pluginName, pluginFn) => {
2
2
  return (options = {}) => ({
3
3
  name: pluginName,
4
- setup(build) {
5
- const plugin = pluginFn(build, options)
4
+ async setup(build) {
5
+ const callbacks = await pluginFn(build, options)
6
6
 
7
- if (plugin.onResolve) {
8
- const { callback, ...onResolve } = plugin.onResolve
7
+ callbacks.forEach(({ type, callback, filter, namespace }) => {
8
+ if (type === 'onResolve') {
9
+ build.onResolve({ filter, namespace }, async params => {
10
+ if (params.pluginData?.isResolvingPath) return
9
11
 
10
- build.onResolve(onResolve, async params => {
11
- if (params.pluginData?.isResolvingPath) return
12
+ options.debug &&
13
+ console.debug(`plugin(${pluginName}):onResolve`, params.path, { params })
12
14
 
13
- options.debug && console.debug(`plugin(${pluginName}):onResolve`, params.path, { params })
14
- const results = await callback(params)
15
- options.debug &&
16
- console.debug(`plugin(${pluginName}):onResolve`, params.path, { results })
15
+ const results = await callback(params)
17
16
 
18
- return results
19
- })
20
- }
17
+ options.debug &&
18
+ console.debug(`plugin(${pluginName}):onResolve`, params.path, { results })
21
19
 
22
- if (plugin.onLoad) {
23
- const { callback, ...onLoad } = plugin.onLoad
20
+ return results
21
+ })
22
+ } else if (type === 'onLoad') {
23
+ build.onLoad({ filter, namespace }, async params => {
24
+ options.debug && console.debug(`plugin(${pluginName}):onLoad`, { params })
24
25
 
25
- build.onLoad(onLoad, params => {
26
- options.debug && console.debug(`plugin(${pluginName}):onLoad`, { params })
27
- const results = callback(params)
28
- options.debug && console.debug(`plugin(${pluginName}):onLoad`, { results })
26
+ const results = await callback(params)
29
27
 
30
- return results
31
- })
32
- }
28
+ options.debug && console.debug(`plugin(${pluginName}):onLoad`, { results })
29
+
30
+ return results
31
+ })
32
+ }
33
+ })
33
34
  }
34
35
  })
35
36
  }
@@ -2,11 +2,12 @@ import { basename } from 'std/path/mod.ts'
2
2
  import { transformAsync } from '@babel/core'
3
3
  import solid from 'babel-preset-solid'
4
4
 
5
- import { setup } from '../utils.js'
5
+ import { setup } from './setup_plugin.js'
6
6
 
7
7
  export default setup('solidjs', () => {
8
- return {
9
- onLoad: {
8
+ return [
9
+ {
10
+ type: 'onLoad',
10
11
  filter: /\.jsx$/,
11
12
  async callback(args) {
12
13
  const source = await Deno.readTextFile(args.path)
@@ -19,5 +20,5 @@ export default setup('solidjs', () => {
19
20
  return { contents: code, loader: 'js' }
20
21
  }
21
22
  }
22
- }
23
+ ]
23
24
  })
@@ -2,8 +2,12 @@ import { join } from 'std/path/mod.ts'
2
2
 
3
3
  import compile from './esbuild.js'
4
4
 
5
- const cwd = join(Deno.cwd(), 'test', 'internal')
5
+ const root = join(Deno.cwd(), 'test', 'internal')
6
6
 
7
- Deno.bench('esbuild', async () => {
8
- await compile(cwd, 'lib/foo.js')
7
+ Deno.bench('esbuild js', async () => {
8
+ await compile(['lib/foo.js'], { root })
9
+ })
10
+
11
+ Deno.bench('esbuild css', async () => {
12
+ await compile(['lib/foo.css'], { root })
9
13
  })
@@ -4,21 +4,37 @@ import { expandGlob } from 'std/fs/mod.ts'
4
4
  import { join, isGlob, resolve, dirname, fromFileUrl } from 'std/path/mod.ts'
5
5
  import { build, stop } from 'esbuild'
6
6
 
7
+ import { readImportMap } from './esbuild/import_map.js'
7
8
  import envPlugin from './esbuild/env_plugin.js'
9
+ import cssPlugin from './esbuild/css_plugin.js'
8
10
  import resolvePlugin from './esbuild/resolve_plugin.js'
9
11
  import ArgumentError from './esbuild/argument_error.js'
12
+ import throwCompileError from './esbuild/compile_error.js'
10
13
 
11
14
  if (import.meta.main) {
15
+ !Deno.env.get('RAILS_ENV') && Deno.env.set('RAILS_ENV', 'development')
16
+
12
17
  const { _: paths, ...options } = parseArgs(Deno.args, {
13
- string: ['root', 'runtime-dir'],
14
- boolean: ['write'],
15
- alias: { 'runtime-dir': 'runtimeDir' }
18
+ string: ['root', 'runtime-dir', 'import-map'],
19
+ boolean: ['write', 'debug'],
20
+ alias: {
21
+ 'runtime-dir': 'runtimeDir',
22
+ 'import-map': 'importMap'
23
+ }
16
24
  })
17
- await writeAll(Deno.stdout, await main(paths, options))
25
+
26
+ let result = await main(paths, options)
27
+
28
+ // `result` is an error object, so return to stderr as JSON, and an exit code of 1.
29
+ if (isPlainObject(result)) {
30
+ result = new TextEncoder().encode(`(${throwCompileError()})(${JSON.stringify(result)})`)
31
+ }
32
+
33
+ await writeAll(Deno.stdout, result)
18
34
  }
19
35
 
20
36
  async function main(paths = [], options = {}) {
21
- const { root, write } = { write: false, ...options }
37
+ const { root, write, debug } = { write: false, ...options }
22
38
 
23
39
  if (!Array.isArray(paths) || paths.length < 1) throw new ArgumentError('pathsRequired')
24
40
  if (!root) throw new ArgumentError('rootRequired')
@@ -31,7 +47,9 @@ async function main(paths = [], options = {}) {
31
47
  throw new ArgumentError('rootUnknown', { root })
32
48
  }
33
49
 
34
- const isProd = Deno.env.get('RAILS_ENV') === 'production'
50
+ const env = Deno.env.get('RAILS_ENV')
51
+ const isProd = env === 'production'
52
+ const isTest = env === 'test'
35
53
 
36
54
  const entryPoints = new Set()
37
55
  for (let i = 0; i < paths.length; i++) {
@@ -46,37 +64,60 @@ async function main(paths = [], options = {}) {
46
64
  }
47
65
  }
48
66
 
67
+ let importMap
68
+ try {
69
+ importMap = readImportMap(options.importMap, root)
70
+ } catch (error) {
71
+ return {
72
+ detail: error.stack,
73
+ text: `Cannot read/parse import map: ${error.message}`,
74
+ location: {
75
+ file: error.file
76
+ }
77
+ }
78
+ }
79
+
49
80
  const runtimeDir = resolve(dirname(fromFileUrl(import.meta.url)), '../runtime')
50
81
 
51
82
  const params = {
52
83
  entryPoints: Array.from(entryPoints),
53
84
  absWorkingDir: root,
54
- logLevel: 'error',
55
- sourcemap: isProd ? 'linked' : 'inline',
85
+ logLevel: 'silent',
86
+ logLimit: 1,
87
+ sourcemap: isTest ? false : isProd ? 'linked' : 'inline',
56
88
  outdir: 'public/assets',
57
89
  outbase: './',
58
90
  format: 'esm',
59
- jsxFactory: 'reactCreateElement',
60
- jsxFragment: 'ReactFragment',
91
+ jsx: 'automatic',
92
+ jsxDev: !isTest && !isProd,
61
93
  minify: isProd,
62
94
  bundle: true,
63
- plugins: [envPlugin(), resolvePlugin({ runtimeDir, debug: false })],
64
- inject: [join(runtimeDir, 'react_shim/index.js')],
95
+ plugins: [envPlugin(), resolvePlugin({ runtimeDir, importMap, debug }), cssPlugin({ debug })],
65
96
  metafile: write,
66
97
  write
67
98
  }
68
99
 
100
+ let result
69
101
  try {
70
- const result = await build(params)
71
-
72
- if (write) {
73
- return new TextEncoder().encode(JSON.stringify(result))
74
- } else {
75
- return result.outputFiles[0].contents
76
- }
102
+ result = await build(params)
103
+ } catch (error) {
104
+ return { ...error.errors[0] }
77
105
  } finally {
78
106
  stop()
79
107
  }
108
+
109
+ if (write) {
110
+ return new TextEncoder().encode(JSON.stringify(result))
111
+ } else {
112
+ return result.outputFiles[0].contents
113
+ }
114
+ }
115
+
116
+ export function isPlainObject(value) {
117
+ if (Object.prototype.toString.call(value) !== '[object Object]') return false
118
+
119
+ const prototype = Object.getPrototypeOf(value)
120
+ return prototype === null || prototype === Object.prototype
80
121
  }
81
122
 
82
123
  export default main
@@ -21,12 +21,12 @@ module Proscenium
21
21
  end
22
22
 
23
23
  def proscenium_dev
24
- return if !Rails.env.development? || !Proscenium::Railtie.websocket
24
+ return unless Proscenium.config.auto_reload
25
25
 
26
26
  javascript_tag %(
27
27
  import autoReload from '/proscenium-runtime/auto_reload.js';
28
28
  autoReload('#{Proscenium::Railtie.websocket_mount_path}');
29
- ), type: 'module'
29
+ ), type: 'module', defer: true
30
30
  end
31
31
  end
32
32
  end
@@ -7,7 +7,9 @@ module Proscenium
7
7
  class Base
8
8
  include ActiveSupport::Benchmarkable
9
9
 
10
- class Error < StandardError; end
10
+ # Error when the result of the build returns an error. For example, when esbuild returns
11
+ # errors.
12
+ class CompileError < StandardError; end
11
13
 
12
14
  def self.attempt(request)
13
15
  new(request).renderable!&.attempt
@@ -57,15 +59,23 @@ module Proscenium
57
59
  response.write content
58
60
  response.content_type = content_type
59
61
  response['X-Proscenium-Middleware'] = name
62
+
63
+ yield response if block_given?
64
+
60
65
  response.finish
61
66
  end
62
67
 
63
68
  def build(cmd)
64
69
  stdout, stderr, status = Open3.capture3(cmd)
65
70
 
66
- raise Error, stderr unless status.success?
71
+ unless status.success?
72
+ raise self.class::CompileError, stderr if status.exitstatus == 2
73
+
74
+ raise BuildError, stderr
75
+ end
76
+
67
77
  unless stderr.empty?
68
- raise "Proscenium build of #{name}:'#{@request.fullpath}' failed -- #{stderr}"
78
+ raise BuildError, "Proscenium build of #{name}:'#{@request.fullpath}' failed -- #{stderr}"
69
79
  end
70
80
 
71
81
  stdout
@@ -3,10 +3,24 @@
3
3
  module Proscenium
4
4
  class Middleware
5
5
  class Esbuild < Base
6
+ class CompileError < StandardError
7
+ attr_reader :detail
8
+
9
+ def initialize(detail)
10
+ @detail = ActiveSupport::HashWithIndifferentAccess.new(Oj.load(detail, mode: :strict))
11
+
12
+ super "#{@detail[:text]} in #{@detail[:location][:file]}:#{@detail[:location][:line]}"
13
+ end
14
+ end
15
+
6
16
  def attempt
7
17
  benchmark :esbuild do
8
18
  render_response build("#{cli} --root #{root} #{path}")
9
19
  end
20
+ rescue CompileError => e
21
+ render_response "export default #{e.detail.to_json}" do |response|
22
+ response['X-Proscenium-Middleware'] = 'Esbuild::CompileError'
23
+ end
10
24
  end
11
25
 
12
26
  private
@@ -7,19 +7,46 @@ module Proscenium
7
7
  class ParcelCss < Base
8
8
  def attempt
9
9
  benchmark :parcelcss do
10
- results = build("#{cli} #{cli_options.join ' '} #{root}#{@request.path}")
11
- render_response css_module? ? Oj.load(results, mode: :strict)['code'] : results
10
+ with_custom_media { |path| build path }
12
11
  end
13
12
  end
14
13
 
15
14
  private
16
15
 
16
+ def with_custom_media
17
+ if custom_media?
18
+ Tempfile.create do |f|
19
+ contents = Pathname.new("#{root}#{@request.path}").read
20
+ f.write contents, "\n", custom_media_path.read
21
+ f.rewind
22
+
23
+ yield f.path
24
+ end
25
+ else
26
+ yield "#{root}#{@request.path}"
27
+ end
28
+ end
29
+
30
+ def build(path)
31
+ results = super("#{cli} #{cli_options.join ' '} #{path}")
32
+ render_response css_module? ? Oj.load(results, mode: :strict)['code'] : results
33
+ end
34
+
35
+ def custom_media?
36
+ @custom_media ||= custom_media_path.exist?
37
+ end
38
+
39
+ def custom_media_path
40
+ @custom_media_path ||= Rails.root.join('lib', 'custom_media_queries.css')
41
+ end
42
+
17
43
  def cli
18
44
  Gem.bin_path 'proscenium', 'parcel_css'
19
45
  end
20
46
 
21
47
  def cli_options
22
- options = ['--nesting', '--custom-media', '--targets', "'>= 0.25%'"]
48
+ options = ['--nesting', '--targets', "'>= 0.25%'"]
49
+ options << '--custom-media' if custom_media?
23
50
 
24
51
  if css_module?
25
52
  hash = Digest::SHA1.hexdigest(@request.path)[..7]
@@ -4,6 +4,9 @@ module Proscenium
4
4
  class Middleware
5
5
  extend ActiveSupport::Autoload
6
6
 
7
+ # Error when the build command fails.
8
+ class BuildError < StandardError; end
9
+
7
10
  autoload :Base
8
11
  autoload :Esbuild
9
12
  autoload :ParcelCss
@@ -13,15 +13,15 @@ module Proscenium
13
13
  # See https://doc.deno.land/https://deno.land/std@0.145.0/path/mod.ts/~/globToRegExp
14
14
  DEFAULT_GLOB_TYPES = {
15
15
  esbuild: [
16
- 'lib/**/*.{js,jsx}',
17
- 'app/components/**/*.{js,jsx}',
18
- 'app/views/**/*.{js,jsx}'
19
- ],
20
- parcelcss: [
21
- 'lib/**/*.css',
22
- 'app/components/**/*.css',
23
- 'app/views/**/*.css'
16
+ 'config/**/*.{js,jsx,css}',
17
+ 'lib/**/*.{js,jsx,css}',
18
+ 'app/**/*.{js,jsx,css}'
24
19
  ]
20
+ # parcelcss: [
21
+ # 'config/**/*.css',
22
+ # 'lib/**/*.css',
23
+ # 'app/**/*.css'
24
+ # ]
25
25
  }.freeze
26
26
 
27
27
  class << self
@@ -34,18 +34,16 @@ module Proscenium
34
34
  isolate_namespace Proscenium
35
35
 
36
36
  config.proscenium = ActiveSupport::OrderedOptions.new
37
- config.proscenium.listen_paths ||= %w[lib app]
38
- config.proscenium.listen_extensions ||= /\.(css|jsx?)$/
39
37
  config.proscenium.side_load = true
38
+ config.proscenium.auto_reload = Rails.env.development?
39
+ config.proscenium.auto_reload_paths ||= %w[lib app config]
40
+ config.proscenium.auto_reload_extensions ||= /\.(css|jsx?)$/
40
41
 
41
42
  initializer 'proscenium.configuration' do |app|
42
43
  options = app.config.proscenium
43
44
 
44
45
  options.glob_types = DEFAULT_GLOB_TYPES if options.glob_types.blank?
45
-
46
- options.auto_refresh = true if options.auto_refresh.nil?
47
- options.listen = Rails.env.development? if options.listen.nil?
48
- options.listen_paths.filter! { |path| Dir.exist? path }
46
+ options.auto_reload_paths.filter! { |path| Dir.exist? path }
49
47
  options.cable_mount_path ||= '/proscenium-cable'
50
48
  options.cable_logger ||= Rails.logger
51
49
  end
@@ -73,10 +71,10 @@ module Proscenium
73
71
  end
74
72
 
75
73
  config.after_initialize do
76
- next unless config.proscenium.listen
74
+ next unless config.proscenium.auto_reload
77
75
 
78
- @listener = Listen.to(*config.proscenium.listen_paths,
79
- only: config.proscenium.listen_extensions) do |mod, add, rem|
76
+ @listener = Listen.to(*config.proscenium.auto_reload_paths,
77
+ only: config.proscenium.auto_reload_extensions) do |mod, add, rem|
80
78
  Proscenium::Railtie.websocket&.broadcast('reload', {
81
79
  modified: mod,
82
80
  removed: rem,
@@ -94,7 +92,7 @@ module Proscenium
94
92
  class << self
95
93
  def websocket
96
94
  return @websocket unless @websocket.nil?
97
- return unless config.proscenium.auto_refresh
95
+ return unless config.proscenium.auto_reload
98
96
 
99
97
  cable = ActionCable::Server::Configuration.new
100
98
  cable.cable = { adapter: 'async' }.with_indifferent_access
@@ -1,18 +1,18 @@
1
1
  /* eslint-disable no-console */
2
2
 
3
- import renderComponent from `/proscenium-runtime/component_manager/render_component.js`
4
-
5
- document.addEventListener('DOMContentLoaded', () => {
3
+ export async function init() {
6
4
  const elements = document.querySelectorAll('[data-component]')
7
5
 
8
6
  if (elements.length < 1) return
9
7
 
10
- Array.from(elements, (ele) => {
8
+ const { default: renderComponent } = await import(`./render_component`)
9
+
10
+ Array.from(elements, ele => {
11
11
  const data = JSON.parse(ele.getAttribute('data-component'))
12
12
 
13
13
  let isVisible = false
14
- const observer = new IntersectionObserver((entries) => {
15
- entries.forEach((entry) => {
14
+ const observer = new IntersectionObserver(entries => {
15
+ entries.forEach(entry => {
16
16
  if (!isVisible && entry.isIntersecting) {
17
17
  isVisible = true
18
18
  observer.unobserve(ele)
@@ -24,4 +24,4 @@ document.addEventListener('DOMContentLoaded', () => {
24
24
 
25
25
  observer.observe(ele)
26
26
  })
27
- })
27
+ }
@@ -18,22 +18,18 @@ export default async function (ele, data) {
18
18
 
19
19
  if (!contentLoader) return null
20
20
 
21
- return /* @__PURE__ */ createElement('div', {
22
- style: { height: '100%' },
23
- dangerouslySetInnerHTML: { __html: contentLoader.outerHTML }
24
- })
21
+ return (
22
+ <div
23
+ style={{ height: '100%' }}
24
+ dangerouslySetInnerHTML={{ __html: contentLoader.outerHTML }}
25
+ ></div>
26
+ )
25
27
  }
26
28
 
27
29
  createRoot(ele).render(
28
- /* @__PURE__ */ createElement(
29
- Suspense,
30
- {
31
- fallback: /* @__PURE__ */ createElement(Fallback, {
32
- contentLoader
33
- })
34
- },
35
- createElement(component, data.props)
36
- )
30
+ <Suspense fallback={<Fallback contentLoader={contentLoader} />}>
31
+ {createElement(component, data.props)}
32
+ </Suspense>
37
33
  )
38
34
 
39
35
  RAILS_ENV === 'development' && console.debug(`[REACT]`, `Rendered ${data.path.slice(1)}`)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium
4
- VERSION = '0.1.0.alpha2'
4
+ VERSION = '0.1.0.alpha3'
5
5
  end