@collagejs/svelte 0.1.0 → 0.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 +30 -2
- package/dist/Piece/Piece.svelte +154 -154
- package/dist/Piece/Piece.svelte.d.ts +3 -3
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ This is the official Svelte component library for *CollageJS* used to:
|
|
|
9
9
|
1. Create *CollageJS* `CorePiece` objects out of Svelte components
|
|
10
10
|
2. Consume `CorePiece` objects (made with any framework or library) in Svelte v5 projects
|
|
11
11
|
|
|
12
|
-
## Creating Svelte-
|
|
12
|
+
## Creating Svelte-Powered `CorePiece` Objects
|
|
13
13
|
|
|
14
14
|
Whenever we are creating a micro-frontend in Svelte v5 and wish for it to be used with *CollageJS*, we must create a `CorePiece` wrapper object for the Svelte component that is the root of our micro-frontend. Unless we wanted to take on this task ourselves, we use this package's `buildPiece()` function:
|
|
15
15
|
|
|
@@ -18,12 +18,23 @@ Whenever we are creating a micro-frontend in Svelte v5 and wish for it to be use
|
|
|
18
18
|
import { buildPiece } from "@collagejs/svelte";
|
|
19
19
|
// The component to wrap. It usually is App.svelte.
|
|
20
20
|
import App from "./App.svelte";
|
|
21
|
+
// Automatic CSS mounting and unmounting algorithm:
|
|
22
|
+
import { cssMountFactory } from "@collagejs/vite-css/ex";
|
|
23
|
+
|
|
24
|
+
// Only one cssMount per file is needed, regardless of the number of factory functions.
|
|
25
|
+
const cssMount = cssMountFactory('mfe' /*, { options } */);
|
|
21
26
|
|
|
22
27
|
export function myMfeFactory() {
|
|
23
|
-
|
|
28
|
+
const piece = buildPiece(App /*, { options } */);
|
|
29
|
+
export {
|
|
30
|
+
mount: [cssMount, piece.mount],
|
|
31
|
+
update: piece.update
|
|
32
|
+
}
|
|
24
33
|
}
|
|
25
34
|
```
|
|
26
35
|
|
|
36
|
+
It is also customary to install [@collagejs/vite-css](https://github.com/collagejs/vite-css) in our piece-exporting projects to be able to mount the bundled CSS files that Vite produces. The CSS-mounting function features FOUC prevention, but it only works if `cssMount` is listed in the array before `piece.mount`. Remember this!
|
|
37
|
+
|
|
27
38
|
> ✨ **Tip**: Repeat this process in the same or different file for any number of Svelte components that you wish to make available as independent micro-frontends. The sky is the limit.
|
|
28
39
|
|
|
29
40
|
## Consuming `CorePiece` Objects
|
|
@@ -42,3 +53,20 @@ We can mount *CollageJS* pieces created in any technology in Svelte projects by
|
|
|
42
53
|
1. We must use the `piece()` function to pass the `CorePiece` object.
|
|
43
54
|
2. The example uses the name of the factory function in the previous example, so we're mounting a Svelte MFE inside a Svelte project.
|
|
44
55
|
3. The `"@my/bare-module-specifier"` module name is the bare module specifier we assign to the micro-frontend in our root project's import map.
|
|
56
|
+
|
|
57
|
+
### Intellisense On The `CorePiece` Props
|
|
58
|
+
|
|
59
|
+
Your IDE can provide Intellisense on the properties the `CorePiece` given to `<Piece>` supports if the return value of the factory function is properly typed.
|
|
60
|
+
|
|
61
|
+
You can go several routes to type the factory functions. One of these is to create a `.d.ts` file and declare the ambient module:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import "@collagejs/core";
|
|
65
|
+
|
|
66
|
+
declare module "@my/bare-module-identifier" {
|
|
67
|
+
function myMfeFactory(): CorePiece<{ extra: string; data: boolean; }>;
|
|
68
|
+
// --------------------------------^ <-- Properties type
|
|
69
|
+
// Etc. Other factory functions for this module.
|
|
70
|
+
...
|
|
71
|
+
}
|
|
72
|
+
```
|
package/dist/Piece/Piece.svelte
CHANGED
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
<script module lang="ts">
|
|
2
|
-
const piecePropsSymbol = Symbol();
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Defines the special properties accepted by the `Piece` component. This type is to be used in conjunction with
|
|
6
|
-
* the `piece()` helper function to create the special property required by the `Piece` component.
|
|
7
|
-
*/
|
|
8
|
-
export type PieceProps<
|
|
9
|
-
TProps extends Record<string, any> = Record<string, any>,
|
|
10
|
-
> = {
|
|
11
|
-
/**
|
|
12
|
-
* The special property that contains the `CorePiece` instance to render, along with optional container
|
|
13
|
-
* properties.
|
|
14
|
-
*/
|
|
15
|
-
[piecePropsSymbol]: {
|
|
16
|
-
/**
|
|
17
|
-
* The `CorePiece` instance to render.
|
|
18
|
-
*/
|
|
19
|
-
piece: CorePiece<TProps
|
|
20
|
-
/**
|
|
21
|
-
* Optional HTML attributes to set on the container element that wraps the piece.
|
|
22
|
-
*/
|
|
23
|
-
containerProps?: HTMLAttributes<HTMLDivElement>;
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Helper function to create the special property required by the `Piece` component. The result of this function
|
|
29
|
-
* is to be spread into the props of the `Piece` component.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```svelte
|
|
33
|
-
* <Piece {...piece(myPiece, { onfocusin: focusInHandler })} foo="bar" count={42} />
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* @param piece The `CorePiece` instance to render.
|
|
37
|
-
* @param containerProps Optional HTML attributes to set on the container element that wraps the piece.
|
|
38
|
-
* @returns An object containing the special property to pass to the `Piece` component.
|
|
39
|
-
*/
|
|
40
|
-
export function piece<
|
|
41
|
-
TProps extends Record<string, any> = Record<string, any>,
|
|
42
|
-
>(
|
|
43
|
-
piece: CorePiece<TProps
|
|
44
|
-
containerProps?: HTMLAttributes<HTMLDivElement>,
|
|
45
|
-
) {
|
|
46
|
-
return {
|
|
47
|
-
[piecePropsSymbol]: {
|
|
48
|
-
piece,
|
|
49
|
-
containerProps,
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
</script>
|
|
54
|
-
|
|
55
|
-
<script
|
|
56
|
-
lang="ts"
|
|
57
|
-
generics="TProps extends Record<string, any> = Record<string, any>"
|
|
58
|
-
>
|
|
59
|
-
import { getCollageContext } from "../collageContext.js";
|
|
60
|
-
import {
|
|
61
|
-
mountPiece,
|
|
62
|
-
type CorePiece,
|
|
63
|
-
type MountedPiece,
|
|
64
|
-
type MountPiece,
|
|
65
|
-
} from "@collagejs/core";
|
|
66
|
-
import { onMount } from "svelte";
|
|
67
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
68
|
-
|
|
69
|
-
type Props = TProps & PieceProps<TProps>;
|
|
70
|
-
|
|
71
|
-
let { ...restProps }: Props = $props();
|
|
72
|
-
|
|
73
|
-
const { piece: corePiece, containerProps } = $derived(restProps[piecePropsSymbol]);
|
|
74
|
-
let containerEl: HTMLDivElement;
|
|
75
|
-
let firstRun = true;
|
|
76
|
-
const ctx = getCollageContext();
|
|
77
|
-
let mountedPiece: MountedPiece<TProps> | undefined;
|
|
78
|
-
|
|
79
|
-
onMount(() => {
|
|
80
|
-
const mountPieceFn =
|
|
81
|
-
(ctx?.mountPiece as MountPiece<TProps>) ?? mountPiece<TProps>;
|
|
82
|
-
const mountPromise = mountPieceFn(corePiece, containerEl, restProps).then((mp) => {
|
|
83
|
-
mountedPiece = mp;
|
|
84
|
-
});
|
|
85
|
-
return async () => {
|
|
86
|
-
await mountPromise;
|
|
87
|
-
await mountedPiece?.unmount();
|
|
88
|
-
mountedPiece = undefined;
|
|
89
|
-
};
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
$effect(() => {
|
|
93
|
-
// Must be the first line so the dependency on restProps is tracked.
|
|
94
|
-
const newProps = { ...restProps };
|
|
95
|
-
delete (newProps as any)[piecePropsSymbol];
|
|
96
|
-
if (firstRun) {
|
|
97
|
-
firstRun = false;
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
mountedPiece?.update(newProps);
|
|
101
|
-
});
|
|
102
|
-
</script>
|
|
103
|
-
|
|
104
|
-
<div bind:this={containerEl} {...containerProps}></div>
|
|
105
|
-
|
|
106
|
-
<style>
|
|
107
|
-
div {
|
|
108
|
-
display: contents;
|
|
109
|
-
}
|
|
110
|
-
</style>
|
|
111
|
-
<!--
|
|
112
|
-
@component
|
|
113
|
-
|
|
114
|
-
### Piece Component
|
|
115
|
-
|
|
116
|
-
Renders a CollageJS "piece" (micro-frontend) inside a Svelte application. The piece itself may be built using any
|
|
117
|
-
valid framework or library, as long as it adheres to the *CollageJS* `CorePiece` interface.
|
|
118
|
-
|
|
119
|
-
#### Props
|
|
120
|
-
|
|
121
|
-
Properties passed to the `Piece` component must include a special property created using the `piece()` helper
|
|
122
|
-
function. This property contains the `CorePiece` instance to render, along with optional container properties. One can
|
|
123
|
-
also pass additional properties that will be forwarded to the mounted piece.
|
|
124
|
-
|
|
125
|
-
If the mounted piece supports property updates, any changes to the additional properties will be propagated to the
|
|
126
|
-
piece reactively as per the rules of Svelte's reactivity system.
|
|
127
|
-
|
|
128
|
-
#### Example Usage
|
|
129
|
-
|
|
130
|
-
1. Import the `Piece` component and the `piece()` helper function from the library.
|
|
131
|
-
2. Import whatever you need to get a hold of your `CorePiece` instance. Normally, one imports a factory function that
|
|
132
|
-
creates the piece from a *bare module specifier* (an alias defined by your application's import map):
|
|
133
|
-
```typescript
|
|
134
|
-
import Piece, { piece } from '@collagejs/svelte';
|
|
135
|
-
import { myPieceFactory } from '@my/bare-module-specifier';
|
|
136
|
-
```
|
|
137
|
-
3. Create a `CorePiece` instance using your factory function. Pass whatever arguments the factory function requires.
|
|
138
|
-
4. Render the `Piece` component in your Svelte template, passing the `CorePiece` instance using the `piece()` helper
|
|
139
|
-
function. Also pass any additional properties that the piece supports:
|
|
140
|
-
|
|
141
|
-
```svelte
|
|
142
|
-
<Piece {...piece(myPieceFactory(), { class: 'my-piece-container' })} foo="bar" count={42} />
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
The above sets the `my-piece-container` CSS class on the container element that wraps the piece, and also passes the
|
|
146
|
-
`foo` and `count` properties to the mounted piece. This example uses constant values in the properties, but you can
|
|
147
|
-
also pass stateful values that can update reactively, as if it were a regular Svelte component.
|
|
148
|
-
|
|
149
|
-
> ⚠️ **IMPORTANT**: Once a piece has unmounted, it cannot be remounted. You must create a new `CorePiece` instance
|
|
150
|
-
> and `<Piece>` instance. This is by design. The easiest is to have the call to the factory function inside the
|
|
151
|
-
> Svelte template, so that a new `CorePiece` instance is created each time a new `<Piece>` instance is created.
|
|
152
|
-
|
|
153
|
-
Online Documentation: Pending (https://collagejs.dev)
|
|
154
|
-
-->
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
const piecePropsSymbol = Symbol();
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Defines the special properties accepted by the `Piece` component. This type is to be used in conjunction with
|
|
6
|
+
* the `piece()` helper function to create the special property required by the `Piece` component.
|
|
7
|
+
*/
|
|
8
|
+
export type PieceProps<
|
|
9
|
+
TProps extends Record<string, any> = Record<string, any>,
|
|
10
|
+
> = {
|
|
11
|
+
/**
|
|
12
|
+
* The special property that contains the `CorePiece` instance to render, along with optional container
|
|
13
|
+
* properties.
|
|
14
|
+
*/
|
|
15
|
+
[piecePropsSymbol]: {
|
|
16
|
+
/**
|
|
17
|
+
* The `CorePiece` instance to render.
|
|
18
|
+
*/
|
|
19
|
+
piece: CorePiece<TProps> | Promise<CorePiece<TProps>>;
|
|
20
|
+
/**
|
|
21
|
+
* Optional HTML attributes to set on the container element that wraps the piece.
|
|
22
|
+
*/
|
|
23
|
+
containerProps?: HTMLAttributes<HTMLDivElement>;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Helper function to create the special property required by the `Piece` component. The result of this function
|
|
29
|
+
* is to be spread into the props of the `Piece` component.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```svelte
|
|
33
|
+
* <Piece {...piece(myPiece, { onfocusin: focusInHandler })} foo="bar" count={42} />
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @param piece The `CorePiece` instance to render.
|
|
37
|
+
* @param containerProps Optional HTML attributes to set on the container element that wraps the piece.
|
|
38
|
+
* @returns An object containing the special property to pass to the `Piece` component.
|
|
39
|
+
*/
|
|
40
|
+
export function piece<
|
|
41
|
+
TProps extends Record<string, any> = Record<string, any>,
|
|
42
|
+
>(
|
|
43
|
+
piece: CorePiece<TProps> | Promise<CorePiece<TProps>>,
|
|
44
|
+
containerProps?: HTMLAttributes<HTMLDivElement>,
|
|
45
|
+
) {
|
|
46
|
+
return {
|
|
47
|
+
[piecePropsSymbol]: {
|
|
48
|
+
piece,
|
|
49
|
+
containerProps,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<script
|
|
56
|
+
lang="ts"
|
|
57
|
+
generics="TProps extends Record<string, any> = Record<string, any>"
|
|
58
|
+
>
|
|
59
|
+
import { getCollageContext } from "../collageContext.js";
|
|
60
|
+
import {
|
|
61
|
+
mountPiece,
|
|
62
|
+
type CorePiece,
|
|
63
|
+
type MountedPiece,
|
|
64
|
+
type MountPiece,
|
|
65
|
+
} from "@collagejs/core";
|
|
66
|
+
import { onMount } from "svelte";
|
|
67
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
68
|
+
|
|
69
|
+
type Props = TProps & PieceProps<TProps>;
|
|
70
|
+
|
|
71
|
+
let { ...restProps }: Props = $props();
|
|
72
|
+
|
|
73
|
+
const { piece: corePiece, containerProps } = $derived(restProps[piecePropsSymbol]);
|
|
74
|
+
let containerEl: HTMLDivElement;
|
|
75
|
+
let firstRun = true;
|
|
76
|
+
const ctx = getCollageContext();
|
|
77
|
+
let mountedPiece: MountedPiece<TProps> | undefined;
|
|
78
|
+
|
|
79
|
+
onMount(() => {
|
|
80
|
+
const mountPieceFn =
|
|
81
|
+
(ctx?.mountPiece as MountPiece<TProps>) ?? mountPiece<TProps>;
|
|
82
|
+
const mountPromise = mountPieceFn(corePiece, containerEl, restProps).then((mp) => {
|
|
83
|
+
mountedPiece = mp;
|
|
84
|
+
});
|
|
85
|
+
return async () => {
|
|
86
|
+
await mountPromise;
|
|
87
|
+
await mountedPiece?.unmount();
|
|
88
|
+
mountedPiece = undefined;
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
$effect(() => {
|
|
93
|
+
// Must be the first line so the dependency on restProps is tracked.
|
|
94
|
+
const newProps = { ...restProps };
|
|
95
|
+
delete (newProps as any)[piecePropsSymbol];
|
|
96
|
+
if (firstRun) {
|
|
97
|
+
firstRun = false;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
mountedPiece?.update(newProps);
|
|
101
|
+
});
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<div bind:this={containerEl} {...containerProps}></div>
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
div {
|
|
108
|
+
display: contents;
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
111
|
+
<!--
|
|
112
|
+
@component
|
|
113
|
+
|
|
114
|
+
### Piece Component
|
|
115
|
+
|
|
116
|
+
Renders a CollageJS "piece" (micro-frontend) inside a Svelte application. The piece itself may be built using any
|
|
117
|
+
valid framework or library, as long as it adheres to the *CollageJS* `CorePiece` interface.
|
|
118
|
+
|
|
119
|
+
#### Props
|
|
120
|
+
|
|
121
|
+
Properties passed to the `Piece` component must include a special property created using the `piece()` helper
|
|
122
|
+
function. This property contains the `CorePiece` instance to render, along with optional container properties. One can
|
|
123
|
+
also pass additional properties that will be forwarded to the mounted piece.
|
|
124
|
+
|
|
125
|
+
If the mounted piece supports property updates, any changes to the additional properties will be propagated to the
|
|
126
|
+
piece reactively as per the rules of Svelte's reactivity system.
|
|
127
|
+
|
|
128
|
+
#### Example Usage
|
|
129
|
+
|
|
130
|
+
1. Import the `Piece` component and the `piece()` helper function from the library.
|
|
131
|
+
2. Import whatever you need to get a hold of your `CorePiece` instance. Normally, one imports a factory function that
|
|
132
|
+
creates the piece from a *bare module specifier* (an alias defined by your application's import map):
|
|
133
|
+
```typescript
|
|
134
|
+
import Piece, { piece } from '@collagejs/svelte';
|
|
135
|
+
import { myPieceFactory } from '@my/bare-module-specifier';
|
|
136
|
+
```
|
|
137
|
+
3. Create a `CorePiece` instance using your factory function. Pass whatever arguments the factory function requires.
|
|
138
|
+
4. Render the `Piece` component in your Svelte template, passing the `CorePiece` instance using the `piece()` helper
|
|
139
|
+
function. Also pass any additional properties that the piece supports:
|
|
140
|
+
|
|
141
|
+
```svelte
|
|
142
|
+
<Piece {...piece(myPieceFactory(), { class: 'my-piece-container' })} foo="bar" count={42} />
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The above sets the `my-piece-container` CSS class on the container element that wraps the piece, and also passes the
|
|
146
|
+
`foo` and `count` properties to the mounted piece. This example uses constant values in the properties, but you can
|
|
147
|
+
also pass stateful values that can update reactively, as if it were a regular Svelte component.
|
|
148
|
+
|
|
149
|
+
> ⚠️ **IMPORTANT**: Once a piece has unmounted, it cannot be remounted. You must create a new `CorePiece` instance
|
|
150
|
+
> and `<Piece>` instance. This is by design. The easiest is to have the call to the factory function inside the
|
|
151
|
+
> Svelte template, so that a new `CorePiece` instance is created each time a new `<Piece>` instance is created.
|
|
152
|
+
|
|
153
|
+
Online Documentation: Pending (https://collagejs.dev)
|
|
154
|
+
-->
|
|
@@ -12,7 +12,7 @@ export type PieceProps<TProps extends Record<string, any> = Record<string, any>>
|
|
|
12
12
|
/**
|
|
13
13
|
* The `CorePiece` instance to render.
|
|
14
14
|
*/
|
|
15
|
-
piece: CorePiece<TProps
|
|
15
|
+
piece: CorePiece<TProps> | Promise<CorePiece<TProps>>;
|
|
16
16
|
/**
|
|
17
17
|
* Optional HTML attributes to set on the container element that wraps the piece.
|
|
18
18
|
*/
|
|
@@ -32,9 +32,9 @@ export type PieceProps<TProps extends Record<string, any> = Record<string, any>>
|
|
|
32
32
|
* @param containerProps Optional HTML attributes to set on the container element that wraps the piece.
|
|
33
33
|
* @returns An object containing the special property to pass to the `Piece` component.
|
|
34
34
|
*/
|
|
35
|
-
export declare function piece<TProps extends Record<string, any> = Record<string, any>>(piece: CorePiece<TProps
|
|
35
|
+
export declare function piece<TProps extends Record<string, any> = Record<string, any>>(piece: CorePiece<TProps> | Promise<CorePiece<TProps>>, containerProps?: HTMLAttributes<HTMLDivElement>): {
|
|
36
36
|
[piecePropsSymbol]: {
|
|
37
|
-
piece: CorePiece<TProps
|
|
37
|
+
piece: CorePiece<TProps> | Promise<CorePiece<TProps>>;
|
|
38
38
|
containerProps: HTMLAttributes<HTMLDivElement> | undefined;
|
|
39
39
|
};
|
|
40
40
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@collagejs/svelte",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Svelte v5 integration for the CollageJS micro-frontend library",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "José Pablo Ramírez Vargas",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
26
26
|
"test:unit": "vitest",
|
|
27
27
|
"test": "npm run test:unit -- --run",
|
|
28
|
+
"test:cicd": "npx playwright install && npm run test",
|
|
28
29
|
"test:e2e": "playwright test"
|
|
29
30
|
},
|
|
30
31
|
"files": [
|
|
@@ -46,8 +47,8 @@
|
|
|
46
47
|
}
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
|
-
"
|
|
50
|
-
"
|
|
50
|
+
"@collagejs/core": "^0.1.2",
|
|
51
|
+
"svelte": "^5.0.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@playwright/test": "^1.57.0",
|