@csedl/svelte-on-rails 12.0.2 → 12.1.1
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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/config.js +7 -7
- package/src/hydrate-build/initializeSvelteComponent.js +9 -10
- package/src/hydrate-build/svelte-on-rails-controller.js +16 -7
- package/src/logger.js +4 -4
- package/src/ssr/render.js +5 -5
- package/src/streams/componentStreamListener.js +1 -1
- package/src/streams/dispatch-event.js +1 -1
- package/src/utils.js +11 -5
- package/src/hydrate-build/cleanupSvelteComponent.js +0 -29
package/README.md
CHANGED
|
@@ -22,4 +22,4 @@ with the properties given by the ruby gem.
|
|
|
22
22
|
|
|
23
23
|
Please follow [svelte-on-rails docs](https://svelte-on-rails.dev) for more information.
|
|
24
24
|
|
|
25
|
-
The repository is shared with the gem [
|
|
25
|
+
The repository is shared with the gem [SOR](https://gitlab.com/sedl/svelte-on-rails) (monorepo).
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -17,7 +17,7 @@ export const SvelteOnRails = {
|
|
|
17
17
|
debugLog("lazyComponents not set: falling back to default «import.meta.glob(['/**/*.svelte'], {eager: false, import: 'default'})»");
|
|
18
18
|
components = _defaultComponents;
|
|
19
19
|
} else {
|
|
20
|
-
debugLog(`
|
|
20
|
+
debugLog(`using given lazyComponents`);
|
|
21
21
|
components = _lazyComponents
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -25,33 +25,33 @@ export const SvelteOnRails = {
|
|
|
25
25
|
const loader = components[componentKey];
|
|
26
26
|
|
|
27
27
|
if (!loader) {
|
|
28
|
-
throw new Error(`[
|
|
28
|
+
throw new Error(`[SOR] Component not found: «${componentKey}»\nAvailable imported Components are:\n\n+++\n • ${Object.keys(components).join('\n • ')}\n+++\n`);
|
|
29
29
|
//return;
|
|
30
30
|
} else {
|
|
31
|
-
debugLog(`
|
|
31
|
+
debugLog(`Component found: ${componentKey}`);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// load and validate component
|
|
35
35
|
|
|
36
36
|
let comp;
|
|
37
37
|
if (loader.prototype) {
|
|
38
|
-
console.warn(`[
|
|
38
|
+
console.warn(`[SOR] Components should be lazy loaded. Did you use vite.meta.glob(..., {eager: true})?`);
|
|
39
39
|
comp = loader;
|
|
40
40
|
} else {
|
|
41
41
|
comp = await loader();
|
|
42
42
|
if (typeof comp !== 'function') {
|
|
43
|
-
throw new Error(`[
|
|
43
|
+
throw new Error(`[SOR] Component is not a function: ${componentKey}\nYou may need to use vite.meta.glob(..., {...import: "default"})`);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// finish
|
|
48
48
|
|
|
49
|
-
debugLog(`
|
|
49
|
+
debugLog(`Component loaded:`, comp);
|
|
50
50
|
return comp;
|
|
51
51
|
},
|
|
52
52
|
|
|
53
53
|
set lazyComponents(value) {
|
|
54
|
-
debugLog(`
|
|
54
|
+
debugLog(`lazyComponents set:`, value);
|
|
55
55
|
_lazyComponents = value;
|
|
56
56
|
},
|
|
57
57
|
|
|
@@ -3,9 +3,6 @@ import {debugLog} from "../logger.js";
|
|
|
3
3
|
import {SvelteOnRails} from "../config.js";
|
|
4
4
|
import {componentRenderError} from "../utils.js";
|
|
5
5
|
|
|
6
|
-
// Store for tracking initialized Svelte component instances
|
|
7
|
-
const svelteInstances = new WeakMap();
|
|
8
|
-
|
|
9
6
|
export async function initializeSvelteComponent(element) {
|
|
10
7
|
|
|
11
8
|
// Decide mount vs hydrate
|
|
@@ -14,7 +11,7 @@ export async function initializeSvelteComponent(element) {
|
|
|
14
11
|
// fetch the component path
|
|
15
12
|
const componentKey = element.getAttribute("data-component")?.trim();
|
|
16
13
|
if (!componentKey) {
|
|
17
|
-
console.warn("[
|
|
14
|
+
console.warn("[SOR] Missing data-component attribute");
|
|
18
15
|
return;
|
|
19
16
|
}
|
|
20
17
|
|
|
@@ -31,7 +28,7 @@ export async function initializeSvelteComponent(element) {
|
|
|
31
28
|
try {
|
|
32
29
|
props = JSON.parse(propsString);
|
|
33
30
|
} catch (e) {
|
|
34
|
-
console.error(`[
|
|
31
|
+
console.error(`[SOR] Error parsing data-props for ${componentKey}:`, e);
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -45,13 +42,15 @@ export async function initializeSvelteComponent(element) {
|
|
|
45
42
|
instance = hydrate(Component, {target: element, props});
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
// Preparing for cleanup
|
|
49
|
-
svelteInstances.set(element, instance);
|
|
50
|
-
|
|
51
45
|
element.setAttribute("data-svelte-status", "initialized");
|
|
52
|
-
debugLog(`Success: ${action} ${componentKey}
|
|
46
|
+
debugLog(`Success: ${action} ${componentKey}`, instance);
|
|
47
|
+
return {
|
|
48
|
+
instance: instance,
|
|
49
|
+
status: "SUCCESS",
|
|
50
|
+
componentName: componentKey,
|
|
51
|
+
};
|
|
53
52
|
} catch (e) {
|
|
54
|
-
console.error(`[
|
|
53
|
+
console.error(`[SOR] Failed to ${action} ${componentKey}:`, e);
|
|
55
54
|
element.setAttribute("data-svelte-status", "error");
|
|
56
55
|
|
|
57
56
|
element.innerHTML = componentRenderError(componentKey, e);
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
import {Controller} from "@hotwired/stimulus"
|
|
2
2
|
import {initializeSvelteComponent} from "./initializeSvelteComponent.js";
|
|
3
|
-
import {
|
|
3
|
+
import {debugLog} from "../logger.js";
|
|
4
|
+
import {unmount} from "svelte";
|
|
4
5
|
|
|
5
6
|
export default class extends Controller {
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
svelteInstance = {};
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
connect() {
|
|
10
11
|
|
|
11
12
|
const stat = this.element.getAttribute('data-svelte-status');
|
|
12
|
-
if (stat === 'do-not-hydrate-
|
|
13
|
+
if (stat === 'do-not-hydrate-me') {
|
|
14
|
+
debugLog(`Skipping hydration of component ${this.element.getAttribute('data-component')}`);
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
;
|
|
13
18
|
|
|
14
|
-
initializeSvelteComponent(this.element, false).then(r => {
|
|
19
|
+
initializeSvelteComponent(this.element, false).then(r => {
|
|
20
|
+
this.svelteInstance = r
|
|
21
|
+
debugLog('HYDRATED', r)
|
|
22
|
+
});
|
|
15
23
|
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
disconnect() {
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
const name = this.svelteInstance.componentName.split('/').pop();
|
|
28
|
+
const r = unmount(this.svelteInstance.instance);
|
|
29
|
+
debugLog(`disconnected ${name} ${typeof this.svelteInstance.instance}`, r)
|
|
21
30
|
|
|
22
31
|
}
|
|
23
32
|
|
package/src/logger.js
CHANGED
|
@@ -11,14 +11,14 @@ export function streamDebugLog(message, object, object2) {
|
|
|
11
11
|
function log(namespace, message, object, object2) {
|
|
12
12
|
if (SvelteOnRails.debug) {
|
|
13
13
|
|
|
14
|
-
const nmsp = (namespace ?
|
|
14
|
+
const nmsp = (namespace ? ` ${namespace}:` : '');
|
|
15
15
|
|
|
16
16
|
if (object2) {
|
|
17
|
-
console.log(`[
|
|
17
|
+
console.log(`[SOR]${nmsp} ${message}`, object, object2);
|
|
18
18
|
} else if (object) {
|
|
19
|
-
console.log(`[
|
|
19
|
+
console.log(`[SOR]${nmsp} ${message}`, object);
|
|
20
20
|
} else {
|
|
21
|
-
console.log(`[
|
|
21
|
+
console.log(`[SOR]${nmsp} ${message}`);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
package/src/ssr/render.js
CHANGED
|
@@ -9,13 +9,13 @@ const compiledComponentPath = process.argv[2];
|
|
|
9
9
|
|
|
10
10
|
(async () => {
|
|
11
11
|
console.log(`${performance.now()}<time>`);
|
|
12
|
-
console.log(`[
|
|
12
|
+
console.log(`[SOR] awaiting load component => «${compiledComponentPath}»`);
|
|
13
13
|
const compiledComponent = await loadComponentModule(compiledComponentPath);
|
|
14
14
|
|
|
15
|
-
console.log(`[
|
|
15
|
+
console.log(`[SOR] Component loaded: «${compiledComponent}»`);
|
|
16
16
|
|
|
17
17
|
const props = await readPropsFromStdin();
|
|
18
|
-
console.log(`[
|
|
18
|
+
console.log(`[SOR] props read: «${JSON.stringify(props)}»`);
|
|
19
19
|
|
|
20
20
|
try {
|
|
21
21
|
const { body, head } = render(compiledComponent, { props });
|
|
@@ -26,7 +26,7 @@ const compiledComponentPath = process.argv[2];
|
|
|
26
26
|
head: head || '',
|
|
27
27
|
};
|
|
28
28
|
console.log(`<time>${performance.now()}`);
|
|
29
|
-
console.log('[
|
|
29
|
+
console.log('[SOR] successful json response: ' + JSON.stringify(res));
|
|
30
30
|
} catch (error) {
|
|
31
31
|
|
|
32
32
|
const res = {
|
|
@@ -36,7 +36,7 @@ const compiledComponentPath = process.argv[2];
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
console.log(`<time>${performance.now()}`);
|
|
39
|
-
console.log('[
|
|
39
|
+
console.log('[SOR] successful json response: ' + JSON.stringify(res));
|
|
40
40
|
}
|
|
41
41
|
})();
|
|
42
42
|
|
|
@@ -6,7 +6,7 @@ export function addComponentStreamListener(node, callback) {
|
|
|
6
6
|
const wrapper = node.closest('.svelte-component');
|
|
7
7
|
|
|
8
8
|
if (!wrapper) {
|
|
9
|
-
console.error('[
|
|
9
|
+
console.error('[SOR] No wrapping element with class .svelte-component found!');
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ export function dispatchSvelteStreamEvent(args) {
|
|
|
6
6
|
const argKeys = Object.keys(args);
|
|
7
7
|
const invalidKeys = argKeys.filter(key => !allowedKeys.includes(key));
|
|
8
8
|
if (invalidKeys.length > 0) {
|
|
9
|
-
throw new Error(`[
|
|
9
|
+
throw new Error(`[SOR] Invalid keys found: ${invalidKeys.join(', ')}. Allowed keys are: ${allowedKeys.join(', ')}.`);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
streamDebugLog(`parsed arguments:`, args)
|
package/src/utils.js
CHANGED
|
@@ -4,7 +4,8 @@ export function componentRenderError(component, error, ssr = false) {
|
|
|
4
4
|
const ssrHint = 'This is Server Side rendered. When Hydrated, you will see a more detailed error message.'
|
|
5
5
|
|
|
6
6
|
return (`
|
|
7
|
-
<div
|
|
7
|
+
<div class="svelte-on-rails-component-error${ssr ? '-server-side' : ''}"
|
|
8
|
+
style="
|
|
8
9
|
padding: 1.5rem;
|
|
9
10
|
margin: 1rem 0;
|
|
10
11
|
border: 2px solid #ef4444;
|
|
@@ -13,12 +14,17 @@ export function componentRenderError(component, error, ssr = false) {
|
|
|
13
14
|
border-radius: 0.5rem;
|
|
14
15
|
font-family: system-ui, sans-serif;
|
|
15
16
|
">
|
|
16
|
-
<strong style="font-size: 1.2em;">Component failed to render</strong>
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
<strong style="font-size: 1.2em;">Component failed to render${ssr ? ' server-side' : ''}</strong>
|
|
18
|
+
|
|
19
|
+
<p class="error-message"
|
|
20
|
+
style="margin: 0.4rem 0 0.4rem;"
|
|
21
|
+
>
|
|
19
22
|
${error.message || 'Unknown rendering error'}
|
|
20
23
|
</p>
|
|
21
|
-
|
|
24
|
+
<div style="display: block;">
|
|
25
|
+
<code style="margin: 0.75rem 0 0;">${component}</code><br>
|
|
26
|
+
</div>
|
|
27
|
+
<small style="color: #7f1d1d; opacity: 0.8; margin-top: 1rem; display: block;">
|
|
22
28
|
${ssr ? ssrHint : hint}
|
|
23
29
|
</small>
|
|
24
30
|
</div>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { unmount } from 'svelte';
|
|
2
|
-
import { debugLog } from "../logger.js";
|
|
3
|
-
|
|
4
|
-
// Store for tracking initialized Svelte component instances
|
|
5
|
-
const svelteInstances = new WeakMap();
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Cleans up all initialized Svelte component instances.
|
|
9
|
-
*/
|
|
10
|
-
export function cleanupSvelteComponent(element) {
|
|
11
|
-
try {
|
|
12
|
-
const instance = svelteInstances.get(element);
|
|
13
|
-
if (instance) {
|
|
14
|
-
unmount(instance).then(()=>{
|
|
15
|
-
debugLog(`Successfully unmounted Svelte component for element:`, element);
|
|
16
|
-
}); // Destroy the Svelte component instance in Svelte 5
|
|
17
|
-
debugLog(`Unmounted Svelte component for element:`, element);
|
|
18
|
-
element.removeAttribute('data-svelte-initialized'); // Reset initialized state
|
|
19
|
-
svelteInstances.delete(element); // Remove from WeakMap
|
|
20
|
-
} else {
|
|
21
|
-
let comps = document.getElementsByClassName('svelte-component')
|
|
22
|
-
debugLog(`Actual ${comps.length} components on the page. No Svelte instance found`, element);
|
|
23
|
-
}
|
|
24
|
-
} catch (e) {
|
|
25
|
-
console.error(`[svelte-on-rails:stream] Error unmounting Svelte component for element:`, e);
|
|
26
|
-
// Fallback: Clear element content to prevent stale content
|
|
27
|
-
element.innerHTML = '';
|
|
28
|
-
}
|
|
29
|
-
}
|