svelte-on-rails 8.1.0 → 9.0.0

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/lib/generators/showcase_generator.rb +128 -0
  4. data/lib/generators/svelte_on_rails/install/install_generator.rb +1 -111
  5. data/lib/svelte-on-rails.rb +1 -1
  6. data/lib/svelte_on_rails/installer/hello_world.rb +7 -26
  7. data/lib/svelte_on_rails/installer/utils.rb +2 -14
  8. data/lib/svelte_on_rails/lib/development_utils.rb +0 -29
  9. data/lib/svelte_on_rails/lib/utils.rb +6 -0
  10. data/lib/svelte_on_rails/lib/view_helper_support.rb +2 -0
  11. data/lib/svelte_on_rails/renderer/render-backup.js +26 -0
  12. data/lib/svelte_on_rails/renderer/render.js +61 -13
  13. data/lib/svelte_on_rails/renderer/renderer.rb +7 -4
  14. data/lib/svelte_on_rails/renderer/utils.js +40 -40
  15. data/lib/tasks/svelte_on_rails_tasks.rake +13 -51
  16. data/templates/config_base/config/svelte_on_rails.yml +1 -1
  17. data/templates/config_base/vite-ssr.config.ts +8 -3
  18. data/templates/showcase/app/channels/application_cable/channel.rb +4 -0
  19. data/templates/showcase/app/channels/application_cable/connection.rb +5 -0
  20. data/templates/showcase/app/controllers/svelte_on_rails_showcase_controller.rb +65 -0
  21. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/JavascriptImport.svelte +7 -0
  22. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/JpgImport.svelte +15 -0
  23. data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/ParentWithChild.svelte +1 -1
  24. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/PngImport.svelte +16 -0
  25. data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/ReceiveFromChannel.svelte +5 -3
  26. data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/SvelteOnRailsHelloWorld.svelte +4 -4
  27. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/SvgRawImport.svelte +7 -0
  28. data/templates/showcase/app/views/svelte_on_rails_showcase/_nav.html.erb +13 -0
  29. data/templates/showcase/app/views/svelte_on_rails_showcase/backend_frontend_rendered.html.erb +37 -0
  30. data/templates/showcase/app/views/svelte_on_rails_showcase/index.html.erb +9 -0
  31. data/templates/{all_features_test/app/views/svelte_on_rails_hello_world → showcase/app/views/svelte_on_rails_showcase}/ssr_auto_rendered.html.erb +2 -2
  32. data/templates/{all_features_test/app/views/svelte_on_rails_hello_world → showcase/app/views/svelte_on_rails_showcase}/web_socket.html.erb +1 -1
  33. metadata +27 -24
  34. data/lib/svelte_on_rails/installer/vite.rb +0 -95
  35. data/templates/all_features_test/app/controllers/svelte_on_rails_hello_world_controller.rb +0 -62
  36. data/templates/all_features_test/app/frontend/javascript/components/JavascriptImport.svelte +0 -7
  37. data/templates/all_features_test/app/frontend/javascript/components/JpgImport.svelte +0 -7
  38. data/templates/all_features_test/app/frontend/javascript/components/PngImport.svelte +0 -7
  39. data/templates/all_features_test/app/frontend/javascript/components/SvgRawImport.svelte +0 -7
  40. data/templates/all_features_test/app/views/svelte_on_rails_hello_world/_nav.html.erb +0 -13
  41. data/templates/all_features_test/app/views/svelte_on_rails_hello_world/backend_frontend_rendered.html.erb +0 -37
  42. data/templates/all_features_test/app/views/svelte_on_rails_hello_world/index.html.erb +0 -9
  43. /data/templates/{all_features_test → showcase}/app/channels/svelte_on_rails_channel.rb +0 -0
  44. /data/templates/{all_features_test → showcase}/app/frontend/initializers/actionCable.js +0 -0
  45. /data/templates/{all_features_test/app/frontend/images/svelte-on-rails-hello-world-england.png → showcase/app/frontend/javascript/svelte_on_rails_showcase/england.png} +0 -0
  46. /data/templates/{all_features_test/app/frontend/images/svelte-on-rails-hello-world-face-smile-wink.svg → showcase/app/frontend/javascript/svelte_on_rails_showcase/face-smile-wink.svg} +0 -0
  47. /data/templates/{all_features_test/app/frontend/javascript → showcase/app/frontend/javascript/svelte_on_rails_showcase}/nestedJavascript.js +0 -0
  48. /data/templates/{all_features_test/app/frontend/javascript → showcase/app/frontend/javascript/svelte_on_rails_showcase}/nestedJavascriptToggled.js +0 -0
  49. /data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/sub/NestedComponent.svelte +0 -0
  50. /data/templates/{all_features_test/app/frontend/images/svelte-on-rails-hello-world-switzerland.jpg → showcase/app/frontend/javascript/svelte_on_rails_showcase/switzerland.jpg} +0 -0
  51. /data/templates/{all_features_test/app/views/svelte_on_rails_hello_world → showcase/app/views/svelte_on_rails_showcase}/_styles.html.erb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8888526927853e78465bc1bbda518d82a0a499c33a1d99d5ada3ea411c0baf70
4
- data.tar.gz: 0c019007e8d68e48e659a47041a15af833d7bd1c1a8b0414af8a51d836a2397d
3
+ metadata.gz: c7247500d2d0c44d3c91cf1bfa5aec7861ec4306928fdfecbcc42e79fda5e63a
4
+ data.tar.gz: 5668e8ec34a3d12fb794641fc763162aa11b1ba2611f4b6fd4145762f743e11e
5
5
  SHA512:
6
- metadata.gz: 91f0eb2d62372a9a7b2337adbb209c6db8f0eade705fe50d4a1fef516cb856999cfa3753521422cab4476399769e0c43672f79d716e839f19097ae4bfa0b273a
7
- data.tar.gz: f7e4e9c10f8cdcbed1e56087fc2470b4c82f575bbf730bc816656dcf03c98becacf97c6efd98936e5696c1e1625d03a2234e251cd0bc9d197888cd72a8e07f88
6
+ metadata.gz: 806a37910e007388a2d89e10d370ca144e46180c78138d1eb7ee05852edec90fc43436f452c64d5901881eb77c1567c416406cff7ecb1e9102a4906a9ba56918
7
+ data.tar.gz: d2f5c37db64f31f061cca10132a4c2b1e70773e3377cce4502a411bcf23afbafad7e98809e9e2f08a933375a721df48a96dabbd12fd3b869dc0fbb88f2b6e41c
data/README.md CHANGED
@@ -37,14 +37,16 @@ If you have issues, please open one, and contributors are welcome!
37
37
  ## Requirements
38
38
 
39
39
  - tested on
40
- - ruby 3.2.2 and rails 7.1
41
- - Recommended: ruby 3x
42
- - ruby 2.7.5 and rails 6.1
43
- - vite@6 (v7 not yet supported, see issues)
40
+ - ruby 3.4.2 / Rails 8.1.2
41
+ - ruby 3.2.2 / rails 7.1
42
+ - ruby 2.7.5 / rails 6.1
43
+ - vite@6 (v7 not yet tested, see issues)
44
44
  - turbolinks and hotwired/turbo
45
45
  - vite_rails (the installer will install it by option --full or --vite)
46
46
  - svelte@5, @sveltejs/vite-plugin-svelte@5 (see: [how to install svelte on rails/vite](https://dev.to/chmich/setup-inertia-and-svelte-on-rails-7-3glk))
47
+ - since gem-version 9, svelte runes-mode is set to true for ssr, check svelte-5 migration guide
47
48
  - turbo (recommended / [how to install turbo on rails](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#installation))
49
+ - this is because of using ssr for initial-load only but that feature is also available for turbo-links.
48
50
  - npm on latest versions
49
51
  - actual node installed.
50
52
  - if `nvm` is installed it gets the path to the node-binary from there.
@@ -0,0 +1,128 @@
1
+ require "rails/generators"
2
+
3
+ module SvelteOnRails
4
+ module Generators
5
+ class ShowcaseGenerator < Rails::Generators::Base
6
+
7
+ class_option :full, type: :boolean, default: false, desc: "Run full installation with additional setup"
8
+ class_option :force, type: :boolean, default: false, desc: "Do not ask for overwriting files"
9
+ class_option :turbo, type: :boolean, default: false, desc: "Use @hotwired/turbo-rails"
10
+ class_option :turbo_streams, type: :boolean, default: false, desc: "Turbo::StreamsChannel"
11
+ class_option :hello_world, type: :boolean, default: false, desc: "Create Hello World component"
12
+
13
+ require 'svelte_on_rails/installer/utils'
14
+ require 'svelte_on_rails/installer/haml'
15
+ require 'svelte_on_rails/lib/development_utils'
16
+
17
+ NPM_PACKAGE_NAME = '@csedl/svelte-on-rails'
18
+
19
+ def initialize(*args)
20
+
21
+ super
22
+
23
+ puts
24
+ puts '-' * 80
25
+ puts '-' * 80
26
+ puts 'INSTALLING DEMO COMPONENTS'
27
+ puts '-' * 80
28
+
29
+ end
30
+
31
+
32
+
33
+ def turbo
34
+
35
+ puts '-' * 80
36
+ puts ' ▶︎▶︎▶︎ INSTALLING @hotwired/turbo-rails'
37
+ puts '-' * 80
38
+ npm_i = SvelteOnRails::Installer::Npm
39
+ tr_pkg = '@hotwired/turbo-rails'
40
+ npm_i.install_or_update_package(tr_pkg)
41
+ js_i = SvelteOnRails::Installer::Javascript
42
+ js_i.append_import_statement(application_js_path, tr_pkg, "import '#{tr_pkg}';")
43
+
44
+ puts '-' * 80
45
+ puts ' ▶︎▶︎▶︎ INSTALLING Turbo::StreamsChannel'
46
+ puts '-' * 80
47
+
48
+ gem_uts = SvelteOnRails::GemUtils
49
+ puts '• installing turbo-rails ...'
50
+ gem_uts.install_gem('turbo-rails')
51
+ puts '• installed turbo-rails!'
52
+ utils_i = SvelteOnRails::Installer::Utils
53
+ puts '• running turbo:install ...'
54
+ utils_i.run_command('bundle exec rails turbo:install', success_message: 'You must import')
55
+ puts '• turbo:install finished!'
56
+ end
57
+
58
+
59
+
60
+
61
+ def hello_world
62
+
63
+ puts '-' * 80
64
+ puts ' ▶︎▶︎▶︎︎ INSTALLING Hello World component'
65
+ puts '-' * 80
66
+
67
+ hw_i = SvelteOnRails::Installer::HelloWorld
68
+
69
+ utils_i = SvelteOnRails::Installer::Utils
70
+ utils_i.add_route(" get \"svelte_on_rails_showcase/web_socket\"", app_root: Rails.root)
71
+ utils_i.add_route(" get \"svelte_on_rails_showcase/web_socket_action\"", app_root: Rails.root)
72
+ npm_i = SvelteOnRails::Installer::Npm
73
+ npm_i.install_or_update_package('axios')
74
+ npm_i.install_or_update_package('@rails/actioncable')
75
+ js_i = SvelteOnRails::Installer::Javascript
76
+ init_stat = '../initializers/actionCable.js'
77
+ js_i.append_import_statement(application_js_path, init_stat, "import '#{init_stat}';")
78
+ @hello_world_path = hw_i.install_hello_world(['showcase'], app_root: nil, force: true, silent: true)
79
+ end
80
+
81
+
82
+
83
+
84
+ def finish
85
+ puts '-' * 80
86
+
87
+ puts "SvelteOnRails Showcase installed successfully!"
88
+ puts "Restart the server and check if it all works."
89
+ if @hello_world_path
90
+ puts "You can now access the Hello World component on: http://localhost:your-port-number/svelte_on_rails_showcase."
91
+ end
92
+ puts "Happy coding!"
93
+ end
94
+
95
+ private
96
+
97
+ def toggle_hello_world_files
98
+ %w[
99
+ app/frontend/images/svg.svg
100
+ app/frontend/images/atom.svg
101
+ app/frontend/javascript/nestedJavascript.js
102
+ app/frontend/javascript/nestedJavascriptToggled.js
103
+ ]
104
+ end
105
+
106
+ # def validate_raw_options!(args)
107
+ # # Get option names from class_options, excluding inherited Thor/Rails options
108
+ # valid_options = self.class.class_options.keys.map { |opt| "--#{opt.to_s.tr('_', '-')}" }
109
+ # rails_internal_options = %w[--skip-namespace --skip-collision-check --pretend --quiet --force]
110
+ # options_array = args.find { |arg| arg.is_a?(Array) && arg.any? { |a| a.start_with?('--') } } || []
111
+ # passed_options = options_array.select { |arg| arg.start_with?('--') }
112
+ # unknown_options = passed_options - valid_options - rails_internal_options
113
+ # unless unknown_options.empty?
114
+ # valid_display = valid_options.map { |opt| opt.gsub(/^--/, '') }.join(', ')
115
+ # raise Thor::Error, "Unknown options: #{unknown_options.join(', ')}. Valid options are: #{valid_display}\nNothing done."
116
+ # end
117
+ #
118
+ # if options[:turbo_streams] && !(options[:full] || options[:turbo])
119
+ # raise Thor::Error, "--turbo-streams option cannot be used without --turbo"
120
+ # end
121
+ # end
122
+
123
+ def application_js_path
124
+ Rails.root.join("app", "frontend", "entrypoints", "application.js")
125
+ end
126
+ end
127
+ end
128
+ end
@@ -6,12 +6,8 @@ module SvelteOnRails
6
6
 
7
7
  class_option :full, type: :boolean, default: false, desc: "Run full installation with additional setup"
8
8
  class_option :force, type: :boolean, default: false, desc: "Do not ask for overwriting files"
9
- class_option :vite, type: :boolean, default: false, desc: "Use Vite"
10
- class_option :haml, type: :boolean, default: false, desc: "Use Haml"
11
9
  class_option :turbo, type: :boolean, default: false, desc: "Use @hotwired/turbo-rails"
12
10
  class_option :turbo_streams, type: :boolean, default: false, desc: "Turbo::StreamsChannel"
13
- class_option :svelte, type: :boolean, default: false, desc: "Install Svelte"
14
- class_option :pug, type: :boolean, default: false, desc: "Install Pug"
15
11
  class_option :hello_world, type: :boolean, default: false, desc: "Create Hello World component"
16
12
 
17
13
  require 'svelte_on_rails/installer/utils'
@@ -24,29 +20,16 @@ module SvelteOnRails
24
20
 
25
21
  super
26
22
 
27
- @local_npm_package_url = SvelteOnRails::DevelopmentUtils.local_npm_package_url
28
-
29
23
  puts
30
24
  validate_raw_options!(args)
31
25
  puts '-' * 80
32
26
  puts '-' * 80
33
27
  puts 'STARTING SVELTE-ON-RAILS INSTALLATION'
34
28
  puts " • FORCED (option --force was given)" if options[:force]
35
- if @local_npm_package_url
36
- puts " • Local Npm Package used: #{NPM_PACKAGE_NAME} used: #{@local_npm_package_url}"
37
- end
38
29
  puts '-' * 80
39
30
 
40
31
  end
41
32
 
42
- def vite
43
- return unless options[:full] || options[:vite]
44
- puts '-' * 80
45
- puts '• INSTALLING VITE-RAILS'
46
- vite_i = SvelteOnRails::Installer::Vite
47
- vite_i.install_vite(version_specifier: '6')
48
- end
49
-
50
33
  def svelte_on_rails
51
34
 
52
35
  puts '-' * 80
@@ -61,14 +44,7 @@ module SvelteOnRails
61
44
  pkg_js['scripts'] ||= { 'build:ssr': "vite build --config vite-ssr.config.ts" }
62
45
  File.write('package.json', JSON.pretty_generate(pkg_js))
63
46
 
64
- if @local_npm_package_url
65
- npm_i.link_local_package(NPM_PACKAGE_NAME, @local_npm_package_url)
66
-
67
- # npm does not resolve peer dependencies on local package url
68
- npm_i.install_or_update_package('@hotwired/stimulus')
69
- else
70
- npm_i.install_or_update_package(NPM_PACKAGE_NAME)
71
- end
47
+ npm_i.install_or_update_package(NPM_PACKAGE_NAME)
72
48
  npm_i.install_or_update_package('typescript')
73
49
  npm_i.install_or_update_package('@types/node')
74
50
 
@@ -77,92 +53,6 @@ module SvelteOnRails
77
53
  js_i.append_import_statement(application_js_path, init_stat, "import '#{init_stat}';")
78
54
  end
79
55
 
80
- def turbo
81
- return unless options[:full] || options[:turbo]
82
-
83
- puts '-' * 80
84
- puts ' ▶︎▶︎▶︎ INSTALLING @hotwired/turbo-rails'
85
- puts '-' * 80
86
- npm_i = SvelteOnRails::Installer::Npm
87
- tr_pkg = '@hotwired/turbo-rails'
88
- npm_i.install_or_update_package(tr_pkg)
89
- js_i = SvelteOnRails::Installer::Javascript
90
- js_i.append_import_statement(application_js_path, tr_pkg, "import '#{tr_pkg}';")
91
-
92
- return unless options[:turbo_streams] || options[:full]
93
-
94
- puts '-' * 80
95
- puts ' ▶︎▶︎▶︎ INSTALLING Turbo::StreamsChannel'
96
- puts '-' * 80
97
-
98
- gem_uts = SvelteOnRails::GemUtils
99
- puts '• installing turbo-rails ...'
100
- gem_uts.install_gem('turbo-rails')
101
- puts '• installed turbo-rails!'
102
- utils_i = SvelteOnRails::Installer::Utils
103
- puts '• running turbo:install ...'
104
- utils_i.run_command('bundle exec rails turbo:install', success_message: 'You must import')
105
- puts '• turbo:install finished!'
106
- end
107
-
108
- def svelte
109
- return unless options[:svelte] || options[:full]
110
-
111
- puts '-' * 80
112
- puts ' ▶︎▶︎▶︎ INSTALLING svelte (npm package)'
113
-
114
- puts '-' * 80
115
- svelte_i = SvelteOnRails::Installer::Svelte
116
- svelte_i.install_svelte(
117
- svelte_version_specifier: '5',
118
- vite_plugin_svelte_version_specifier: '5'
119
- )
120
- end
121
-
122
- def hello_world
123
- return unless options[:hello_world] || options[:full]
124
-
125
- puts '-' * 80
126
- puts ' ▶︎▶︎▶︎︎ INSTALLING Hello World component'
127
- puts '-' * 80
128
-
129
- hw_i = SvelteOnRails::Installer::HelloWorld
130
-
131
- utils_i = SvelteOnRails::Installer::Utils
132
- utils_i.add_route(" get \"svelte_on_rails_hello_world/web_socket\"", app_root: Rails.root)
133
- utils_i.add_route(" get \"svelte_on_rails_hello_world/web_socket_action\"", app_root: Rails.root)
134
- npm_i = SvelteOnRails::Installer::Npm
135
- npm_i.install_or_update_package('axios')
136
- npm_i.install_or_update_package('@rails/actioncable')
137
- js_i = SvelteOnRails::Installer::Javascript
138
- init_stat = '../initializers/actionCable.js'
139
- js_i.append_import_statement(application_js_path, init_stat, "import '#{init_stat}';")
140
- @hello_world_path = hw_i.install_hello_world(['all_features_test'], app_root: nil, force: true, silent: true)
141
- end
142
-
143
- def haml_and_convert
144
- return unless options[:haml]
145
-
146
- puts '-' * 80
147
- puts ' ▶︎▶︎▶︎ INSTALLING Haml and converting existing .erb files to .haml'
148
-
149
- haml_i = SvelteOnRails::Installer::Haml
150
- haml_i.install_haml_and_convert(force: options[:force])
151
- end
152
-
153
- def finish
154
- puts '-' * 80
155
- puts ' 👍 FINISHED SVELTE-ON-RAILS INSTALLATION 👍'
156
- puts '-' * 80
157
-
158
- puts "SvelteOnRails installed successfully!"
159
- puts "Restart the server and check if it all works."
160
- if @hello_world_path
161
- puts "You can now access the Hello World component on: http://localhost:your-port-number#{@hello_world_path}."
162
- end
163
- puts "Happy coding!"
164
- end
165
-
166
56
  private
167
57
 
168
58
  def toggle_hello_world_files
@@ -16,13 +16,13 @@ require "svelte_on_rails/lib/to_svelte"
16
16
  require 'svelte_on_rails/installer/utils'
17
17
  require 'svelte_on_rails/installer/haml'
18
18
  require 'svelte_on_rails/installer/gem_utils'
19
- require 'svelte_on_rails/installer/vite'
20
19
  require 'svelte_on_rails/installer/svelte'
21
20
  require 'svelte_on_rails/installer/npm'
22
21
  require 'svelte_on_rails/installer/javascript'
23
22
  require 'svelte_on_rails/installer/hello_world'
24
23
 
25
24
  require 'generators/svelte_on_rails/install/install_generator'
25
+ require 'generators/showcase_generator'
26
26
 
27
27
  module SvelteOnRails
28
28
  class << self
@@ -10,35 +10,16 @@ module SvelteOnRails
10
10
 
11
11
  utils_i.write_templates(templates, ask_for_overwrite: !force, app_root: app_root, silent: silent)
12
12
 
13
- # route
14
-
15
- route = 'svelte_on_rails_hello_world#index'
16
-
17
- utils_i.add_route(" get \"#{route.sub('#', '/')}\"", app_root: app_root)
18
- utils_i.add_route(" get \"svelte_on_rails_hello_world/backend_frontend_rendered\"", app_root: app_root)
19
- utils_i.add_route(" get \"svelte_on_rails_hello_world/ssr_auto_rendered\"", app_root: app_root)
20
-
21
- rr = utils_i.which_root_route(app_root)
22
- root_url = "/"
23
- url = root_url + route.sub('#', '/')
24
-
25
- if rr && rr == route
26
- puts "Root route «#{route}» already exists, skipping."
27
- root_url
28
- elsif rr && utils_i.route_exists?(route.sub('#', '/'))
29
- puts "route «#{route}» already exists, skipping."
30
- url
31
- elsif rr
32
- url
33
- else
34
- utils_i.add_route(' root "svelte_on_rails_hello_world#index"', app_root: app_root)
35
- root_url
36
- end
13
+ # routes
14
+
15
+ utils_i.add_route(" get \"svelte_on_rails_showcase/backend_frontend_rendered\"", app_root: app_root)
16
+ utils_i.add_route(" get \"svelte_on_rails_showcase/ssr_auto_rendered\"", app_root: app_root)
17
+ utils_i.add_route(" get \"svelte_on_rails_showcase\", to: \"svelte_on_rails_showcase#index\"", app_root: app_root)
37
18
 
38
19
  end
39
20
 
40
21
 
41
- def self.remove_hello_world(templates = ['all_features_test'], app_root: nil, ask: true)
22
+ def self.remove_hello_world(templates = ['showcase'], app_root: nil, ask: true)
42
23
 
43
24
  utils = SvelteOnRails::Installer::Utils
44
25
 
@@ -58,7 +39,7 @@ module SvelteOnRails
58
39
 
59
40
  utils.remove_line_from_file(
60
41
  utils.app_root_path(app_root).join('config/routes.rb'),
61
- "svelte_on_rails_hello_world",
42
+ "svelte_on_rails_showcase",
62
43
  force: !ask,
63
44
  )
64
45
 
@@ -5,12 +5,11 @@ module SvelteOnRails
5
5
  module Utils
6
6
  def self.install_npm_package
7
7
  package_name = "@csedl/svelte-on-rails@latest"
8
- puts "Installing #{package_name} via npm..."
9
8
 
10
9
  if system("npm install #{package_name}")
11
- puts "#{package_name} successfully installed."
10
+ puts "Installed successfully: «#{package_name}»"
12
11
  else
13
- abort "Failed to install #{package_name}. Please ensure npm is installed and try running 'npm install #{package_name}' manually."
12
+ abort "Failed to install «#{package_name}» by npm. You must manually."
14
13
  end
15
14
  end
16
15
 
@@ -243,17 +242,6 @@ module SvelteOnRails
243
242
  continue == 'y'
244
243
  end
245
244
 
246
- def self.which_root_route(app_root = nil)
247
-
248
- # Check if the root route is active (uncommented) or commented out
249
-
250
- routes = File.read(app_root_path(app_root).join('config', 'routes.rb'))
251
- m = routes.match(/^\s*root\s+['"]([^'"]+)['"]/m)
252
- if m
253
- m.to_s.match(/^\s*root\s*['"]([^'"]*)['"]/)[1]
254
- end
255
- end
256
-
257
245
  def self.add_route(route, app_root: nil)
258
246
 
259
247
  file_path = app_root_path(app_root).join('config/routes.rb')
@@ -1,38 +1,9 @@
1
1
  module SvelteOnRails
2
2
  class DevelopmentUtils
3
3
 
4
- def self.local_npm_package_url
5
- str = contributor_config('local_npm_package_path', required: false)
6
- if !str.present?
7
- nil
8
- elsif !Dir.exist?(str)
9
- raise "Invalid path given on local_npm_package_path: «#{str}»"
10
- elsif !File.exist?(Pathname.new(str).join('package.json'))
11
- raise "Given local_npm_package_path does not seem to be a valid npm package as it does not contain a package.json"
12
- else
13
- return Pathname.new(str)
14
- end
15
- end
16
-
17
4
  def self.gem_folder
18
5
  Pathname.new(File.expand_path('../../..', __dir__))
19
6
  end
20
7
 
21
- def self.contributor_config(key, required: true)
22
- config_file = File.expand_path('../svelte_on_rails_contributor_configs.yml', gem_folder)
23
- if !File.exist?(config_file)
24
- if required
25
- raise "Missing configuration file, searched at: «#{config_file}»"
26
- end
27
- else
28
- yml = YAML.load_file(config_file)
29
- value = yml[key.to_s]
30
- if required && !value.present?
31
- raise "Missing value «#{key}» in configuration file: «#{config_file}»"
32
- end
33
- value
34
- end
35
- end
36
-
37
8
  end
38
9
  end
@@ -69,6 +69,7 @@ module SvelteOnRails
69
69
  errors_matcher = Regexp.new('(Could not resolve|failed to resolve)')
70
70
  error_lines = warnings.select { |e| e.match(errors_matcher) }
71
71
  have_error = error_lines.present? || status.to_s.match(/exit 1/)
72
+ copy_render_js
72
73
 
73
74
  # error handling
74
75
 
@@ -118,6 +119,11 @@ module SvelteOnRails
118
119
 
119
120
  end
120
121
 
122
+ def self.copy_render_js
123
+ config = SvelteOnRails::Configuration.instance
124
+ FileUtils.cp(gem_app_dir + 'renderer/render.js', config.ssr_dist_folder.join('render.js'))
125
+ end
126
+
121
127
  # Defining methods to log errors and warnings using Rails logger
122
128
  def self.puts_error(text)
123
129
  # Using Rails logger to log error with custom formatting
@@ -9,6 +9,8 @@ module SvelteOnRails
9
9
 
10
10
  def initialize(file, props, html_options, options, request, caching = false)
11
11
 
12
+ require 'zlib'
13
+
12
14
  @start_time = Time.now
13
15
  @conf = SvelteOnRails::Configuration.instance
14
16
  utils = SvelteOnRails::Lib::Utils
@@ -0,0 +1,26 @@
1
+ import {loadComponentModule, readPropsFromStdin} from './utils.js';
2
+
3
+ (async () => {
4
+
5
+ console.log(`[svelte-on-rails:debug] awaiting load component => «${process.argv[2]}»`)
6
+
7
+ const MyComponent = await loadComponentModule(process.argv[2]);
8
+ console.log(`[svelte-on-rails:debug] component read: «${MyComponent}}»`)
9
+
10
+ const props = await readPropsFromStdin();
11
+ console.log(`[svelte-on-rails:debug] props read: «${props}»`)
12
+
13
+ const payload = {out: []};
14
+
15
+ try {
16
+ MyComponent(payload, props); // Writes directly to payload.out
17
+ console.log(`[svelte-on-rails:debug] written to payload (typeof payload.out => «${typeof payload.out}»)`)
18
+ } catch (error) {
19
+ console.error('[svelte-on-rails:debug] Error rendering component:', error);
20
+ process.exit(1);
21
+ }
22
+
23
+ const res = {status: 'SUCCESS', html: payload.out};
24
+ console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
25
+ })();
26
+
@@ -1,26 +1,74 @@
1
- import {loadComponentModule, readPropsFromStdin} from './utils.js';
1
+ // render.js (updated for Svelte 5+ SSR rendering with 'svelte/server')
2
+ // this script is, by rails assets:precompile copied to the public assets folder and used from there
3
+ // the reason for doing it this way is that this is the only clean way for using the svelte from frontends package.json
2
4
 
3
- (async () => {
5
+ import {fileURLToPath} from 'node:url';
6
+ import {dirname, resolve} from 'node:path';
7
+ const compiledComponentPath = process.argv[2];
4
8
 
5
- console.log(`[svelte-on-rails:debug] awaiting load component => «${process.argv[2]}»`)
9
+ import { render } from 'svelte/server';
6
10
 
7
- const MyComponent = await loadComponentModule(process.argv[2]);
8
- console.log(`[svelte-on-rails:debug] component read: «${MyComponent}}»`)
11
+ (async () => {
12
+ console.log(`[svelte-on-rails:debug] awaiting load component => «${compiledComponentPath}»`);
13
+ const compiledComponent = await loadComponentModule(compiledComponentPath);
14
+ console.log(`[svelte-on-rails:debug] component read: «${compiledComponent}»`);
9
15
 
10
16
  const props = await readPropsFromStdin();
11
- console.log(`[svelte-on-rails:debug] props read: «${props}»`)
12
-
13
- const payload = {out: []};
17
+ console.log(`[svelte-on-rails:debug] props read: «${JSON.stringify(props)}»`);
14
18
 
15
19
  try {
16
- MyComponent(payload, props); // Writes directly to payload.out
17
- console.log(`[svelte-on-rails:debug] written to payload (typeof payload.out => «${typeof payload.out}»)`)
20
+ // Svelte 5+ SSR rendering (runes-compatible; signals omitted on server for perf)
21
+ // Returns { body: string, head: string } no 'html' or 'css' props
22
+ const { body, head } = render(compiledComponent, { props });
23
+
24
+ const res = {
25
+ status: 'SUCCESS',
26
+ html: body, // Use 'body' as the main HTML content (replaces old 'html')
27
+ head: head || '', // Optional: Include <head> content (styles, meta, etc.)
28
+ // Add bodyAttributes or other result props if needed in future
29
+ };
30
+
31
+ console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
18
32
  } catch (error) {
19
33
  console.error('[svelte-on-rails:debug] Error rendering component:', error);
20
34
  process.exit(1);
21
35
  }
22
-
23
- const res = {status: 'SUCCESS', html: payload.out};
24
- console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
25
36
  })();
26
37
 
38
+ async function loadComponentModule(compiledFile) {
39
+ // Get the directory of the current script
40
+ const __filename = fileURLToPath(import.meta.url);
41
+ const __dirname = dirname(__filename);
42
+
43
+ try {
44
+ // Convert relative path to absolute path
45
+ const absolutePath = resolve(__dirname, compiledFile);
46
+
47
+ // Convert absolute path to a file URL
48
+ const modulePath = `file://${absolutePath}`;
49
+
50
+ // Import the module
51
+ const module = await import(modulePath);
52
+ return module.default;
53
+ } catch (error) {
54
+ console.error(`=> compiledFile: «${compiledFile}»`);
55
+ console.error(`[loadComponentModule] Error loading component from ${compiledFile}:`, error);
56
+ process.exit(1);
57
+ }
58
+ }
59
+
60
+ function readPropsFromStdin() {
61
+ return new Promise((resolve, reject) => {
62
+ let input = '';
63
+ process.stdin.setEncoding('utf8');
64
+ process.stdin.on('data', (chunk) => (input += chunk));
65
+ process.stdin.on('end', () => {
66
+ try {
67
+ resolve(JSON.parse(input));
68
+ } catch (error) {
69
+ reject(new Error(`Error parsing JSON from STDIN: ${error.message}\nInput: «${input}»`));
70
+ }
71
+ });
72
+ process.stdin.on('error', (error) => reject(new Error(`Error reading STDIN: ${error.message}`)));
73
+ });
74
+ }
@@ -26,12 +26,15 @@ module SvelteOnRails
26
26
 
27
27
  cmd = [
28
28
  cnf.node_bin_path,
29
- File.join(utils.gem_app_dir, 'renderer', 'render.js'),
30
- @component_files[:compiled_file] + '.js',
31
- cnf.rails_root
29
+ cnf.ssr_dist_folder.join('render.js'),
30
+ @component_files[:compiled_file] + '.js'
32
31
  ].join(' ')
33
32
 
34
- stdout, stderr, status = Open3.capture3(cmd, stdin_data: props.to_json, chdir: cnf.rails_root)
33
+ stdout, stderr, status = Open3.capture3(
34
+ cmd,
35
+ stdin_data: props.to_json,
36
+ chdir: cnf.rails_root,
37
+ )
35
38
 
36
39
  ary = stdout.split('[svelte-on-rails:successful-json-response]')
37
40