@primate/solid 0.0.2 → 0.2.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/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # Solid
2
2
 
3
- This handler module supports SSR and serves SolidJS (JSX) components with the
4
- .jsx extension.
3
+ This handler serves Solid (JSX) components with the `jsx` file extension.
5
4
 
6
5
  ## [Documentation](https://primatejs.com/modules/solid)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primate/solid",
3
- "version": "0.0.2",
3
+ "version": "0.2.0",
4
4
  "description": "Primate Solid module",
5
5
  "homepage": "https://primatejs.com/modules/solid",
6
6
  "bugs": "https://github.com/primatejs/primate/issues",
@@ -16,12 +16,13 @@
16
16
  "directory": "packages/solid"
17
17
  },
18
18
  "dependencies": {
19
+ "@primate/frontend": "^0.2.0",
19
20
  "babel-preset-solid": "^1.7.7",
20
- "runtime-compat": "^0.25.1",
21
+ "runtime-compat": "^0.25.7",
21
22
  "solid-js": "^1.7.11"
22
23
  },
23
24
  "peerDependencies": {
24
- "primate": "0.21"
25
+ "primate": "0.22"
25
26
  },
26
27
  "type": "module",
27
28
  "exports": "./src/exports.js"
@@ -7,13 +7,13 @@ const {groups: {code: hydration_script}} = generateHydrationScript()
7
7
 
8
8
  export default ({names, data}, options) => `
9
9
  import * as components from "app";
10
- import {hydrate_solid} from "app";
10
+ import {hydrate_solid, render_solid} from "app";
11
11
 
12
- window._$HY = { events: [], completed: new WeakSet(), r: {} };
12
+ window._$HY = {events: [], completed: new WeakSet(), r: {}};
13
13
 
14
14
  ${hydration_script}
15
15
 
16
- const root = hydrate_solid(() => components.${rootname}({
16
+ let dispose = hydrate_solid(() => components.${rootname}({
17
17
  components: [${names.map(name => `components.${name}`).join(", ")}],
18
18
  data: JSON.parse(${JSON.stringify(JSON.stringify(data))}),
19
19
  }), globalThis.window.document.body);
@@ -1,5 +1,4 @@
1
1
  export {default as client} from "./client.js";
2
2
  export {default as hydrate} from "./hydrate.js";
3
3
  export {default as create_root} from "./create-root.js";
4
- export {default as create_root2} from "./create-root2.js";
5
4
  export {default as rootname} from "./rootname.js";
@@ -1 +1,4 @@
1
- export default "export {hydrate as hydrate_solid} from \"solid-js/web\";";
1
+ export default `export {
2
+ hydrate as hydrate_solid,
3
+ render as render_solid,
4
+ } from "solid-js/web";`;
@@ -3,10 +3,9 @@ import rootname from "./rootname.js";
3
3
  export default `
4
4
  const {liveview} = components;
5
5
  window.addEventListener("DOMContentLoaded", _ => liveview((props, update) => {
6
- root.render(
7
- createElement(components.${rootname}, {
8
- components: props.names.map(name => components[name]),
9
- data: props.data,
10
- })
11
- );
6
+ dispose();
7
+ dispose = render_solid(() => components.${rootname}({
8
+ components: props.names.map(name => components[name]),
9
+ data: props.data,
10
+ }), globalThis.window.document.body);
12
11
  }));`;
package/src/module.js CHANGED
@@ -1,63 +1,38 @@
1
- import crypto from "runtime-compat/crypto";
2
1
  import {Path} from "runtime-compat/fs";
3
2
  import {Response, Status, MediaType} from "runtime-compat/http";
3
+ import * as base from "@primate/frontend";
4
+ import {renderToString as render} from "solid-js/web";
4
5
  import {transformAsync} from "@babel/core";
5
6
  import solid from "babel-preset-solid";
6
- import {renderToString} from "solid-js/web";
7
- import {tryreturn} from "runtime-compat/async";
8
- import errors from "./errors.js";
9
- import {client, create_root, create_root2, rootname, hydrate} from "./client/exports.js";
7
+ import {client, create_root, rootname, hydrate} from "./client/exports.js";
10
8
 
11
- // do not hard-depend on node
12
- const packager = import.meta.runtime?.packager ?? "package.json";
13
- const library = import.meta.runtime?.library ?? "node_modules";
14
-
15
- const encoder = new TextEncoder();
16
- const hash = async (string, algorithm = "sha-256") => {
17
- const base = 16;
18
- const target_pad_length = 2;
19
- const target_slice = 12;
20
- const bytes = await crypto.subtle.digest(algorithm, encoder.encode(string));
21
- return Array.from(new Uint8Array(bytes))
22
- .map(byte => byte.toString(base).padStart(target_pad_length, "0"))
23
- .join("")
24
- .slice(0, target_slice);
25
- };
26
- const normalize = async path => `solid_${await hash(path)}`;
9
+ const normalize = base.normalize("solid");
27
10
 
28
11
  const import$ = async (module, app, copy_dependency) => {
29
- const {build: {modules}, http: {static: {root}}} = app.config;
12
+ const {library, packager} = app;
13
+ const {http: {static: {root}}} = app.config;
30
14
  const parts = module.split("/");
31
15
  const path = [library, ...parts];
32
16
  const pkg = await Path.resolve().join(...path, packager).json();
33
17
  if (copy_dependency) {
34
18
  const dependency = Path.resolve().join(...path);
35
- const to = app.build.paths.client.join(modules, ...parts);
19
+ const to = app.runpath(app.config.location.client, library, ...parts);
36
20
  await dependency.file.copy(`${to}`);
37
21
  }
38
22
 
39
23
  const entry = pkg.exports["."].browser.import;
40
- app.importmaps[module] = new Path(root, modules, module, entry).path;
24
+ app.importmaps[module] = new Path(root, library, module, entry).path;
41
25
  };
42
26
 
43
- const filename = `${rootname}.js`;
44
27
  const type = "module";
45
28
 
46
- const load = async path =>
47
- tryreturn(async () => (await import(`${path}.js`)).default)
48
- .orelse(_ => errors.MissingComponent.throw(path.name, path));
49
-
50
- const make_component = base => async (name, props) =>
51
- ({name, component: await load(base.join(name)), props});
52
-
53
- const handler = (name, props = {}, {status = Status.OK} = {}) =>
29
+ const handler = config => (name, props = {}, {status = Status.OK, page} = {}) =>
54
30
  async (app, {layouts = [], as_layout} = {}, request) => {
31
+ const {make, root} = config;
32
+ const {headers} = request;
55
33
  const options = {
56
34
  liveview: app.liveview !== undefined,
57
35
  };
58
- const {headers} = request;
59
- const {paths} = app.build;
60
- const make = make_component(paths.server.join(app.config.build.app));
61
36
  if (as_layout) {
62
37
  return make(name, props);
63
38
  }
@@ -78,9 +53,8 @@ const handler = (name, props = {}, {status = Status.OK} = {}) =>
78
53
  });
79
54
  }
80
55
 
81
- const root = paths.server.join(filename);
82
56
  const imported = (await import(root)).default;
83
- const body = renderToString(() => imported({
57
+ const body = render(() => imported({
84
58
  components: components.map(({component}) => component),
85
59
  data,
86
60
  }));
@@ -91,119 +65,60 @@ const handler = (name, props = {}, {status = Status.OK} = {}) =>
91
65
  // needs to be called before app.render
92
66
  const headers$ = await app.headers();
93
67
 
94
- return new Response(await app.render({body}), {
68
+ return new Response(await app.render({body, page}), {
95
69
  status,
96
70
  headers: {...headers$, "Content-Type": MediaType.TEXT_HTML},
97
71
  });
98
72
  };
99
73
 
100
- const options = {
101
- server: [solid, {
102
- generate: "ssr",
103
- hydratable: true,
104
- }],
105
- client: [solid, {
106
- generate: "dom",
107
- hydratable: true,
108
- }],
109
- };
110
-
111
- const endings = {
112
- solid: ".solid",
113
- js: ".solid.js",
114
- };
115
-
116
- const transform = {
117
- async server(file) {
118
- return (await transformAsync(file, {presets: [options.server]})).code;
119
- },
120
- async client(file) {
121
- return (await transformAsync(file, {presets: [options.client]})).code;
122
- },
123
- };
124
-
125
74
  export default ({
126
- dynamicProps = "data",
75
+ directory,
76
+ dynamicProps,
127
77
  extension = "jsx",
128
78
  } = {}) => {
129
- const env = {};
130
-
131
79
  return {
132
- name: "@primate/solid",
133
- init(app, next) {
134
- env.source = app.build.paths.components;
135
-
136
- return next(app);
137
- },
80
+ name: "primate:solid",
138
81
  register(app, next) {
139
- app.register("solid", handler);
82
+ app.register(extension, handler(base.register({app, rootname})));
83
+
140
84
  return next(app);
141
85
  },
142
86
  async compile(app, next) {
143
- // copy components to build/components
144
- await app.copy(app.paths.components, env.source, /^.*.(?:solid)$/u);
145
- const components = await env.source.collect(/^.*.solid$/u);
146
- const target = app.build.paths.server.join(app.config.build.app);
147
- await target.file.create();
148
-
149
- await Promise.all(components.map(async component => {
150
- const file = await component.file.read();
151
- const code = await transform.server(file);
152
- const to = target.join(`${component.path}.js`.replace(env.source, ""));
153
- await to.directory.file.create();
154
- await to.file.write(code.replaceAll(endings.solid, endings.js));
155
- }));
156
-
157
- const root = await transform.server(create_root2(app.layoutDepth,
158
- dynamicProps));
159
- const to = app.build.paths.server.join(filename);
160
- await to.file.write(root);
87
+ await base.compile({
88
+ app,
89
+ directory: directory ?? app.config.location.components,
90
+ extension,
91
+ rootname,
92
+ create_root,
93
+ dynamicProps,
94
+ async compile(file) {
95
+ const presets = [[solid, {generate: "ssr", hydratable: true}]];
96
+ return (await transformAsync(file, {presets})).code;
97
+ },
98
+ });
161
99
 
162
100
  return next(app);
163
101
  },
164
102
  async publish(app, next) {
165
- const target = app.build.paths.client.join(app.config.build.app);
166
- await target.file.create();
167
-
168
- // create client components
169
- const components = await env.source.collect(/^.*.solid/u);
170
- await Promise.all(components.map(async component => {
171
- const name = component.path.replace(`${env.source}/`, "");
172
- const file = await component.file.read();
173
- const code = await transform.client(file);
174
- const build = app.config.build.app;
175
- const {path} = component;
176
-
177
- {
178
- {
179
- const src = `${path}.js`.replace(`${env.source}`, _ => build);
180
- await app.publish({src,
181
- code: code.replaceAll(endings.solid, endings.js),
182
- type});
183
- }
184
- const imported = await normalize(name);
185
- app.bootstrap({
186
- type: "script",
187
- code: `export {default as ${imported}} from "./${name}.js";\n`,
188
- });
189
- }
190
- }));
191
-
103
+ // import libs
192
104
  await import$("solid-js", app, true);
193
105
  await import$("solid-js/web", app);
194
-
195
- app.bootstrap({type: "script", code: hydrate});
196
-
197
- {
198
- const code = await transform.client(create_root2(app.layoutDepth,
199
- dynamicProps));
200
- const src = new Path(app.config.http.static.root, filename);
201
- await app.publish({src, code, type});
202
- }
203
- {
204
- const code = `export {default as ${rootname}} from "../${filename}";\n`;
205
- app.bootstrap({type: "script", code});
206
- }
106
+ // export hydration code
107
+ app.export({type: "script", code: hydrate});
108
+
109
+ await base.publish({
110
+ app,
111
+ directory: directory ?? app.config.location.components,
112
+ extension,
113
+ rootname,
114
+ create_root,
115
+ dynamicProps,
116
+ normalize,
117
+ async compile(file) {
118
+ const presets = [[solid, {generate: "dom", hydratable: true}]];
119
+ return {js: (await transformAsync(file, {presets})).code};
120
+ },
121
+ });
207
122
 
208
123
  return next(app);
209
124
  },
@@ -1,22 +0,0 @@
1
- export default (length, data) => {
2
- const n = length - 1;
3
- const body = Array.from({length: n}, (_, i) => i - 1)
4
- .reduceRight((child, _, i) => `<Show
5
- when={components[${i + 1}] !== undefined}
6
- fallback={
7
- <>
8
- <Dynamic component={components[${i}]} ${data}={data[${i}]} />
9
- </>
10
- }
11
- >
12
- <Dynamic component={components[${i}]} ${data}={data[${i}]}>${child}</Dynamic>
13
- </Show>
14
- `, `<Dynamic component={components[${n}]} ${data}={data[${n}]} />`);
15
-
16
- return `
17
- import {Dynamic, Show} from "solid-js/web";
18
- export default function Root({components, data} = {}) {
19
- return ${body};
20
- };
21
- `;
22
- };