@primate/svelte 0.13.2 → 0.15.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.
- package/package.json +4 -4
- package/src/module.js +130 -112
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Primate Svelte module",
|
|
5
5
|
"homepage": "https://primatejs.com/modules/svelte",
|
|
6
6
|
"bugs": "https://github.com/primatejs/primate/issues",
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"directory": "packages/svelte"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"runtime-compat": "^0.
|
|
20
|
-
"svelte": "^4.
|
|
19
|
+
"runtime-compat": "^0.24.1",
|
|
20
|
+
"svelte": "^4.1.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"primate": "0.
|
|
23
|
+
"primate": "0.21"
|
|
24
24
|
},
|
|
25
25
|
"type": "module",
|
|
26
26
|
"exports": "./src/exports.js"
|
package/src/module.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import crypto from "runtime-compat/crypto";
|
|
2
2
|
import {Path} from "runtime-compat/fs";
|
|
3
|
+
import {Response, Status, MediaType} from "runtime-compat/http";
|
|
3
4
|
import * as compiler from "svelte/compiler";
|
|
4
5
|
import {tryreturn} from "runtime-compat/async";
|
|
5
6
|
import errors from "./errors.js";
|
|
@@ -8,6 +9,7 @@ const endings = {
|
|
|
8
9
|
svelte: ".svelte",
|
|
9
10
|
js: ".svelte.js",
|
|
10
11
|
};
|
|
12
|
+
const rootname = "root";
|
|
11
13
|
|
|
12
14
|
const hash = async (string, algorithm = "sha-256") => {
|
|
13
15
|
const base = 16;
|
|
@@ -21,7 +23,6 @@ const hash = async (string, algorithm = "sha-256") => {
|
|
|
21
23
|
};
|
|
22
24
|
const normalize = async path => `_${await hash(path)}`;
|
|
23
25
|
|
|
24
|
-
const rootname = "root";
|
|
25
26
|
const filename = `${rootname}.js`;
|
|
26
27
|
|
|
27
28
|
const options = {
|
|
@@ -33,57 +34,84 @@ const type = "module";
|
|
|
33
34
|
|
|
34
35
|
const load = async path =>
|
|
35
36
|
tryreturn(async () => (await import(`${path}.js`)).default)
|
|
36
|
-
.orelse(
|
|
37
|
+
.orelse(_ => errors.MissingComponent.throw(path.name, path));
|
|
37
38
|
|
|
38
39
|
const make_component = base => async (name, props) =>
|
|
39
40
|
({name, component: await load(base.join(name)), props});
|
|
40
41
|
|
|
41
42
|
const encoder = new TextEncoder();
|
|
42
43
|
|
|
43
|
-
const handler = (
|
|
44
|
-
async (app, {layouts = [], as_layout} = {}) => {
|
|
45
|
-
const
|
|
44
|
+
const handler = (name, props = {}, {status = Status.OK, page} = {}) =>
|
|
45
|
+
async (app, {layouts = [], as_layout} = {}, request) => {
|
|
46
|
+
const {paths} = app.build;
|
|
47
|
+
const make = make_component(paths.server.join(app.config.build.app));
|
|
46
48
|
if (as_layout) {
|
|
47
49
|
return make(name, props);
|
|
48
50
|
}
|
|
49
51
|
const components = (await Promise.all(layouts.map(layout =>
|
|
50
|
-
layout(app, {as_layout: true})
|
|
52
|
+
layout(app, {as_layout: true}, request)
|
|
51
53
|
)))
|
|
52
54
|
/* set the actual page as the last component */
|
|
53
55
|
.concat(await make(name, props));
|
|
54
56
|
|
|
55
57
|
const data = components.map(component => component.props);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
const names = await Promise.all(components.map(component =>
|
|
59
|
+
normalize(component.name)));
|
|
60
|
+
|
|
61
|
+
const liveview = app.liveview !== undefined;
|
|
62
|
+
if (liveview && request.headers.get(app.liveview.header) !== undefined) {
|
|
63
|
+
return new Response(JSON.stringify({names, data}), {
|
|
64
|
+
status,
|
|
65
|
+
headers: {...await app.headers(),
|
|
66
|
+
"Content-Type": MediaType.APPLICATION_JSON},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const root = paths.server.join(filename);
|
|
58
70
|
const imported = (await import(root)).default;
|
|
59
71
|
const {html} = imported.render({
|
|
60
72
|
components: components.map(({component}) => component),
|
|
61
73
|
data,
|
|
62
74
|
});
|
|
63
75
|
|
|
64
|
-
const names = (await Promise.all(components.map(component =>
|
|
65
|
-
normalize(component.name)))).join(", ");
|
|
66
76
|
const code = `
|
|
67
|
-
import
|
|
68
|
-
|
|
77
|
+
import * as components from "app";
|
|
78
|
+
const getComponents = names =>
|
|
79
|
+
Object.entries(components).filter(([name, component]) =>
|
|
80
|
+
names.includes(name))
|
|
81
|
+
.map(([, component]) => component);
|
|
82
|
+
let root = new components.${rootname}({
|
|
69
83
|
target: document.body,
|
|
70
84
|
hydrate: true,
|
|
71
85
|
props: {
|
|
72
|
-
components: [${names}],
|
|
86
|
+
components: getComponents([${names.map(name => `"${name}"`)}]),
|
|
73
87
|
data: JSON.parse(${JSON.stringify(JSON.stringify(data))}),
|
|
74
88
|
},
|
|
75
89
|
});
|
|
90
|
+
|
|
91
|
+
${liveview ? `
|
|
92
|
+
const {liveview} = components;
|
|
93
|
+
window.addEventListener("DOMContentLoaded", _ => liveview(props => {
|
|
94
|
+
root.$destroy();
|
|
95
|
+
root = new components.${rootname}({
|
|
96
|
+
target: document.body,
|
|
97
|
+
hydrate: true,
|
|
98
|
+
props: {
|
|
99
|
+
components: getComponents(props.names),
|
|
100
|
+
data: props.data,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}));
|
|
104
|
+
` : ""}
|
|
76
105
|
`;
|
|
77
106
|
|
|
78
107
|
await app.publish({code, type, inline: true});
|
|
79
|
-
// needs to be called before app.render
|
|
80
|
-
const headers = app.headers();
|
|
81
108
|
|
|
82
|
-
|
|
83
|
-
|
|
109
|
+
const headers = await app.headers();
|
|
110
|
+
|
|
111
|
+
return new Response(await app.render({body: html, page}), {
|
|
84
112
|
status,
|
|
85
|
-
headers: {...headers, "Content-Type":
|
|
86
|
-
}
|
|
113
|
+
headers: {...headers, "Content-Type": MediaType.TEXT_HTML},
|
|
114
|
+
});
|
|
87
115
|
};
|
|
88
116
|
|
|
89
117
|
const create_root = (length, data) => {
|
|
@@ -109,102 +137,92 @@ const create_root = (length, data) => {
|
|
|
109
137
|
};
|
|
110
138
|
|
|
111
139
|
const {svelte, js} = endings;
|
|
112
|
-
export default ({
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
export default ({dynamicProps = "data"} = {}) => ({
|
|
141
|
+
name: "@primate/svelte",
|
|
142
|
+
register(app, next) {
|
|
143
|
+
app.register("svelte", handler);
|
|
144
|
+
return next(app);
|
|
145
|
+
},
|
|
146
|
+
async compile(app, next) {
|
|
147
|
+
const source = app.build.paths.components;
|
|
148
|
+
// copy components to build/components
|
|
149
|
+
await app.copy(app.paths.components, source, /^.*.(?:js|svelte)$/u);
|
|
150
|
+
const components = await source.collect(/^.*.svelte$/u);
|
|
151
|
+
const target = app.build.paths.server.join(app.config.build.app);
|
|
152
|
+
await target.file.create();
|
|
153
|
+
|
|
154
|
+
await Promise.all(components.map(async component => {
|
|
155
|
+
const file = await component.file.read();
|
|
156
|
+
const server = compiler.compile(file, options.server);
|
|
157
|
+
const to = target.join(`${component.path}.js`.replace(source, ""));
|
|
158
|
+
await to.directory.file.create();
|
|
159
|
+
await to.file.write(server.js.code.replaceAll(svelte, js));
|
|
160
|
+
}));
|
|
161
|
+
|
|
162
|
+
const root = create_root(app.layoutDepth, dynamicProps);
|
|
163
|
+
const server = compiler.compile(root, options.server).js.code;
|
|
164
|
+
const to = app.build.paths.server.join(filename);
|
|
165
|
+
await to.file.write(server);
|
|
166
|
+
|
|
167
|
+
return next(app);
|
|
168
|
+
},
|
|
169
|
+
async publish(app, next) {
|
|
170
|
+
const source = app.build.paths.components;
|
|
171
|
+
const components = await source.collect(/^.*.svelte$/u);
|
|
172
|
+
await app.import("svelte");
|
|
173
|
+
|
|
174
|
+
// liveview
|
|
175
|
+
if (app.liveview !== undefined) {
|
|
176
|
+
app.bootstrap({
|
|
177
|
+
type: "script",
|
|
178
|
+
code: "export {default as liveview} from \"@primate/liveview\";\n",
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
await Promise.all(components.map(async component => {
|
|
182
|
+
const name = component.path.replace(`${source}/`, "");
|
|
183
|
+
const file = await component.file.read();
|
|
184
|
+
const client = compiler.compile(file, options.client);
|
|
185
|
+
const build = app.config.build.app;
|
|
186
|
+
const {path} = component;
|
|
151
187
|
|
|
152
|
-
|
|
153
|
-
const server = compiler.compile(root, options.server).js.code;
|
|
154
|
-
const to = app.paths.server.join(filename);
|
|
155
|
-
await to.file.write(server);
|
|
156
|
-
|
|
157
|
-
return next(app);
|
|
158
|
-
},
|
|
159
|
-
async publish(app, next) {
|
|
160
|
-
await app.import("svelte");
|
|
161
|
-
const {source, build} = env;
|
|
162
|
-
|
|
163
|
-
const target = env.paths.client;
|
|
164
|
-
await target.file.create();
|
|
165
|
-
|
|
166
|
-
await Promise.all(env.components.map(async component => {
|
|
167
|
-
const name = component.path.replace(`${source}/`, "");
|
|
168
|
-
const file = await component.file.read();
|
|
169
|
-
const client = compiler.compile(file, options.client);
|
|
188
|
+
{
|
|
170
189
|
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
await app.publish({src, code, type});
|
|
175
|
-
}
|
|
176
|
-
const imported = await normalize(name);
|
|
177
|
-
app.bootstrap({
|
|
178
|
-
type: "script",
|
|
179
|
-
code: `export {default as ${imported}} from "./${name}.js";\n`,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
if (client.css.code !== null) {
|
|
183
|
-
{
|
|
184
|
-
const {code} = client.css;
|
|
185
|
-
const src = `${component.path}.css`.replace(`${source}`, build);
|
|
186
|
-
await app.publish({src, code, type: "style"});
|
|
187
|
-
}
|
|
188
|
-
{
|
|
189
|
-
const src = `${component.path}.css`.replace(`${source}`, "");
|
|
190
|
-
app.bootstrap({type: "style", code: `import ".${src}";`});
|
|
191
|
-
}
|
|
190
|
+
const code = client.js.code.replaceAll(svelte, js);
|
|
191
|
+
const src = `${path}.js`.replace(`${source}`, _ => build);
|
|
192
|
+
await app.publish({src, code, type});
|
|
192
193
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const code = client.js.code.replaceAll(svelte, js);
|
|
199
|
-
const src = new Path(app.config.http.static.root, filename);
|
|
200
|
-
await app.publish({src, code, type});
|
|
194
|
+
const imported = await normalize(name);
|
|
195
|
+
app.bootstrap({
|
|
196
|
+
type: "script",
|
|
197
|
+
code: `export {default as ${imported}} from "./${name}.js";\n`,
|
|
198
|
+
});
|
|
201
199
|
}
|
|
202
|
-
{
|
|
203
|
-
|
|
204
|
-
|
|
200
|
+
if (client.css.code !== null) {
|
|
201
|
+
{
|
|
202
|
+
const {code} = client.css;
|
|
203
|
+
const src = `${path}.css`.replace(`${source}`, _ => build);
|
|
204
|
+
await app.publish({src, code, type: "style"});
|
|
205
|
+
}
|
|
206
|
+
{
|
|
207
|
+
// sans app.config.build.app removal, for a bundler to resolve,
|
|
208
|
+
// irrelevant without bundling
|
|
209
|
+
const src = `${path}.css`.replace(`${source}`, "");
|
|
210
|
+
app.bootstrap({type: "style", code: `import ".${src}";`});
|
|
211
|
+
}
|
|
205
212
|
}
|
|
213
|
+
}));
|
|
206
214
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
215
|
+
{
|
|
216
|
+
const root = create_root(app.layoutDepth, dynamicProps);
|
|
217
|
+
const client = compiler.compile(root, options.client);
|
|
218
|
+
const code = client.js.code.replaceAll(svelte, js);
|
|
219
|
+
const src = new Path(app.config.http.static.root, filename);
|
|
220
|
+
await app.publish({src, code, type});
|
|
221
|
+
}
|
|
222
|
+
{
|
|
223
|
+
const code = `export {default as ${rootname}} from "../${filename}";\n`;
|
|
224
|
+
app.bootstrap({type: "script", code});
|
|
225
|
+
}
|
|
226
|
+
return next(app);
|
|
227
|
+
},
|
|
228
|
+
});
|