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.
- checksums.yaml +4 -4
- data/README.md +15 -50
- data/lib/generators/showcase_generator.rb +128 -0
- data/lib/generators/svelte_on_rails/install/install_generator.rb +1 -111
- data/lib/generators/svelte_on_rails/update/update_generator.rb +21 -0
- data/lib/svelte-on-rails.rb +2 -1
- data/lib/svelte_on_rails/installer/hello_world.rb +7 -26
- data/lib/svelte_on_rails/installer/utils.rb +8 -15
- data/lib/svelte_on_rails/lib/development_utils.rb +0 -29
- data/lib/svelte_on_rails/lib/utils.rb +6 -0
- data/lib/svelte_on_rails/lib/view_helper_support.rb +2 -0
- data/lib/svelte_on_rails/renderer/render-backup.js +26 -0
- data/lib/svelte_on_rails/renderer/render.js +61 -13
- data/lib/svelte_on_rails/renderer/renderer.rb +7 -4
- data/lib/svelte_on_rails/renderer/utils.js +40 -40
- data/lib/tasks/svelte_on_rails_tasks.rake +13 -51
- data/templates/config_base/config/svelte_on_rails.yml +1 -1
- data/templates/config_base/vite-ssr.config.ts +8 -3
- data/templates/showcase/app/channels/application_cable/channel.rb +4 -0
- data/templates/showcase/app/channels/application_cable/connection.rb +5 -0
- data/templates/showcase/app/controllers/svelte_on_rails_showcase_controller.rb +65 -0
- data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/JavascriptImport.svelte +7 -0
- data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/JpgImport.svelte +15 -0
- data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/ParentWithChild.svelte +1 -1
- data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/PngImport.svelte +16 -0
- data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/ReceiveFromChannel.svelte +5 -3
- data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/SvelteOnRailsHelloWorld.svelte +4 -4
- data/templates/showcase/app/frontend/javascript/svelte_on_rails_showcase/SvgRawImport.svelte +7 -0
- data/templates/showcase/app/views/svelte_on_rails_showcase/_nav.html.erb +13 -0
- data/templates/showcase/app/views/svelte_on_rails_showcase/backend_frontend_rendered.html.erb +37 -0
- data/templates/showcase/app/views/svelte_on_rails_showcase/index.html.erb +9 -0
- 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
- 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
- metadata +28 -24
- data/lib/svelte_on_rails/installer/vite.rb +0 -95
- data/templates/all_features_test/app/controllers/svelte_on_rails_hello_world_controller.rb +0 -62
- data/templates/all_features_test/app/frontend/javascript/components/JavascriptImport.svelte +0 -7
- data/templates/all_features_test/app/frontend/javascript/components/JpgImport.svelte +0 -7
- data/templates/all_features_test/app/frontend/javascript/components/PngImport.svelte +0 -7
- data/templates/all_features_test/app/frontend/javascript/components/SvgRawImport.svelte +0 -7
- data/templates/all_features_test/app/views/svelte_on_rails_hello_world/_nav.html.erb +0 -13
- data/templates/all_features_test/app/views/svelte_on_rails_hello_world/backend_frontend_rendered.html.erb +0 -37
- data/templates/all_features_test/app/views/svelte_on_rails_hello_world/index.html.erb +0 -9
- /data/templates/{all_features_test → showcase}/app/channels/svelte_on_rails_channel.rb +0 -0
- /data/templates/{all_features_test → showcase}/app/frontend/initializers/actionCable.js +0 -0
- /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
- /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
- /data/templates/{all_features_test/app/frontend/javascript → showcase/app/frontend/javascript/svelte_on_rails_showcase}/nestedJavascript.js +0 -0
- /data/templates/{all_features_test/app/frontend/javascript → showcase/app/frontend/javascript/svelte_on_rails_showcase}/nestedJavascriptToggled.js +0 -0
- /data/templates/{all_features_test/app/frontend/javascript/components → showcase/app/frontend/javascript/svelte_on_rails_showcase}/sub/NestedComponent.svelte +0 -0
- /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
- /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
|
-
|
|
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
|
-
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {dirname, resolve} from 'node:path';
|
|
7
|
+
const compiledComponentPath = process.argv[2];
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
import { render } from 'svelte/server';
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
console.log(`[svelte-on-rails:debug] component
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function readPropsFromStdin() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
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
|
-
//
|
|
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,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
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
function callChannelAction(action) {
|
|
8
8
|
results = []
|
|
9
|
-
axios.get(`/
|
|
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>
|
|
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
|
|
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 '
|
|
2
|
+
import jpg from './switzerland.jpg'
|
|
3
3
|
import Nested from './sub/NestedComponent.svelte'
|
|
4
|
-
import {nestedJavascriptFunction} from '
|
|
5
|
-
|
|
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,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>
|
|
@@ -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
|
|
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
|
|