svelte-on-rails 0.0.18 → 0.0.21

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bdaed0f08472a9dde76f78c8d69f99b1b9cd1422ed75631620e3e60cff5c8ba
4
- data.tar.gz: 6dedb73fdb5b1a85bdd6996c7947e9a66ab5e69663e86a5f868d1dfd20dc8115
3
+ metadata.gz: 4760a8d0ae7d7de9e8bfb08b82e6cc7ff830979ef1297001606ab9a6eb282bff
4
+ data.tar.gz: 49ba7cbb917e62092d1997a4d39b1815d43a71546d78c5c5e52845e95a4c2d7e
5
5
  SHA512:
6
- metadata.gz: 270ba6319f043ac8aa36bf437d338a400aa2b03005d060b93e86c939df638c40688faf57c0758ccc231031ae6da969bc57d9570a04ae649c7f912e3df41a893f
7
- data.tar.gz: 272da007dd9136464b1705b47f4d6fc0f1a3ba046ee1299d70442648c3b412b8450cf655d3888b60a4c7a117fa9a4ee63e56b01adc3d0742be7fcd7bcb763432
6
+ metadata.gz: 4a3774a457cb886ff0854393857aea33b0c067cb814f72a94bad40c7beb4265018544370b1df2e5c6968daf35df9318897dcc666e16e595e8108f1e04c63547a
7
+ data.tar.gz: b35eabfabd993155ced5ad68f90f9c8795e9520234312f142bd42c25c98b5fe16ebddec50c230879df72a144c13c31e3ace74a9cbaee7681264f4707e658c613
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Svelte on rails
1
+ # Svelte. On rails! Awesome.
2
2
 
3
3
  Seamless and robust Svelte in Rails integration.
4
4
 
5
- By default, and when installed together with hotwired/turbo, it renders
5
+ By default, and when installed together with `@hotwired/turbo-rails`, it renders
6
6
  svelte components on first request server side («SSR») and for subsequent
7
7
  requests it provides a empty tag that will be mounted on the frontend by the associated npm package [@csedl/svelte-on-rails](https://www.npmjs.com/package/@csedl/svelte-on-rails) on the frontend.
8
8
 
@@ -34,17 +34,33 @@ If you have issues, please open one and contributors are welcome!
34
34
  - svelte v5 (see: [how to install svelte on rails/vite](https://dev.to/chmich/setup-inertia-and-svelte-on-rails-7-3glk))
35
35
  - turbo (recommended / [how to install turbo on rails](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#installation))
36
36
 
37
- ## Setup from cero
37
+ ## Installation from cero
38
+
39
+ together with haml, vite, svelte and turbo
38
40
 
39
41
  If you want to start from a new rails app, follow theese tutorials
40
42
 
41
- - [Create a new rails app with vite_rails](https://dev.to/chmich/setup-vite-on-rails-7-f1i)
42
- - create a controller and a view and you should see `Vite ⚡️ Rails` on the browser console.
43
- - make sure vite is on its latest version, sometimes you have to `npm i vite@latest`
44
- - [Setup Svelte](https://dev.to/chmich/setup-inertia-and-svelte-on-rails-7-3glk)
45
- - and restart the app
43
+ ```bash
44
+ rails new my-test-app --skip-javascript
45
+ ```
46
+
47
+ within the app path do
48
+
49
+ ```bash
50
+ bundle add svelte-on-rails
51
+ ```
52
+
53
+ and run the fat installer
46
54
 
47
- ## Installation
55
+ ```bash
56
+ rails svelte_on_rails:install_haml_vite
57
+ ```
58
+
59
+ this installer guides you through and if you answer all with yes,
60
+ at the end, you just have to (re-) start your server
61
+ and you will see a Svelte component!
62
+
63
+ ## Minimal Installation
48
64
 
49
65
  within the app folder
50
66
 
@@ -52,14 +68,11 @@ within the app folder
52
68
  bundle add svelte-on-rails
53
69
  ```
54
70
  ```bash
55
- rails svelte_on_rails:install_for_vite_and_turbo
71
+ rails svelte_on_rails:install
56
72
  ```
57
73
 
58
-
59
74
  This will create a little config file, installs the npm package,
60
75
  creates a initializer file and adds the import statement on `appplication.js` entrypoint file
61
- and it adds a HelloWorld.svelte component.
62
- If not installed, it installs `@hotwired/turbo-rails` too.
63
76
 
64
77
  #### Minimal installer
65
78
 
@@ -69,7 +82,13 @@ There is also a minimal installer:
69
82
  rails svelte_on_rails:install
70
83
  ```
71
84
 
72
- that does nothing else than creating a config file.
85
+ that does:
86
+
87
+ - creating a config file.
88
+ - installs the npm package
89
+
90
+ please follow the instructions on [@csedl/svelte-on-rails](https://www.npmjs.com/package/@csedl/svelte-on-rails)
91
+ for setup the workflow
73
92
 
74
93
  Within the config file, there are mainly two important tags:
75
94
 
@@ -92,7 +111,7 @@ On [@csedl/svelte-on-rails](https://www.npmjs.com/package/@csedl/svelte-on-rails
92
111
  are details how the frontend part is working.
93
112
 
94
113
  Without the npm package installed,
95
- or by passing `render_server_side: true` and `hydrate: false` to the view helper,
114
+ or by passing `ssr: true` and `hydrate: false` to the view helper,
96
115
  you would see the same html, and the styled button,
97
116
  but the increment button would not work.
98
117
 
@@ -112,13 +131,13 @@ Among others there are
112
131
  - `import { someFunction } from '../customJavascript.js';`
113
132
  - `import Child from './Child.svelte';`
114
133
 
115
- ## Option `render_server_side: :auto`
134
+ ## Option `ssr: :auto`
116
135
 
117
- `render_server_side: :auto` is the default option, as set on config file and can be overridden on the view helper.
136
+ `ssr: :auto` is the default option, as set on config file and can be overridden on the view helper.
118
137
 
119
138
  Works with `hotwired/turbo` only
120
139
 
121
- By passing the `render_server_side: :auto` option to the view helper,
140
+ By passing the `ssr: :auto` option to the view helper,
122
141
  it checks if the request is an initial request (request header `X-Turbo-Request-ID` is present):
123
142
 
124
143
  On Initial-Request, it adds the attribute `data-svelte-on-rails-initialize-action="hydrate"` and
@@ -161,6 +180,26 @@ or you want to see the state before hydration, for development purposes, you can
161
180
  the `hydrate: false` option to the view helper,
162
181
  and no hydration will happen for this component.
163
182
 
183
+ ## More rake tasks
184
+
185
+ This tasks are more for testing/playground purposes
186
+
187
+ ```bash
188
+ rails svelte_on_rails:add_hello_world
189
+ ```
190
+
191
+ ```bash
192
+ rails svelte_on_rails:remove_hello_world
193
+ ```
194
+
195
+ ```bash
196
+ rails svelte_on_rails:reset_and_compile_all
197
+ ```
198
+
199
+ This does the same step that ist triggered together with the
200
+ `rails assets:precompile` step together with the deployment pipeline:
201
+ it removes all contents of the svelte-on-rails compiled
202
+ assets and compiles them all new.
164
203
 
165
204
  ## Performance
166
205
 
@@ -3,6 +3,16 @@ require "svelte_on_rails/view_helpers"
3
3
  require "svelte_on_rails/render_server_side"
4
4
  require "svelte_on_rails/railtie" if defined?(Rails)
5
5
 
6
+ # installer
7
+ require 'svelte_on_rails/installer/utils'
8
+ require 'svelte_on_rails/installer/haml'
9
+ require 'svelte_on_rails/installer/gem_utils'
10
+ require 'svelte_on_rails/installer/vite'
11
+ require 'svelte_on_rails/installer/svelte'
12
+ require 'svelte_on_rails/installer/npm'
13
+ require 'svelte_on_rails/installer/javascript'
14
+ require 'svelte_on_rails/installer/hello_world'
15
+
6
16
  module SvelteOnRails
7
17
  class << self
8
18
  def configuration
@@ -49,8 +49,8 @@ module SvelteOnRails
49
49
  @configs['components_folder']
50
50
  end
51
51
 
52
- def render_server_side
53
- rss = @configs['render_server_side']
52
+ def ssr
53
+ rss = @configs['ssr']
54
54
  if rss == false || rss == :auto
55
55
  rss
56
56
  else
@@ -0,0 +1,36 @@
1
+ module SvelteOnRails
2
+
3
+ module GemUtils
4
+
5
+ def self.check_gem_version(gem_name)
6
+ gl = File.read(Rails.root.join('Gemfile.lock'))
7
+ regex = /(?<=#{Regexp.escape(gem_name)})[<>=\(~0-9\. \),]+/
8
+ match = gl.match(regex)
9
+
10
+ if match
11
+ match.to_s.gsub('(','').gsub(')','').strip
12
+ end
13
+
14
+ end
15
+
16
+ def self.install_gem(gem_name, group: nil)
17
+ v = check_gem_version(gem_name)
18
+ if v
19
+ puts "Gem #{gem_name} already installed, version: #{v} "
20
+ else
21
+ cmd = [
22
+ "bundle add #{gem_name}",
23
+ (group ? "--group=#{group}" : nil)
24
+ ].compact.join(' ')
25
+ stdout, stderr, status = Open3.capture3(cmd)
26
+ if stderr.present?
27
+ raise stderr
28
+ else
29
+ puts "Installed #{gem_name} version #{check_gem_version(gem_name)}"
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+ end
36
+ end
@@ -0,0 +1,109 @@
1
+ module SvelteOnRails
2
+ module Installer
3
+ module Haml
4
+ def self.install_haml_and_convert
5
+
6
+ # install haml-rails
7
+
8
+ puts '-' * 80
9
+
10
+ gu = SvelteOnRails::GemUtils
11
+ gu.install_gem('haml-rails')
12
+
13
+ # check existing files
14
+
15
+ existing_haml_files = Dir.glob('app/views/**/*.haml').select { |f| File.file? f }
16
+
17
+ overwrite_files = []
18
+ files = Dir.glob('app/views/**/*.html.erb').each_with_object([]) do |f, ary|
19
+ new_file = f.gsub(/\.erb\z/, '.haml')
20
+ if File.file? new_file
21
+ overwrite_files += [new_file]
22
+ existing_haml_files.delete(new_file)
23
+ end
24
+ if File.file? f
25
+ ary << [
26
+ f,
27
+ new_file
28
+ ]
29
+ end
30
+ end
31
+
32
+ if files.empty?
33
+ puts "No .erb files found, no conversion necessary."
34
+ return
35
+ end
36
+
37
+ # ask if haml already exist
38
+
39
+ if existing_haml_files.any?
40
+ puts '-' * 80
41
+ begin
42
+ puts "Theare are already .haml files:"
43
+ puts existing_haml_files
44
+ puts "Would you like to continue? (y/n)"
45
+ continue = STDIN.gets.chomp.downcase[0]
46
+ end until ['y', 'n'].include?(continue)
47
+ if continue == 'n'
48
+ puts 'skipping convert to haml'
49
+ return
50
+ end
51
+ end
52
+
53
+ # ask if overwrite
54
+
55
+ if overwrite_files.any?
56
+ puts '-' * 80
57
+ begin
58
+ puts "The following files already exist and would be overwritten:"
59
+ puts overwrite_files
60
+ puts "Would you like to overwrite these .haml files? (y/n)"
61
+ should_overwrite = STDIN.gets.chomp.downcase[0]
62
+ end until ['y', 'n'].include?(should_overwrite)
63
+ end
64
+
65
+ puts '-' * 80
66
+
67
+ # check for html2haml
68
+
69
+ installed_html2haml = false
70
+ if gu.check_gem_version('html2haml')
71
+ puts "html2haml already installed, now converting..."
72
+ else
73
+ gu.install_gem('html2haml', group: 'development')
74
+ installed_html2haml = true
75
+ end
76
+
77
+ # convert
78
+
79
+ backup_dir = "svelte_on_rails_backup_views_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
80
+ FileUtils.mkdir_p(backup_dir)
81
+
82
+ Dir.chdir(Rails.root) do
83
+ files.each do |f|
84
+ stdout, stderr, status = Open3.capture3("html2haml #{f.join(' ')}")
85
+ if stderr.present?
86
+ raise stderr
87
+ else
88
+ view_dir = File.dirname(f.first).to_s.match(/(?<=app\/views\/)(.*)/).to_s
89
+ backup_view_dir = backup_dir + '/' + view_dir
90
+ FileUtils.mkdir_p(backup_view_dir)
91
+ FileUtils.mv(f.first, backup_view_dir)
92
+ puts "Converted #{f.join(' => ')}"
93
+ end
94
+ end
95
+ end
96
+
97
+ if installed_html2haml
98
+ system("bundle remove html2haml")
99
+ if $?.success?
100
+ puts "cleanup: removed html2haml from Gemfile"
101
+ else
102
+ puts "ERROR: failed to remove html2haml (please remove manually as it was only installed for this task)"
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,57 @@
1
+ module SvelteOnRails
2
+ module Installer
3
+ module HelloWorld
4
+
5
+ def self.install_hello_world
6
+ utils_i = SvelteOnRails::Installer::Utils
7
+
8
+ # write templates
9
+
10
+ templates = %w[
11
+ app/controllers/svelte_on_rails_hello_world_controller.rb
12
+ app/views/svelte_on_rails_hello_world/index.haml
13
+ app/frontend/javascript/components/SvelteOnRailsHelloWorld.svelte
14
+ ]
15
+ utils_i.write_templates(templates)
16
+
17
+ # route
18
+
19
+ route = 'svelte_on_rails_hello_world#index'
20
+ rr = utils_i.which_root_route
21
+ root_url = "/"
22
+ url = root_url + route.sub('#', '/')
23
+
24
+ if rr && rr == route
25
+ puts "Root route «#{route}» already exists, skipping."
26
+ root_url
27
+ elsif rr && utils_i.route_exists?(route.sub('#', '/'))
28
+ puts "route «#{route}» already exists, skipping."
29
+ url
30
+ elsif rr
31
+ utils_i.add_route(" get \"#{route.sub('#', '/')}\"")
32
+ url
33
+ else
34
+ utils_i.add_route(' root "svelte_on_rails_hello_world#index"')
35
+ root_url
36
+ end
37
+
38
+ end
39
+
40
+ def self.remove_hello_world
41
+
42
+ utils = SvelteOnRails::Installer::Utils
43
+ if utils.ask_yn('Remove the Hello World component?')
44
+ files = %w[
45
+ app/views/svelte_on_rails_hello_world/index.haml
46
+ app/views/svelte_on_rails_hello_world
47
+ app/controllers/svelte_on_rails_hello_world_controller.rb
48
+ app/frontend/javascript/components/SvelteOnRailsHelloWorld.svelte
49
+ ]
50
+ utils.remove_files(files)
51
+ utils.remove_line_from_file('config/routes.rb', 'svelte_on_rails_hello_world')
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,55 @@
1
+ module SvelteOnRails
2
+ module Installer
3
+ module Javascript
4
+
5
+ # check if import statement already exists and, if not, append it after the last import statement of that file
6
+ #
7
+
8
+ def self.append_import_statement(file_path, package_name_for_test_existence, import_statement)
9
+
10
+ # Read the file content
11
+ content = File.read(file_path)
12
+
13
+ # Split content into lines
14
+ lines = content.lines
15
+
16
+ already_exist = []
17
+ lines.each do |line|
18
+ if line.match(/^\s*import\s+.*['"]#{package_name_for_test_existence}['";].*$/)
19
+ already_exist.push(line)
20
+ end
21
+ end
22
+
23
+ if already_exist.present?
24
+ puts "skipping: #{import_statement} already exists in #{File.basename(file_path)}, found: «#{already_exist.join(' // ').strip}»."
25
+ else
26
+
27
+ # Find the index of the last import statement
28
+ last_import_index = -1
29
+ lines.each_with_index do |line, index|
30
+ if line.match?(/^\s*import\s+.*$/)
31
+ last_import_index = index
32
+ end
33
+ end
34
+
35
+ # Insert the import statement after the last import
36
+ if last_import_index >= 0
37
+ lines.insert(last_import_index + 1, import_statement)
38
+ else
39
+ # If no import statements, add at the beginning
40
+ lines.unshift(import_statement)
41
+ end
42
+
43
+ # Write the modified content back to the file
44
+ begin
45
+ File.write(file_path, lines.map{|l|l.gsub(/\n/, '')}.join("\n"))
46
+ puts "Successfully inserted «#{import_statement}» into '#{file_path}'"
47
+ rescue => e
48
+ raise "Error writing to #{file_path} => «#{e.message}»"
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,90 @@
1
+ module SvelteOnRails
2
+ module Installer
3
+ module Npm
4
+
5
+ def self.install_or_update_package(package_name, minimal_version: nil, update_to_latest: true)
6
+ pkg = inspect_package(package_name)
7
+ to_do = !check_version((pkg ? pkg[:version] : nil), minimal_version)
8
+ if to_do
9
+
10
+ cmd = if update_to_latest
11
+ "npm install #{package_name}@latest"
12
+ else
13
+ raise "ERROR: not implemented"
14
+ end
15
+
16
+ stdout, stderr, status = Open3.capture3(cmd)
17
+ if stderr.present?
18
+ raise "ERROR #{cmd} => #{stderr}"
19
+ end
20
+
21
+ notice = [
22
+ (pkg ? "Updated" : "Installed"),
23
+ package_name,
24
+ (pkg ? "from version #{pkg[:version].join('.')}" : nil),
25
+ (pkg ? "to" : nil),
26
+ "@latest"
27
+ ].compact.join(' ')
28
+
29
+ puts notice
30
+
31
+ else
32
+ min_str = minimal_version.present? ? ", required: >= #{minimal_version.join('.')}" : ''
33
+ puts "#{package_name} already installed (#{pkg[:version].join('.')}#{min_str}), skipping."
34
+ end
35
+ end
36
+
37
+ def self.inspect_package(package_name)
38
+ pkg = nil
39
+ version = nil
40
+
41
+ if File.exist?('package-lock.json')
42
+ pl = JSON.parse(File.read('package-lock.json'))
43
+ unless pl['packages']
44
+ raise "ERROR: package-lock.json found, but no packages found, seems to be corrupted."
45
+ end
46
+ pkg = pl['packages'].keys.grep(/\/#{package_name}$/).first
47
+ version = pl['packages'][pkg]['version'] if pkg
48
+ end
49
+
50
+ if pkg
51
+ {
52
+ type: pkg.match(/^.*?(?=\/[^\/]*$)/).to_s,
53
+ version: version.split('.').map(&:to_i)
54
+ }
55
+ end
56
+
57
+ end
58
+
59
+ def self.check_version(current_version, minimal_version)
60
+ if !current_version
61
+ return false
62
+ elsif !minimal_version.present?
63
+ return true
64
+ else
65
+ compare_version_arrays(current_version, minimal_version)
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def self.compare_version_arrays(current_version, minimal_version)
72
+ raise "ERROR: current_version must be an array" unless current_version.is_a?(Array)
73
+ raise "ERROR: minimal_version must be an array" unless current_version.is_a?(Array)
74
+
75
+ current_version.each_with_index do |v, i|
76
+ raise "ERROR: current_version entries must be an integer" unless v.is_a?(Integer)
77
+
78
+ if minimal_version[i]
79
+ raise "ERROR: minimal_version entries must be an integer" unless minimal_version[i].is_a?(Integer)
80
+ if v < minimal_version[i]
81
+ return false
82
+ end
83
+ end
84
+ end
85
+ true
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,6 @@
1
+ class SvelteOnRailsHelloWorldController < ApplicationController
2
+
3
+ def index
4
+ end
5
+
6
+ end
@@ -0,0 +1,18 @@
1
+
2
+ import { initializeSvelteComponents, cleanupSvelteComponents } from '@csedl/svelte-on-rails';
3
+
4
+ const components = import.meta.glob('/javascript/components/**/*.svelte', { eager: true });
5
+ const componentsRoot = '/javascript/components';
6
+
7
+ // Initialize Svelte components
8
+ initializeSvelteComponents(componentsRoot, components, true);
9
+
10
+ // Turbo event listener for page load
11
+ document.addEventListener('turbo:load', () => {
12
+ initializeSvelteComponents(componentsRoot, components, true);
13
+ });
14
+
15
+ // Turbo event listener for cleanup before page cache
16
+ document.addEventListener('turbo:before-cache', () => {
17
+ cleanupSvelteComponents(false);
18
+ });
@@ -0,0 +1,3 @@
1
+ %h1 Hello
2
+
3
+ = svelte_component "SvelteOnRailsHelloWorld"
@@ -0,0 +1,23 @@
1
+ frontend_folder: "app/frontend"
2
+ # the entrypoint that is your web root, example for vite: where @ points to
3
+ # relative to Rails.root
4
+
5
+ components_folder: "javascript/components"
6
+ # relative to frontend_folder
7
+ # where your svelte components are located
8
+
9
+ ssr: :auto
10
+ # options: true, false, :auto
11
+ # :auto: render server side if request is initial request (works only with turbo, because it checks for the X-Turbo-Request-ID header)
12
+ # when not server-side rendered the components must be built as custom elements, see node-package @csedl/svelte-on-rails
13
+
14
+ development:
15
+ watch_changes: true
16
+ # Check on every request if any file within the svelte components folder have changed, for recompiling
17
+ # Case sensitive path checking, even the file system is case insensitive
18
+ # Make sure this ist set to tue for development and test, but not for production
19
+
20
+ test:
21
+ watch_changes: true
22
+
23
+ production:
@@ -0,0 +1,22 @@
1
+ module SvelteOnRails
2
+ module Installer
3
+ module Svelte
4
+
5
+ def self.install_svelte
6
+ puts '-' * 80
7
+
8
+ # check npm package version
9
+
10
+ npm_i = SvelteOnRails::Installer::Npm
11
+ npm_i.install_or_update_package('svelte', minimal_version: [5])
12
+
13
+ # configure vite
14
+
15
+ vite_i = SvelteOnRails::Installer::Vite
16
+ vite_i.configure_for_svelte
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end