svelte-on-rails 0.0.20 → 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 +4 -4
- data/README.md +52 -13
- data/lib/svelte-on-rails.rb +10 -1
- data/lib/svelte_on_rails/installer/gem_utils.rb +36 -0
- data/lib/svelte_on_rails/installer/haml.rb +109 -0
- data/lib/svelte_on_rails/installer/hello_world.rb +57 -0
- data/lib/svelte_on_rails/installer/javascript.rb +55 -0
- data/lib/svelte_on_rails/installer/npm.rb +90 -0
- data/lib/svelte_on_rails/installer/rails_template/app/controllers/svelte_on_rails_hello_world_controller.rb +6 -0
- data/lib/svelte_on_rails/installer/rails_template/app/frontend/initializers/svelte.js +18 -0
- data/lib/svelte_on_rails/installer/rails_template/app/frontend/javascript/components/SvelteOnRailsHelloWorld.svelte +1 -0
- data/lib/svelte_on_rails/installer/rails_template/app/views/svelte_on_rails_hello_world/index.haml +3 -0
- data/lib/svelte_on_rails/installer/rails_template/config/svelte_on_rails.yml +23 -0
- data/lib/svelte_on_rails/installer/svelte.rb +22 -0
- data/lib/svelte_on_rails/installer/utils.rb +328 -0
- data/lib/svelte_on_rails/installer/vite.rb +91 -0
- data/lib/tasks/svelte_on_rails_tasks.rake +89 -19
- metadata +15 -3
- data/lib/svelte_on_rails/installer_utils.rb +0 -170
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4760a8d0ae7d7de9e8bfb08b82e6cc7ff830979ef1297001606ab9a6eb282bff
|
4
|
+
data.tar.gz: 49ba7cbb917e62092d1997a4d39b1815d43a71546d78c5c5e52845e95a4c2d7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a3774a457cb886ff0854393857aea33b0c067cb814f72a94bad40c7beb4265018544370b1df2e5c6968daf35df9318897dcc666e16e595e8108f1e04c63547a
|
7
|
+
data.tar.gz: b35eabfabd993155ced5ad68f90f9c8795e9520234312f142bd42c25c98b5fe16ebddec50c230879df72a144c13c31e3ace74a9cbaee7681264f4707e658c613
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Seamless and robust Svelte in Rails integration.
|
4
4
|
|
5
|
-
By default, and when installed together with hotwired/turbo
|
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
|
-
##
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
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:
|
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
|
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
|
|
@@ -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
|
|
data/lib/svelte-on-rails.rb
CHANGED
@@ -2,7 +2,16 @@ require "svelte_on_rails/configuration"
|
|
2
2
|
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'
|
6
15
|
|
7
16
|
module SvelteOnRails
|
8
17
|
class << self
|
@@ -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,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 @@
|
|
1
|
+
<h1>Hello Svelte</h1>
|
@@ -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
|
@@ -0,0 +1,328 @@
|
|
1
|
+
module SvelteOnRails
|
2
|
+
|
3
|
+
module Installer
|
4
|
+
|
5
|
+
module Utils
|
6
|
+
def self.install_npm_package
|
7
|
+
package_name = "@csedl/svelte-on-rails@latest"
|
8
|
+
puts "Installing #{package_name} via npm..."
|
9
|
+
|
10
|
+
if system("npm install #{package_name}")
|
11
|
+
puts "#{package_name} successfully installed."
|
12
|
+
else
|
13
|
+
abort "Failed to install #{package_name}. Please ensure npm is installed and try running 'npm install #{package_name}' manually."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.install_turbo
|
18
|
+
|
19
|
+
pkg_js = Rails.root.join("package.json")
|
20
|
+
package_name = "@hotwired/turbo-rails"
|
21
|
+
file_content = File.exist?(pkg_js) ? File.read(pkg_js) : ""
|
22
|
+
|
23
|
+
if file_content.match?(/#{package_name}/)
|
24
|
+
puts "#{package_name} is already present in package.json, assuming that it is set up well and working."
|
25
|
+
else
|
26
|
+
puts "Installing #{package_name} via npm..."
|
27
|
+
if system("npm install #{package_name}")
|
28
|
+
puts "#{package_name} successfully installed."
|
29
|
+
add_line_to_file(Rails.root.join("app", "frontend", "entrypoints", "application.js"), "import '#{package_name}';")
|
30
|
+
else
|
31
|
+
abort "Failed to install #{package_name}. Please ensure npm is installed and try running 'npm install #{package_name}' manually."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.create_folder(folder)
|
38
|
+
if Dir.exist?(folder)
|
39
|
+
puts "Folder already exists: #{folder}"
|
40
|
+
else
|
41
|
+
FileUtils.mkdir_p(folder)
|
42
|
+
puts "Created folder: #{folder}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.add_line_to_file(file_path, line)
|
47
|
+
file_content = File.exist?(file_path) ? File.read(file_path) : ""
|
48
|
+
|
49
|
+
if file_content.match?(/#{line}/)
|
50
|
+
puts "#{line} already present in #{file_path}, nothing changed here."
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
File.open(file_path, 'a') do |file|
|
55
|
+
file.puts(line)
|
56
|
+
end
|
57
|
+
puts "added #{line} to #{file_path}."
|
58
|
+
rescue StandardError => e
|
59
|
+
puts "Error: #{e.message}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.create_file(file_path)
|
63
|
+
|
64
|
+
unless File.exist?(file_path)
|
65
|
+
FileUtils.touch(file_path)
|
66
|
+
puts "Created empty file at file://#{file_path}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.create_javascript_initializer
|
71
|
+
config_path = Rails.root.join("app", "frontend", "initializers", "svelte.js")
|
72
|
+
if File.exist?(config_path)
|
73
|
+
puts "Initializer already exists: file://#{config_path}"
|
74
|
+
else
|
75
|
+
File.write(config_path, <<~JAVASCRIPT)
|
76
|
+
|
77
|
+
import { initializeSvelteComponents, cleanupSvelteComponents } from '@csedl/svelte-on-rails';
|
78
|
+
|
79
|
+
const components = import.meta.glob('/javascript/components/**/*.svelte', { eager: true });
|
80
|
+
const componentsRoot = '/javascript/components';
|
81
|
+
|
82
|
+
// Initialize Svelte components
|
83
|
+
initializeSvelteComponents(componentsRoot, components, true);
|
84
|
+
|
85
|
+
// Turbo event listener for page load
|
86
|
+
document.addEventListener('turbo:load', () => {
|
87
|
+
initializeSvelteComponents(componentsRoot, components, true);
|
88
|
+
});
|
89
|
+
|
90
|
+
// Turbo event listener for cleanup before page cache
|
91
|
+
document.addEventListener('turbo:before-cache', () => {
|
92
|
+
cleanupSvelteComponents(false);
|
93
|
+
});
|
94
|
+
JAVASCRIPT
|
95
|
+
puts "Created initializer file at file://#{config_path}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.create_svelte_hello_world
|
100
|
+
file_path = Rails.root.join("app", "frontend", "javascript", "components", "HelloWorld.svelte")
|
101
|
+
if File.exist?(file_path)
|
102
|
+
puts "Hello World file already exists: file://#{file_path}"
|
103
|
+
else
|
104
|
+
File.write(file_path, <<~HTML)
|
105
|
+
<script>
|
106
|
+
export let items
|
107
|
+
let count = 0;
|
108
|
+
|
109
|
+
function increment() {
|
110
|
+
count += 1;
|
111
|
+
}
|
112
|
+
</script>
|
113
|
+
|
114
|
+
<h1>Greetings from svelte</h1>
|
115
|
+
|
116
|
+
<button on:click={increment}>Increment: {count}</button>
|
117
|
+
<ul>
|
118
|
+
{#each items as item}
|
119
|
+
<li>{item}</li>
|
120
|
+
{/each}
|
121
|
+
</ul>
|
122
|
+
|
123
|
+
<style>
|
124
|
+
button {
|
125
|
+
background-color: darkred;
|
126
|
+
color: white;
|
127
|
+
padding: 10px;
|
128
|
+
border: none;
|
129
|
+
}
|
130
|
+
</style>
|
131
|
+
HTML
|
132
|
+
puts "Hello World file at file://#{file_path}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.run_command(command)
|
137
|
+
|
138
|
+
Dir.chdir(Rails.root) do
|
139
|
+
stdout, stderr, status = Open3.capture3(command)
|
140
|
+
if stderr.present?
|
141
|
+
puts "Error running command «#{command}»:"
|
142
|
+
raise stderr
|
143
|
+
else
|
144
|
+
puts "#{command} => Success"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.check_file_exists(file_path)
|
151
|
+
unless File.exist?(file_path)
|
152
|
+
raise "ERROR: File not found: #{file_path}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.check_folder_exists(folder_path)
|
157
|
+
unless File.exist?(folder_path)
|
158
|
+
raise "ERROR: Folder not found: #{folder_path}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.check_file_not_exists(file_path)
|
163
|
+
if File.exist?(file_path)
|
164
|
+
raise "ERROR: File already exists: #{file_path}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.check_folder_not_exists(folder_path)
|
169
|
+
if File.exist?(folder_path)
|
170
|
+
raise "ERROR: Folder already exists: #{folder_path}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.write_templates(template_paths)
|
175
|
+
|
176
|
+
existing = template_paths.select { |p| File.exist?(p) }
|
177
|
+
verb = 'Created'
|
178
|
+
|
179
|
+
if existing.present?
|
180
|
+
begin
|
181
|
+
puts "#{'Template'.pluralize(existing.length)} already exists:\n#{existing.join("\n")}.\nOverwrite? (y/n)"
|
182
|
+
continue = STDIN.gets.chomp.downcase[0]
|
183
|
+
end until ['y', 'n'].include?(continue)
|
184
|
+
if continue == 'n'
|
185
|
+
puts "Skipping write #{'template'.pluralize(template_paths.length)}."
|
186
|
+
return
|
187
|
+
end
|
188
|
+
verb = 'Overwrote'
|
189
|
+
end
|
190
|
+
|
191
|
+
template_paths.each do |p|
|
192
|
+
source_path = File.expand_path('rails_template', __dir__) + '/' + p
|
193
|
+
FileUtils.mkdir_p(File.dirname(p))
|
194
|
+
FileUtils.cp(source_path, p)
|
195
|
+
end
|
196
|
+
|
197
|
+
puts "#{verb} #{'file'.pluralize(template_paths.length)}:\n#{template_paths.join("\n")}"
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.ask_yn(question)
|
201
|
+
begin
|
202
|
+
puts "#{question} (y/n)"
|
203
|
+
continue = STDIN.gets.chomp.downcase[0]
|
204
|
+
end until ['y', 'n'].include?(continue)
|
205
|
+
continue == 'y'
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.which_root_route
|
209
|
+
|
210
|
+
# Check if the root route is active (uncommented) or commented out
|
211
|
+
|
212
|
+
routes = File.read(Rails.root.join('config', 'routes.rb'))
|
213
|
+
m = routes.match(/^\s*root\s+['"]([^'"]+)['"]/m)
|
214
|
+
if m
|
215
|
+
m.to_s.match(/^\s*root\s*['"]([^'"]*)['"]/)[1]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.add_route(route)
|
220
|
+
|
221
|
+
file_path = 'config/routes.rb'
|
222
|
+
|
223
|
+
# Read the file content
|
224
|
+
content = File.read(file_path)
|
225
|
+
|
226
|
+
# Split content into lines
|
227
|
+
lines = content.lines
|
228
|
+
|
229
|
+
# Find the index of Rails.application.routes.draw do
|
230
|
+
ind = -1
|
231
|
+
lines.each_with_index do |line, i|
|
232
|
+
if line.match?(/^\s*Rails.application.routes.draw\s*do[\s\S]+$/)
|
233
|
+
ind = i
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Insert
|
238
|
+
|
239
|
+
if ind >= 0
|
240
|
+
lines.insert(ind + 1, route)
|
241
|
+
else
|
242
|
+
raise "ERROR: Could not find Rails.application.routes.draw do"
|
243
|
+
end
|
244
|
+
|
245
|
+
# Write the modified content back to the file
|
246
|
+
begin
|
247
|
+
File.write(file_path, lines.map { |l| l.gsub(/\n/, '') }.join("\n"))
|
248
|
+
puts "Successfully inserted «root '#{route}'» into '#{file_path}'"
|
249
|
+
rescue => e
|
250
|
+
raise "Error writing to #{file_path} => «#{e.message}»"
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
def self.route_exists?(target_route)
|
256
|
+
|
257
|
+
# check if exists
|
258
|
+
# Ensure the Rails environment is loaded
|
259
|
+
# require File.expand_path("../config/environment", __dir__)
|
260
|
+
|
261
|
+
# Get all routes from the Rails application
|
262
|
+
routes = Rails.application.routes.routes
|
263
|
+
|
264
|
+
# Check if the route exists
|
265
|
+
routes.any? do |route|
|
266
|
+
# Extract the path spec and remove any optional parts or constraints
|
267
|
+
path = route.path.spec.to_s
|
268
|
+
# Clean up the path to match the format (remove leading/trailing slashes, etc.)
|
269
|
+
cleaned_path = path.gsub(/\(.*\)/, "").gsub(/^\/|\/$/, "")
|
270
|
+
# Check if the cleaned path matches the target route
|
271
|
+
cleaned_path == target_route
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
def self.remove_files(file_paths)
|
277
|
+
file_paths.each do |f|
|
278
|
+
if File.exist?(f)
|
279
|
+
if File.directory?(f)
|
280
|
+
Dir.delete(f)
|
281
|
+
puts " • Removed directory: #{f}"
|
282
|
+
else
|
283
|
+
File.delete(f)
|
284
|
+
puts " • Removed file: #{f}"
|
285
|
+
end
|
286
|
+
else
|
287
|
+
puts " • File/Path not found so not removed: #{f}"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def self.remove_line_from_file(file_path, string_to_find)
|
293
|
+
|
294
|
+
# Read the file content
|
295
|
+
content = File.read(file_path)
|
296
|
+
|
297
|
+
# Split content into lines
|
298
|
+
lines = content.lines
|
299
|
+
|
300
|
+
found_lines = []
|
301
|
+
modified_content = []
|
302
|
+
lines.each do |line|
|
303
|
+
if line.match(/^[\s\S]+#{string_to_find}[\s\S]+$/)
|
304
|
+
found_lines.push(line)
|
305
|
+
else
|
306
|
+
modified_content.push(line)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
utils = SvelteOnRails::Installer::Utils
|
311
|
+
if found_lines.present? && utils.ask_yn("Remove lines\n • #{found_lines.join("\n • ")}\n from #{file_path}?")
|
312
|
+
# Write the modified content back to the file
|
313
|
+
begin
|
314
|
+
File.write(file_path, modified_content.map{|l|l.gsub(/\n/, '')}.join("\n"))
|
315
|
+
puts "Successfully removed #{found_lines.length} #{'line'.pluralize(found_lines.length)}."
|
316
|
+
rescue => e
|
317
|
+
raise "Error writing to #{file_path} => «#{e.message}»"
|
318
|
+
end
|
319
|
+
else
|
320
|
+
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module SvelteOnRails
|
2
|
+
|
3
|
+
module Installer
|
4
|
+
|
5
|
+
module Vite
|
6
|
+
|
7
|
+
def self.install_vite
|
8
|
+
iu = SvelteOnRails::Installer::Utils
|
9
|
+
|
10
|
+
puts '-' * 80
|
11
|
+
|
12
|
+
gu = SvelteOnRails::GemUtils
|
13
|
+
if gu.check_gem_version('vite_rails')
|
14
|
+
puts "vite_rails already installed, skipping this part."
|
15
|
+
else
|
16
|
+
|
17
|
+
# check non-existence
|
18
|
+
|
19
|
+
iu.check_file_not_exists('config/vite.json')
|
20
|
+
iu.check_file_not_exists('vite.config.ts')
|
21
|
+
iu.check_folder_not_exists('app/frontend')
|
22
|
+
|
23
|
+
# install
|
24
|
+
|
25
|
+
gu.install_gem('vite_rails')
|
26
|
+
|
27
|
+
Dir.chdir(Rails.root) do
|
28
|
+
`bundle exec vite install`
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
# check existence
|
34
|
+
|
35
|
+
iu.check_file_exists('config/vite.json')
|
36
|
+
iu.check_file_exists('vite.config.ts')
|
37
|
+
iu.check_file_exists('package.json')
|
38
|
+
iu.check_file_exists('package-lock.json')
|
39
|
+
iu.check_file_exists('app/frontend/entrypoints/application.js')
|
40
|
+
iu.check_folder_exists('app/frontend')
|
41
|
+
|
42
|
+
# check npm package version
|
43
|
+
|
44
|
+
ni = SvelteOnRails::Installer::Npm
|
45
|
+
ni.install_or_update_package('vite', minimal_version: [6, 1])
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.configure_for_svelte
|
50
|
+
|
51
|
+
# add import statement
|
52
|
+
|
53
|
+
js_i = SvelteOnRails::Installer::Javascript
|
54
|
+
pkg = '@sveltejs/vite-plugin-svelte'
|
55
|
+
js_i.append_import_statement('vite.config.ts', pkg, "import {svelte} from '#{pkg}'")
|
56
|
+
npm_i = SvelteOnRails::Installer::Npm
|
57
|
+
npm_i.install_or_update_package(pkg)
|
58
|
+
|
59
|
+
# add plugin
|
60
|
+
|
61
|
+
file_content = File.read('vite.config.ts')
|
62
|
+
|
63
|
+
if file_content.match?(/svelte/)
|
64
|
+
puts "Svelte seams already configured in vite.config.ts, nothing changed here."
|
65
|
+
else
|
66
|
+
|
67
|
+
# Regex to match the plugins array and locate RubyPlugin()
|
68
|
+
plugins_regex = /(plugins:\s*\[\s*)(\s*)RubyPlugin\(\),\s*([^]]*?\])/m
|
69
|
+
|
70
|
+
# Check if plugins array with RubyPlugin exists
|
71
|
+
unless file_content.match?(plugins_regex)
|
72
|
+
puts "Error: No plugins array with RubyPlugin() found in the input."
|
73
|
+
return file_content
|
74
|
+
end
|
75
|
+
|
76
|
+
# Insert svelte({}), after RubyPlugin() with proper indentation
|
77
|
+
modified_content = file_content.gsub(plugins_regex) do |match|
|
78
|
+
prefix = $1 # Start of plugins array (e.g., "plugins: [")
|
79
|
+
indent = ' ' # Indentation before RubyPlugin()
|
80
|
+
rest = $3 # Remaining plugins and closing bracket
|
81
|
+
"#{prefix}#{indent}RubyPlugin(),\n#{indent}svelte({}),\n#{indent}#{rest}"
|
82
|
+
end
|
83
|
+
|
84
|
+
File.write('vite.config.ts', modified_content)
|
85
|
+
puts "Updated vite.config.ts with svelte() plugin."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -3,38 +3,108 @@ Rake::Task["assets:precompile"].enhance do
|
|
3
3
|
puts "Mount Svelte: Reset dist and compile-all executed"
|
4
4
|
end
|
5
5
|
|
6
|
-
require 'svelte_on_rails/
|
6
|
+
require 'svelte_on_rails/installer/utils'
|
7
|
+
require 'svelte_on_rails/installer/haml'
|
8
|
+
utils = SvelteOnRails::Installer::Utils
|
9
|
+
npm_i = SvelteOnRails::Installer::Npm
|
10
|
+
application_js_path = Rails.root.join("app", "frontend", "entrypoints", "application.js")
|
7
11
|
|
8
12
|
namespace :svelte_on_rails do
|
9
|
-
desc "Installs SvelteOnRails YAML configuration into your Rails application"
|
10
|
-
task :install do
|
11
13
|
|
12
|
-
|
14
|
+
desc "Installs SvelteOnRails for usage together with vite_rails, haml and @hotwired/turbo-rails"
|
15
|
+
task :install_haml_vite => :environment do
|
16
|
+
|
17
|
+
puts '-' * 80
|
18
|
+
puts 'STARTING SVELTE-ON-RAILS INSTALLATION'
|
19
|
+
|
20
|
+
# svelte_on_rails
|
21
|
+
|
22
|
+
utils.write_templates(['config/svelte_on_rails.yml'])
|
23
|
+
npm_i.install_or_update_package('@csedl/svelte-on-rails')
|
24
|
+
# insert_initializer
|
25
|
+
uts = SvelteOnRails::Installer::Utils
|
26
|
+
uts.write_templates(['app/frontend/initializers/svelte.js'])
|
27
|
+
# add import statements
|
28
|
+
js_i = SvelteOnRails::Installer::Javascript
|
29
|
+
init_stat = '../initializers/svelte.js'
|
30
|
+
js_i.append_import_statement(application_js_path, init_stat, "import '#{init_stat}';")
|
31
|
+
|
32
|
+
|
33
|
+
# haml
|
34
|
+
|
35
|
+
haml_i = SvelteOnRails::Installer::Haml
|
36
|
+
haml_i.install_haml_and_convert
|
37
|
+
|
38
|
+
# vite
|
39
|
+
|
40
|
+
vite_i = SvelteOnRails::Installer::Vite
|
41
|
+
vite_i.install_vite
|
42
|
+
|
43
|
+
# turbo
|
44
|
+
|
45
|
+
tr_pkg = '@hotwired/turbo-rails'
|
13
46
|
|
47
|
+
npm_i.install_or_update_package(tr_pkg)
|
48
|
+
|
49
|
+
js_i = SvelteOnRails::Installer::Javascript
|
50
|
+
js_i.append_import_statement(application_js_path, tr_pkg, "import '#{tr_pkg}';")
|
51
|
+
|
52
|
+
# svelte
|
53
|
+
|
54
|
+
svelte_i = SvelteOnRails::Installer::Svelte
|
55
|
+
svelte_i.install_svelte
|
56
|
+
|
57
|
+
# Hello World
|
58
|
+
|
59
|
+
puts '-' * 80
|
60
|
+
hello_world_path = nil
|
61
|
+
if utils.ask_yn('Do you want to install the Hello World component?')
|
62
|
+
hw_i = SvelteOnRails::Installer::HelloWorld
|
63
|
+
hello_world_path = hw_i.install_hello_world
|
64
|
+
end
|
65
|
+
|
66
|
+
# finish
|
67
|
+
|
68
|
+
puts '-' * 80
|
69
|
+
puts 'FINISHED SVELTE INSTALLATION'
|
70
|
+
puts '-' * 80
|
71
|
+
|
72
|
+
puts "SvelteOnRails installed successfully!"
|
73
|
+
puts "Restart the server and check if it all works."
|
74
|
+
if hello_world_path
|
75
|
+
puts "You can now see the Hello World component on: #{hello_world_path}."
|
76
|
+
end
|
77
|
+
puts "Happy coding!"
|
78
|
+
#exit
|
14
79
|
end
|
15
80
|
|
16
|
-
desc "Installs SvelteOnRails
|
17
|
-
task :
|
81
|
+
desc "Installs SvelteOnRails YAML configuration into your Rails application"
|
82
|
+
task :install do
|
83
|
+
|
84
|
+
# svelte_on_rails
|
18
85
|
|
19
|
-
|
86
|
+
utils.write_templates(['config/svelte_on_rails.yml'])
|
87
|
+
npm_i.install_or_update_package('@csedl/svelte-on-rails')
|
20
88
|
|
21
|
-
|
89
|
+
end
|
22
90
|
|
91
|
+
desc "Removes the Hello World component"
|
92
|
+
task :remove_hello_world do
|
23
93
|
|
24
|
-
|
25
|
-
|
94
|
+
hw_i = SvelteOnRails::Installer::HelloWorld
|
95
|
+
hw_i.remove_hello_world
|
26
96
|
|
27
|
-
|
28
|
-
iu.create_folder(Rails.root.join("app", "frontend", "javascript", "components"))
|
29
|
-
iu.add_line_to_file(Rails.root.join("app", "frontend", "entrypoints", "application.js"), "import '../initializers/svelte.js';")
|
97
|
+
end
|
30
98
|
|
31
|
-
|
32
|
-
|
99
|
+
desc "Add the Hello World component"
|
100
|
+
task :add_hello_world do
|
33
101
|
|
34
|
-
puts ''
|
35
|
-
|
36
|
-
|
37
|
-
|
102
|
+
puts '-' * 80
|
103
|
+
if utils.ask_yn('Do you want to install the Hello World component?')
|
104
|
+
hw_i = SvelteOnRails::Installer::HelloWorld
|
105
|
+
hello_world_path = hw_i.install_hello_world
|
106
|
+
puts "You can now see the Hello World component on: #{hello_world_path}."
|
107
|
+
end
|
38
108
|
|
39
109
|
end
|
40
110
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: svelte-on-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Sedlmair
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -34,7 +34,19 @@ files:
|
|
34
34
|
- lib/svelte-on-rails.rb
|
35
35
|
- lib/svelte_on_rails/compile.js
|
36
36
|
- lib/svelte_on_rails/configuration.rb
|
37
|
-
- lib/svelte_on_rails/
|
37
|
+
- lib/svelte_on_rails/installer/gem_utils.rb
|
38
|
+
- lib/svelte_on_rails/installer/haml.rb
|
39
|
+
- lib/svelte_on_rails/installer/hello_world.rb
|
40
|
+
- lib/svelte_on_rails/installer/javascript.rb
|
41
|
+
- lib/svelte_on_rails/installer/npm.rb
|
42
|
+
- lib/svelte_on_rails/installer/rails_template/app/controllers/svelte_on_rails_hello_world_controller.rb
|
43
|
+
- lib/svelte_on_rails/installer/rails_template/app/frontend/initializers/svelte.js
|
44
|
+
- lib/svelte_on_rails/installer/rails_template/app/frontend/javascript/components/SvelteOnRailsHelloWorld.svelte
|
45
|
+
- lib/svelte_on_rails/installer/rails_template/app/views/svelte_on_rails_hello_world/index.haml
|
46
|
+
- lib/svelte_on_rails/installer/rails_template/config/svelte_on_rails.yml
|
47
|
+
- lib/svelte_on_rails/installer/svelte.rb
|
48
|
+
- lib/svelte_on_rails/installer/utils.rb
|
49
|
+
- lib/svelte_on_rails/installer/vite.rb
|
38
50
|
- lib/svelte_on_rails/node_modules/@ampproject/remapping/LICENSE
|
39
51
|
- lib/svelte_on_rails/node_modules/@ampproject/remapping/README.md
|
40
52
|
- lib/svelte_on_rails/node_modules/@ampproject/remapping/dist/remapping.mjs
|
@@ -1,170 +0,0 @@
|
|
1
|
-
module SvelteOnRails
|
2
|
-
|
3
|
-
module InstallerUtils
|
4
|
-
def self.install_npm_package
|
5
|
-
package_name = "@csedl/svelte-on-rails@latest"
|
6
|
-
puts "Installing #{package_name} via npm..."
|
7
|
-
|
8
|
-
if system("npm install #{package_name}")
|
9
|
-
puts "#{package_name} successfully installed."
|
10
|
-
else
|
11
|
-
abort "Failed to install #{package_name}. Please ensure npm is installed and try running 'npm install #{package_name}' manually."
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.install_turbo
|
16
|
-
|
17
|
-
pkg_js = Rails.root.join("package.json")
|
18
|
-
package_name = "@hotwired/turbo-rails"
|
19
|
-
file_content = File.exist?(pkg_js) ? File.read(pkg_js) : ""
|
20
|
-
|
21
|
-
if file_content.match?(/#{package_name}/)
|
22
|
-
puts "#{package_name} is already present in package.json, assuming that it is set up well and working."
|
23
|
-
else
|
24
|
-
puts "Installing #{package_name} via npm..."
|
25
|
-
if system("npm install #{package_name}")
|
26
|
-
puts "#{package_name} successfully installed."
|
27
|
-
add_line_to_file(Rails.root.join("app", "frontend", "entrypoints", "application.js"), "import '#{package_name}';")
|
28
|
-
else
|
29
|
-
abort "Failed to install #{package_name}. Please ensure npm is installed and try running 'npm install #{package_name}' manually."
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.create_folder(folder)
|
36
|
-
if Dir.exist?(folder)
|
37
|
-
puts "Folder already exists: #{folder}"
|
38
|
-
else
|
39
|
-
FileUtils.mkdir_p(folder)
|
40
|
-
puts "Created folder: #{folder}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.create_configuration_file
|
45
|
-
config_path = Rails.root.join("config", "svelte_on_rails.yml")
|
46
|
-
if File.exist?(config_path)
|
47
|
-
puts "Configuration file already exists at file://#{config_path}"
|
48
|
-
else
|
49
|
-
File.write(config_path, <<~YAML)
|
50
|
-
|
51
|
-
frontend_folder: "app/frontend"
|
52
|
-
# the entrypoint that is your web root, example for vite: where @ points to
|
53
|
-
# relative to Rails.root
|
54
|
-
|
55
|
-
components_folder: "javascript/components"
|
56
|
-
# relative to frontend_folder
|
57
|
-
# where your svelte components are located
|
58
|
-
|
59
|
-
ssr: :auto
|
60
|
-
# options: true, false, :auto
|
61
|
-
# :auto: render server side if request is initial request (works only with turbo, because it checks for the X-Turbo-Request-ID header)
|
62
|
-
# when not server-side rendered the components must be built as custom elements, see node-package @csedl/svelte-on-rails
|
63
|
-
|
64
|
-
development:
|
65
|
-
watch_changes: true
|
66
|
-
# Check on every request if any file within the svelte components folder have changed, for recompiling
|
67
|
-
# Case sensitive path checking, even the file system is case insensitive
|
68
|
-
# Make sure this ist set to tue for development and test, but not for production
|
69
|
-
|
70
|
-
test:
|
71
|
-
watch_changes: true
|
72
|
-
|
73
|
-
production:
|
74
|
-
YAML
|
75
|
-
puts "Created configuration file at file://#{config_path}"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.add_line_to_file(file_path, line)
|
80
|
-
file_content = File.exist?(file_path) ? File.read(file_path) : ""
|
81
|
-
|
82
|
-
if file_content.match?(/#{line}/)
|
83
|
-
puts "#{line} already present in #{file_path}, nothing changed here."
|
84
|
-
return
|
85
|
-
end
|
86
|
-
|
87
|
-
File.open(file_path, 'a') do |file|
|
88
|
-
file.puts(line)
|
89
|
-
end
|
90
|
-
puts "added #{line} to #{file_path}."
|
91
|
-
rescue StandardError => e
|
92
|
-
puts "Error: #{e.message}"
|
93
|
-
end
|
94
|
-
|
95
|
-
def self.create_file(file_path)
|
96
|
-
|
97
|
-
unless File.exist?(file_path)
|
98
|
-
FileUtils.touch(file_path)
|
99
|
-
puts "Created empty file at file://#{file_path}"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
def self.create_javascript_initializer
|
105
|
-
config_path = Rails.root.join("app", "frontend", "initializers", "svelte.js")
|
106
|
-
if File.exist?(config_path)
|
107
|
-
puts "Initializer already exists: file://#{config_path}"
|
108
|
-
else
|
109
|
-
File.write(config_path, <<~JAVASCRIPT)
|
110
|
-
|
111
|
-
import { initializeSvelteComponents, cleanupSvelteComponents } from '@csedl/svelte-on-rails';
|
112
|
-
|
113
|
-
const components = import.meta.glob('/javascript/components/**/*.svelte', { eager: true });
|
114
|
-
const componentsRoot = '/javascript/components';
|
115
|
-
|
116
|
-
// Initialize Svelte components
|
117
|
-
initializeSvelteComponents(componentsRoot, components, true);
|
118
|
-
|
119
|
-
// Turbo event listener for page load
|
120
|
-
document.addEventListener('turbo:load', () => {
|
121
|
-
initializeSvelteComponents(componentsRoot, components, true);
|
122
|
-
});
|
123
|
-
|
124
|
-
// Turbo event listener for cleanup before page cache
|
125
|
-
document.addEventListener('turbo:before-cache', () => {
|
126
|
-
cleanupSvelteComponents(false);
|
127
|
-
});
|
128
|
-
JAVASCRIPT
|
129
|
-
puts "Created initializer file at file://#{config_path}"
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.create_svelte_hello_world
|
134
|
-
file_path = Rails.root.join("app", "frontend", "javascript", "components", "HelloWorld.svelte")
|
135
|
-
if File.exist?(file_path)
|
136
|
-
puts "Hello World file already exists: file://#{file_path}"
|
137
|
-
else
|
138
|
-
File.write(file_path, <<~HTML)
|
139
|
-
<script>
|
140
|
-
export let items
|
141
|
-
let count = 0;
|
142
|
-
|
143
|
-
function increment() {
|
144
|
-
count += 1;
|
145
|
-
}
|
146
|
-
</script>
|
147
|
-
|
148
|
-
<h1>Greetings from svelte</h1>
|
149
|
-
|
150
|
-
<button on:click={increment}>Increment: {count}</button>
|
151
|
-
<ul>
|
152
|
-
{#each items as item}
|
153
|
-
<li>{item}</li>
|
154
|
-
{/each}
|
155
|
-
</ul>
|
156
|
-
|
157
|
-
<style>
|
158
|
-
button {
|
159
|
-
background-color: darkred;
|
160
|
-
color: white;
|
161
|
-
padding: 10px;
|
162
|
-
border: none;
|
163
|
-
}
|
164
|
-
</style>
|
165
|
-
HTML
|
166
|
-
puts "Hello World file at file://#{file_path}"
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|