svelte-on-rails 8.1.0 → 9.1.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -50
  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/generators/svelte_on_rails/update/update_generator.rb +21 -0
  6. data/lib/svelte-on-rails.rb +2 -1
  7. data/lib/svelte_on_rails/installer/hello_world.rb +7 -26
  8. data/lib/svelte_on_rails/installer/utils.rb +8 -15
  9. data/lib/svelte_on_rails/lib/development_utils.rb +0 -29
  10. data/lib/svelte_on_rails/lib/utils.rb +6 -0
  11. data/lib/svelte_on_rails/lib/view_helper_support.rb +2 -0
  12. data/lib/svelte_on_rails/renderer/render-backup.js +26 -0
  13. data/lib/svelte_on_rails/renderer/render.js +61 -13
  14. data/lib/svelte_on_rails/renderer/renderer.rb +7 -4
  15. data/lib/svelte_on_rails/renderer/utils.js +40 -40
  16. data/lib/tasks/svelte_on_rails_tasks.rake +13 -51
  17. data/templates/config_base/config/svelte_on_rails.yml +1 -1
  18. data/templates/config_base/vite-ssr.config.ts +8 -3
  19. data/templates/showcase/app/channels/application_cable/channel.rb +4 -0
  20. data/templates/showcase/app/channels/application_cable/connection.rb +5 -0
  21. data/templates/showcase/app/controllers/svelte_on_rails_showcase_controller.rb +65 -0
  22. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/JavascriptImport.svelte +7 -0
  23. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/JpgImport.svelte +15 -0
  24. data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/ParentWithChild.svelte +1 -1
  25. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/PngImport.svelte +16 -0
  26. data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/ReceiveFromChannel.svelte +5 -3
  27. data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/SvelteOnRailsHelloWorld.svelte +4 -4
  28. data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/SvgRawImport.svelte +7 -0
  29. data/templates/showcase/app/views/svelte_on_rails_showcase/_nav.html.erb +13 -0
  30. data/templates/showcase/app/views/svelte_on_rails_showcase/backend_frontend_rendered.html.erb +37 -0
  31. data/templates/showcase/app/views/svelte_on_rails_showcase/index.html.erb +9 -0
  32. 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
  33. 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
  34. metadata +28 -24
  35. data/lib/svelte_on_rails/installer/vite.rb +0 -95
  36. data/templates/all_features_test/app/controllers/svelte_on_rails_hello_world_controller.rb +0 -62
  37. data/templates/all_features_test/app/frontend/javascript/components/JavascriptImport.svelte +0 -7
  38. data/templates/all_features_test/app/frontend/javascript/components/JpgImport.svelte +0 -7
  39. data/templates/all_features_test/app/frontend/javascript/components/PngImport.svelte +0 -7
  40. data/templates/all_features_test/app/frontend/javascript/components/SvgRawImport.svelte +0 -7
  41. data/templates/all_features_test/app/views/svelte_on_rails_hello_world/_nav.html.erb +0 -13
  42. data/templates/all_features_test/app/views/svelte_on_rails_hello_world/backend_frontend_rendered.html.erb +0 -37
  43. data/templates/all_features_test/app/views/svelte_on_rails_hello_world/index.html.erb +0 -9
  44. /data/templates/{all_features_test → showcase}/app/channels/svelte_on_rails_channel.rb +0 -0
  45. /data/templates/{all_features_test → showcase}/app/frontend/initializers/actionCable.js +0 -0
  46. /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
  47. /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
  48. /data/templates/{all_features_test/app/frontend/javascript → showcase/app/frontend/javascript/svelte_on_rails_showcase}/nestedJavascript.js +0 -0
  49. /data/templates/{all_features_test/app/frontend/javascript → showcase/app/frontend/javascript/svelte_on_rails_showcase}/nestedJavascriptToggled.js +0 -0
  50. /data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/sub/NestedComponent.svelte +0 -0
  51. /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
  52. /data/templates/{all_features_test/app/views/svelte_on_rails_hello_world → showcase/app/views/svelte_on_rails_showcase}/_styles.html.erb +0 -0
@@ -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
 
@@ -1,40 +1,40 @@
1
- import {fileURLToPath} from 'node:url';
2
- import {dirname, resolve} from 'node:path';
3
-
4
- export async function loadComponentModule(compiledFile) {
5
- // Get the directory of the current script
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = dirname(__filename);
8
-
9
- try {
10
- // Convert relative path to absolute path
11
- const absolutePath = resolve(__dirname, compiledFile);
12
-
13
- // Convert absolute path to a file URL
14
- const modulePath = `file://${absolutePath}`;
15
-
16
- // Import the module
17
- const module = await import(modulePath);
18
- return module.default;
19
- } catch (error) {
20
- console.error(`=> compiledFile: «${compiledFile}»`);
21
- console.error(`[loadComponentModule] Error loading component from ${compiledFile}:`, error);
22
- process.exit(1);
23
- }
24
- }
25
-
26
- export function readPropsFromStdin() {
27
- return new Promise((resolve, reject) => {
28
- let input = '';
29
- process.stdin.setEncoding('utf8');
30
- process.stdin.on('data', (chunk) => (input += chunk));
31
- process.stdin.on('end', () => {
32
- try {
33
- resolve(JSON.parse(input));
34
- } catch (error) {
35
- reject(new Error(`Error parsing JSON from STDIN: ${error.message}\nInput: «${input}»`));
36
- }
37
- });
38
- process.stdin.on('error', (error) => reject(new Error(`Error reading STDIN: ${error.message}`)));
39
- });
40
- }
1
+ // import {fileURLToPath} from 'node:url';
2
+ // import {dirname, resolve} from 'node:path';
3
+ //
4
+ // export async function loadComponentModule(compiledFile) {
5
+ // // Get the directory of the current script
6
+ // const __filename = fileURLToPath(import.meta.url);
7
+ // const __dirname = dirname(__filename);
8
+ //
9
+ // try {
10
+ // // Convert relative path to absolute path
11
+ // const absolutePath = resolve(__dirname, compiledFile);
12
+ //
13
+ // // Convert absolute path to a file URL
14
+ // const modulePath = `file://${absolutePath}`;
15
+ //
16
+ // // Import the module
17
+ // const module = await import(modulePath);
18
+ // return module.default;
19
+ // } catch (error) {
20
+ // console.error(`=> compiledFile: «${compiledFile}»`);
21
+ // console.error(`[loadComponentModule] Error loading component from ${compiledFile}:`, error);
22
+ // process.exit(1);
23
+ // }
24
+ // }
25
+ //
26
+ // export function readPropsFromStdin() {
27
+ // return new Promise((resolve, reject) => {
28
+ // let input = '';
29
+ // process.stdin.setEncoding('utf8');
30
+ // process.stdin.on('data', (chunk) => (input += chunk));
31
+ // process.stdin.on('end', () => {
32
+ // try {
33
+ // resolve(JSON.parse(input));
34
+ // } catch (error) {
35
+ // reject(new Error(`Error parsing JSON from STDIN: ${error.message}\nInput: «${input}»`));
36
+ // }
37
+ // });
38
+ // process.stdin.on('error', (error) => reject(new Error(`Error reading STDIN: ${error.message}`)));
39
+ // });
40
+ // }
@@ -6,57 +6,19 @@ if defined?(Rails) && Rake::Task.task_defined?("assets:precompile")
6
6
  end
7
7
  end
8
8
 
9
-
10
9
  require_relative '../../lib/svelte_on_rails/installer/hello_world'
11
10
  require_relative '../../lib/generators/svelte_on_rails/install/install_generator'
12
11
 
13
-
14
-
15
- namespace :svelte_on_rails do
16
-
17
- desc "Removes the Hello World component"
18
- task :remove_hello_world do
19
-
20
- hw_i = SvelteOnRails::Installer::HelloWorld
21
- hw_i.remove_hello_world(['all_features_test'])
22
-
23
- end
24
-
25
- desc "Add the Hello World component"
26
- task :add_hello_world do
27
-
28
- puts '-' * 80
29
- hw_i = SvelteOnRails::Installer::HelloWorld
30
- hello_world_path = hw_i.install_hello_world(['all_features_test'])
31
- puts "You can now see the Hello World component on: #{hello_world_path}."
32
-
33
- end
34
-
35
- desc "For contributors to this gem: writes a config file for developing options."
36
- task :create_contributor_configs_file do
37
- path = File.expand_path('../../../svelte_on_rails_contributor_configs.yml', __dir__)
38
-
39
- if File.exist?(path)
40
- puts "Config file for Contributors already exists: file://#{path}"
41
- puts 'nothing done.'
42
- exit
43
- end
44
-
45
- content = <<-END
46
- #local_npm_package_path: /path/to/my/local/csedl-svelte-on-rails-main
47
-
48
- # optional
49
- # If you want to develop the @csedl/svelte-on-rails package
50
- # add full path like /path/to/csedl-svelte-on-rails-main
51
- # Then, on running the generator, it installs this package from your local root folder
52
-
53
- generated_test_app_folder_path: /destination/folder/for/generated/test/app
54
-
55
- # required!
56
- # When you run tests, a rails app will be generated into this folder
57
- END
58
- File.write(path, content)
59
- puts "Config file for Contributors created at: #{path}"
60
- end
61
-
62
- end
12
+ # namespace :svelte_on_rails do
13
+ #
14
+ # desc "Add the Hello World component"
15
+ # task :add_hello_world do
16
+ #
17
+ # puts '-' * 80
18
+ # hw_i = SvelteOnRails::Installer::HelloWorld
19
+ # hello_world_path = hw_i.install_hello_world(['showcase'])
20
+ # puts "You can now see the Hello World component on: #{hello_world_path}."
21
+ #
22
+ # end
23
+ #
24
+ # end
@@ -2,7 +2,7 @@ frontend_folder: "app/frontend"
2
2
  # the entrypoint that is your web root, example for vite: where @ points to
3
3
  # relative to Rails.root
4
4
 
5
- components_folder: "javascript/components"
5
+ components_folder: "javascript"
6
6
  # relative to frontend_folder
7
7
  # where your svelte components are located
8
8
 
@@ -1,3 +1,5 @@
1
+ // vite-ssr.config.ts (updated for Svelte 5+ with runes: true)
2
+
1
3
  import { defineConfig } from 'vite';
2
4
  import RubyPlugin from 'vite-plugin-ruby';
3
5
  import { svelte } from '@sveltejs/vite-plugin-svelte';
@@ -62,11 +64,11 @@ function findSvelteFiles(dir: string, baseDir: string = dir): Record<string, str
62
64
  const svelteComponents = findSvelteFiles(path.resolve('app/frontend'));
63
65
 
64
66
  export default defineConfig(({ mode }) => {
65
-
66
67
  const isProduction = (process.env.RAILS_ENV === 'development' || process.env.RAILS_ENV === 'test' ? false : true);
67
68
 
68
69
  return {
69
70
  base: isProduction ? '/vite/' : '/vite-dev/',
71
+ publicDir: false,
70
72
  plugins: [
71
73
  rewriteAssetPathsPlugin(),
72
74
  {
@@ -85,7 +87,10 @@ export default defineConfig(({ mode }) => {
85
87
  svelte({
86
88
  include: ['app/frontend/**/*.svelte'],
87
89
  compilerOptions: {
88
- // hydratable: false,
90
+ // Enable runes mode for Svelte 5+ (explicit reactivity, signals)
91
+ runes: true,
92
+ // generate: 'server' is handled internally by the plugin for SSR builds
93
+ // hydratable: false, // Uncomment if you don't need client hydration
89
94
  },
90
95
  }),
91
96
  {
@@ -102,7 +107,7 @@ export default defineConfig(({ mode }) => {
102
107
  build: {
103
108
  ssr: true,
104
109
  outDir: 'public/vite-ssr',
105
- manifest: 'manifest.json',
110
+ manifest: 'manifest.json', // This will generate the SSR manifest in Svelte 5+/Vite
106
111
  rollupOptions: {
107
112
  input: {
108
113
  ...svelteComponents,
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ # You can add identified_by :current_user etc. later
4
+ end
5
+ end
@@ -0,0 +1,65 @@
1
+ class SvelteOnRailsShowcaseController < ApplicationController
2
+
3
+ def index
4
+ end
5
+
6
+ def web_socket_action
7
+
8
+ comp = 'svelte_on_rails_showcase/ReceiveFromChannel'
9
+
10
+ emojis = '🤣🌴🌍漢字😀😎😇🥰😎🥸🧐🤪🥸😤🥳🤢😻🤓👁️🥵🥶🫵🧑‍🎤🤖😹🤡😹🤠👩‍🦰🙇‍♀️'
11
+ emojis_rand = 5.times.map { emojis[rand(emojis.size)] }.join
12
+
13
+ case params['stream']
14
+
15
+ when 'action-cable-to-component'
16
+ SvelteOnRails::ActionCable.dispatch(
17
+ comp,
18
+ { message: "Sent by <span class='transfer'>ActionCable</span>: #{emojis_rand}", class: 'action-cable-to-component' },
19
+ event: 'stream-action'
20
+ )
21
+
22
+ when 'action-cable-to-element'
23
+ SvelteOnRails::ActionCable.dispatch(
24
+ comp,
25
+ { message: "Sent by <span class='transfer'>ActionCable to .my-custom-class / my-custom-event</span>: #{emojis_rand}", class: 'action-cable-to-element' },
26
+ selector: '.my-custom-class',
27
+ event: 'my-custom-event'
28
+ )
29
+
30
+ when 'action-cable-to-selector'
31
+ SvelteOnRails::ActionCable.dispatch_by_selector(
32
+ '.receive-by-selector',
33
+ { message: "Sent by <span class='transfer'>ActionCable/Selector</span>: #{emojis_rand}", class: 'action-cable-to-selector' }
34
+ )
35
+
36
+ when 'turbo-stream-to-all-components'
37
+ SvelteOnRails::TurboStream.dispatch(
38
+ nil,
39
+ { message: "Sent by <span class='transfer'>TurboStream</span>: #{emojis_rand}", class: 'turbo-stream-to-all-components' },
40
+ )
41
+
42
+ when 'turbo-stream-to-element'
43
+ SvelteOnRails::TurboStream.dispatch(
44
+ nil,
45
+ { message: "Sent by <span class='transfer'>TurboStream</span>: #{emojis_rand}", class: 'turbo-stream-to-element' },
46
+ selector: '.my-custom-class',
47
+ event: 'my-custom-event'
48
+ )
49
+
50
+ when 'turbo-stream-to-selector'
51
+ SvelteOnRails::TurboStream.dispatch_by_selector(
52
+ '.receive-by-selector',
53
+ { message: "Sent by <span class='transfer'>TurboStream/Selector</span>: #{emojis_rand}", class: 'turbo-stream-to-selector' }
54
+ )
55
+
56
+ else
57
+ raise 'Unknown stream'
58
+
59
+ end
60
+
61
+ render plain: "dispatched: #{params['stream']}"
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,7 @@
1
+ <script>
2
+ let {title} = $props();
3
+ import {nestedJavascriptFunction} from "./nestedJavascript.js";
4
+ </script>
5
+
6
+ <p>{title}</p>
7
+ <p>{nestedJavascriptFunction()}</p>
@@ -0,0 +1,15 @@
1
+ <script>
2
+ let {title} = $props();
3
+ import jpg from './switzerland.jpg'
4
+ </script>
5
+
6
+ <p>{title}</p>
7
+ <img alt="Jpg not loaded!" src="{jpg}" />
8
+
9
+ <style>
10
+ p {
11
+ background-color: blue;
12
+ color: white;
13
+ padding: 3px;
14
+ }
15
+ </style>
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import Nested from './sub/NestedComponent.svelte'
3
- export let title
3
+ let {title} = $props();
4
4
  </script>
5
5
  <p>{title}</p>
6
6
  <Nested />
@@ -0,0 +1,16 @@
1
+ <script>
2
+ let {title} = $props();
3
+ import png from './england.png'
4
+ </script>
5
+
6
+ <p>{title}</p>
7
+ <img alt="Png not loaded!" src="{png}" />
8
+
9
+
10
+ <style>
11
+ p {
12
+ background-color: red;
13
+ color: white;
14
+ padding: 3px;
15
+ }
16
+ </style>
@@ -6,7 +6,7 @@
6
6
 
7
7
  function callChannelAction(action) {
8
8
  results = []
9
- axios.get(`/svelte_on_rails_hello_world/web_socket_action?stream=${action}`)
9
+ axios.get(`/svelte_on_rails_showcase/web_socket_action?stream=${action}`)
10
10
  .then(function (response) {
11
11
  console.log(`server action called, status: ${response.status}`)
12
12
  })
@@ -43,7 +43,9 @@
43
43
 
44
44
  <h1 use:addComponentStreamListener={handleCableEvent}>Dispatch Actions from Server</h1>
45
45
 
46
- <p>Actions that are triggered from the server, by TurboStream or ActionCable</p>
46
+ <p>Please click a button this triggers server action server pushes update independently to Svelte (via Turbo/ActionCable).</p>
47
+ <p>You should see the random Emojis.</p>
48
+ <p>This Server-push could also come from timers/other server events, not tied to request-response.</p>
47
49
 
48
50
  <h3>ActionCable</h3>
49
51
  <p>Easier Technic, more basic</p>
@@ -60,7 +62,7 @@
60
62
  <span class="my-custom-class" onmy-custom-event="{handleElementEvent}"></span>
61
63
  <span class="receive-by-selector" onstream-action="{handleStreamSelectorEvent}"></span>
62
64
 
63
- <h3>Results</h3>
65
+ <h3>Results:</h3>
64
66
  <div class="results-box">
65
67
  <ul class="results">
66
68
  {#each results as result}
@@ -1,9 +1,9 @@
1
1
  <script>
2
- import jpg from '../../images/svelte-on-rails-hello-world-switzerland.jpg'
2
+ import jpg from './switzerland.jpg'
3
3
  import Nested from './sub/NestedComponent.svelte'
4
- import {nestedJavascriptFunction} from '../nestedJavascript.js'
5
- export let items
6
- let count = 0;
4
+ import {nestedJavascriptFunction} from './nestedJavascript.js'
5
+ let {items} = $props();
6
+ let count = $state(0);
7
7
 
8
8
  function increment() {
9
9
  count += 1;
@@ -0,0 +1,7 @@
1
+ <script>
2
+ let {title} = $props();
3
+ import svgRaw from './face-smile-wink.svg?raw'
4
+ </script>
5
+
6
+ <p>{title}</p>
7
+ {@html svgRaw}
@@ -0,0 +1,13 @@
1
+ <div class="nav">
2
+ <%= link_to 'Hello World', '/svelte_on_rails_showcase' %>
3
+ |
4
+ <%= link_to 'Backend/Frontend Test', '/svelte_on_rails_showcase/backend_frontend_rendered' %>
5
+ |
6
+ <%= link_to 'SSR-Auto rendered (default)', '/svelte_on_rails_showcase/ssr_auto_rendered' %>
7
+ |
8
+ <%= link_to 'Turbo Streams', '/svelte_on_rails_showcase/web_socket' %>
9
+ </div>
10
+
11
+ <% turbo_id = request.headers['X-Turbo-Request-ID'] %>
12
+ <p class="<%= (turbo_id.present? ? 'turbo-request' : 'initial-request') %>"><%= (turbo_id.blank? ? 'This is a initial request' : "Turbo-Request-ID: #{turbo_id}") %></p>
13
+ <p>Rails.environment: <%= Rails.env %></p>
@@ -0,0 +1,37 @@
1
+ <%= render 'styles' %>
2
+ <style>
3
+ .svelte-component {
4
+ border: 1px solid lightgray;
5
+ padding: 10px;
6
+ margin: 10px;
7
+ width: 100px;
8
+ display: inline-block;
9
+ }
10
+ </style>
11
+
12
+ <%= render 'nav' %>
13
+
14
+
15
+ <h1>Server-Side / Client side rendering test</h1>
16
+ <p>Server side rendered and Client side rendered components must look similar.</p>
17
+ <p>Otherwise SSR or client side rendering would not work as expected.</p>
18
+ <hr>
19
+
20
+ <% components = ['SvgRawImport', 'JpgImport', 'PngImport', 'JavascriptImport', 'ParentWithChild'] %>
21
+
22
+ <h3>Server side rendered</h3>
23
+ <p>Theese Elements will arrive stable like you know it on a classical backend rendered rails app.</p>
24
+ <div class="ssr-only">
25
+ <% components.each do |component| %>
26
+ <%= svelte_component("svelte_on_rails_showcase/#{component}", {title: component}, options: {ssr: true, hydrate: false}) %>
27
+ <% end %>
28
+ </div>
29
+
30
+ <hr>
31
+ <h3>Client side rendered</h3>
32
+ <p>Here you may see a unpleasant «blink» on the initial request or by clicking the reload button on the browser.</p>
33
+ <div class="client-only">
34
+ <% components.each do |component| %>
35
+ <%= svelte_component("svelte_on_rails_showcase/#{component}", {title: component}, options: {ssr: false, hydrate: true}) %>
36
+ <% end %>
37
+ </div>
@@ -0,0 +1,9 @@
1
+ <%= render 'styles' %>
2
+
3
+
4
+ <%= render 'nav' %>
5
+
6
+
7
+ <h1>Svelte is here</h1>
8
+
9
+ <%= svelte_component "svelte_on_rails_showcase/SvelteOnRailsHelloWorld", { items: ['attributes', 'are', 'parsed'] } %>
@@ -17,10 +17,10 @@
17
17
 
18
18
  <% components = ['SvgRawImport', 'JpgImport', 'PngImport', 'JavascriptImport', 'ParentWithChild'] %>
19
19
 
20
- <h3>Rendered server side only on initial request</h3>
20
+ <h3>Rendered server side only on initial request, then, on subsequent requests, rendered client side:</h3>
21
21
  <div class="ssr-auto">
22
22
  <% components.each do |component| %>
23
- <%= svelte_component(component, { title: component }) %>
23
+ <%= svelte_component("svelte_on_rails_showcase/#{component}", { title: component }) %>
24
24
  <% end %>
25
25
  </div>
26
26
 
@@ -6,7 +6,7 @@
6
6
  <%= render 'nav' %>
7
7
 
8
8
 
9
- <%= svelte_component "ReceiveFromChannel" %>
9
+ <%= svelte_component "svelte_on_rails_showcase/ReceiveFromChannel" %>
10
10
 
11
11
  <%= content_tag :div, id: 'svelte-on-rails-stream-actions-box' do %>
12
12
  <% end %>