proscenium 0.1.0.alpha2-arm64-darwin → 0.1.0.alpha3-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
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