create-evikit 2.3.1 → 2.5.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/.woodpecker/test.yaml +18 -0
- package/README.md +36 -0
- package/bin/create-evikit.js +1 -1
- package/package.json +2 -2
- package/po/create-evikit.pot +6 -1
- package/po/uk.po +9 -2
- package/src/lib/db/index.js +5 -6
- package/src/routes/page.js +21 -6
- package/static/preact-ssr-framework.png +0 -0
- package/static/preact-ssr-framework.xcf +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
when:
|
|
2
|
+
- event: push
|
|
3
|
+
branch: main
|
|
4
|
+
- event: pull_request
|
|
5
|
+
|
|
6
|
+
steps:
|
|
7
|
+
- name: build
|
|
8
|
+
image: node:24-alpine
|
|
9
|
+
commands:
|
|
10
|
+
- apk add git
|
|
11
|
+
# Are types correct?
|
|
12
|
+
- npm i
|
|
13
|
+
- npm run lint
|
|
14
|
+
- npm run build
|
|
15
|
+
# Does todo app example build?
|
|
16
|
+
- npm link
|
|
17
|
+
- npx create-evikit my-app
|
|
18
|
+
- (cd my-app; npm run build)
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# create-evikit
|
|
2
|
+
|
|
3
|
+
Create a monolith server-rendered Preact app with an API powered by a node:sqlite database, using [EviKit](https://evikit.js.org/):
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm init evikit my-app
|
|
7
|
+
cd my-app
|
|
8
|
+
npm run dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Open http://localhost:5173/, try editing the example routes and see changes live.
|
|
12
|
+
|
|
13
|
+
You can continue with the [EviKit tutorial](https://codeberg.org/nykula/evikit#documentation). With this initializer, you don't have to manually install dependencies, add scripts to `package.json`, or create typical files such as `index.html` and `vite.config.js`.
|
|
14
|
+
|
|
15
|
+
> 😉 If you are new to Preact and the concept of Virtual DOM, it is a good idea to complete the [Preact tutorial](https://preactjs.com/tutorial/) first.
|
|
16
|
+
|
|
17
|
+
## Read more
|
|
18
|
+
|
|
19
|
+
Think of EviKit as an [LXDE](https://en.wikipedia.org/wiki/LXDE#Software_components_of_LXDE) of web frameworks, it stands on the shoulders of awesome libraries and tools from the Preact and Node.js ecosystems:
|
|
20
|
+
|
|
21
|
+
- **[valibot](https://valibot.dev/guides/introduction/)** - Lets you declare detabase schema and validate API input/output.
|
|
22
|
+
- **[hoofd/preact](https://github.com/0no-co/hoofd)** - Populates `<title>` and `<meta>` tags.
|
|
23
|
+
- **[gettext.js](https://github.com/smhg/gettext-parser)** - Lets you pluralize translated strings.
|
|
24
|
+
- **[vite](https://vite.dev/guide/)** - Builds your app for development and production.
|
|
25
|
+
- **[express](https://expressjs.com/)** - Lets you apply compression, serve static files and use other familiar middleware.
|
|
26
|
+
- [@fastify/busboy](https://github.com/fastify/busboy) - Parses forms, including uploaded files.
|
|
27
|
+
- [@preact/preset-vite](https://github.com/preactjs/preset-vite) - In development, shows your code changes without reloading the page.
|
|
28
|
+
- [env-paths](https://github.com/fastify/busboy) - Saves your database in standard system-specific directory.
|
|
29
|
+
- [gettext-parser](https://github.com/smhg/gettext-parser) - Parses translation files.
|
|
30
|
+
- [preact-iso](https://github.com/preactjs/preact-iso) - Handles routing and hydrates the server-rendered code on the client.
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
SPDX-License-Identifier: 0BSD
|
|
35
|
+
|
|
36
|
+
Note: this license applies to this example application template. EviKit itself uses the MIT license.
|
package/bin/create-evikit.js
CHANGED
|
@@ -25,7 +25,7 @@ for (const file of [...template, "eslint.config.js", "tsconfig.json"]) {
|
|
|
25
25
|
path,
|
|
26
26
|
readFileSync(join(ownRoot, file), "utf8")
|
|
27
27
|
.replace(
|
|
28
|
-
/<link\s+href="[^"]+"
|
|
28
|
+
/<link\s+href="[^"]+"\s+media="[^"]+"\s+rel="[a-z]+"\s+\/>\s+/g,
|
|
29
29
|
"",
|
|
30
30
|
)
|
|
31
31
|
.replace(', "uk"', ""),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-evikit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": "bin/create-evikit.js",
|
|
6
6
|
"scripts": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@speed-highlight/core": "^1.2.17",
|
|
38
38
|
"accept-language": "^3.0.20",
|
|
39
39
|
"classnames": "^2.5.1",
|
|
40
|
-
"evikit": "^2.
|
|
40
|
+
"evikit": "^2.5.0",
|
|
41
41
|
"express": "^5.2.1",
|
|
42
42
|
"file-type": "^22.0.1",
|
|
43
43
|
"hoofd": "^1.7.3",
|
package/po/create-evikit.pot
CHANGED
|
@@ -8,7 +8,7 @@ msgid ""
|
|
|
8
8
|
msgstr ""
|
|
9
9
|
"Project-Id-Version: create-evikit\n"
|
|
10
10
|
"Report-Msgid-Bugs-To: \n"
|
|
11
|
-
"POT-Creation-Date: 2026-07-08
|
|
11
|
+
"POT-Creation-Date: 2026-07-08 14:48+0300\n"
|
|
12
12
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
13
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
14
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
@@ -53,6 +53,11 @@ msgstr ""
|
|
|
53
53
|
msgid "Quick start"
|
|
54
54
|
msgstr ""
|
|
55
55
|
|
|
56
|
+
msgid ""
|
|
57
|
+
"<a href=\"{translate}\">Translate</a> this page to your language using <a "
|
|
58
|
+
"href=\"{poedit}\">Poedit</a> and send a merge request!"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
56
61
|
msgid ""
|
|
57
62
|
"There’s intentionally <b>not much API</b>. Documentation entirely fits in a "
|
|
58
63
|
"long but straightforward <b>README</b>. Like the Django tutorial, it guides "
|
package/po/uk.po
CHANGED
|
@@ -7,8 +7,8 @@ msgid ""
|
|
|
7
7
|
msgstr ""
|
|
8
8
|
"Project-Id-Version: create-evikit\n"
|
|
9
9
|
"Report-Msgid-Bugs-To: \n"
|
|
10
|
-
"POT-Creation-Date: 2026-07-08
|
|
11
|
-
"PO-Revision-Date: 2026-07-08
|
|
10
|
+
"POT-Creation-Date: 2026-07-08 14:48+0300\n"
|
|
11
|
+
"PO-Revision-Date: 2026-07-08 14:49+0300\n"
|
|
12
12
|
"Last-Translator: EMAIL@ADDRESS\n"
|
|
13
13
|
"Language-Team: Ukrainian\n"
|
|
14
14
|
"Language: uk\n"
|
|
@@ -64,6 +64,13 @@ msgstr ""
|
|
|
64
64
|
msgid "Quick start"
|
|
65
65
|
msgstr "Швидкий початок"
|
|
66
66
|
|
|
67
|
+
msgid ""
|
|
68
|
+
"<a href=\"{translate}\">Translate</a> this page to your language using <a "
|
|
69
|
+
"href=\"{poedit}\">Poedit</a> and send a merge request!"
|
|
70
|
+
msgstr ""
|
|
71
|
+
"<a href=\"{translate}\">Перекладіть</a> цю сторінку своєю мовою за допомогою "
|
|
72
|
+
"<a href=\"{poedit}\">Poedit</a> і надішліть запит на злиття!"
|
|
73
|
+
|
|
67
74
|
msgid ""
|
|
68
75
|
"There’s intentionally <b>not much API</b>. Documentation entirely fits in a "
|
|
69
76
|
"long but straightforward <b>README</b>. Like the Django tutorial, it guides "
|
package/src/lib/db/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { daemon } from "evikit/server";
|
|
1
2
|
import { sqlite } from "evikit/sqlite";
|
|
2
3
|
|
|
3
4
|
import pkg from "../../../package.json" with { type: "json" };
|
|
@@ -5,15 +6,13 @@ import * as schema from "./schema.js";
|
|
|
5
6
|
|
|
6
7
|
export const db = sqlite({ pkg, schema });
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
process.env["npm_lifecycle_event"] == "dev"
|
|
11
|
-
) {
|
|
12
|
-
setInterval(() => {
|
|
9
|
+
daemon(() => {
|
|
10
|
+
const interval = setInterval(() => {
|
|
13
11
|
db.Todo.delete({
|
|
14
12
|
text: db.Todo.select()
|
|
15
13
|
.filter(({ createdAt }) => createdAt < Date.now() - 10 * 60e3)
|
|
16
14
|
.map(({ text }) => text),
|
|
17
15
|
});
|
|
18
16
|
}, 1000);
|
|
19
|
-
|
|
17
|
+
return () => clearInterval(interval);
|
|
18
|
+
});
|
package/src/routes/page.js
CHANGED
|
@@ -182,7 +182,21 @@ npm run dev
|
|
|
182
182
|
|
|
183
183
|
h(
|
|
184
184
|
Code,
|
|
185
|
-
{
|
|
185
|
+
{
|
|
186
|
+
file: data?.File["src/lib/index.js"],
|
|
187
|
+
lang: "js",
|
|
188
|
+
note:
|
|
189
|
+
"🤝 " +
|
|
190
|
+
i18n
|
|
191
|
+
.gettext(
|
|
192
|
+
`<a href="{translate}">Translate</a> this page to your language using <a href="{poedit}">Poedit</a> and send a merge request!`,
|
|
193
|
+
)
|
|
194
|
+
.replace(
|
|
195
|
+
"{translate}",
|
|
196
|
+
"https://codeberg.org/nykula/create-evikit/src/branch/main/po/create-evikit.pot",
|
|
197
|
+
)
|
|
198
|
+
.replace("{poedit}", "https://poedit.com/"),
|
|
199
|
+
},
|
|
186
200
|
span(null, "src/lib/"),
|
|
187
201
|
b(null, "index.js"),
|
|
188
202
|
),
|
|
@@ -285,8 +299,8 @@ npm run dev
|
|
|
285
299
|
);
|
|
286
300
|
}
|
|
287
301
|
|
|
288
|
-
/** @param {{ children?: any, lang: string, file: string | undefined, tag?: string }} props */
|
|
289
|
-
function Code({ children, file, lang, tag }) {
|
|
302
|
+
/** @param {{ children?: any, lang: string, file: string | undefined, note?: string, tag?: string }} props */
|
|
303
|
+
function Code({ children, file, lang, note, tag }) {
|
|
290
304
|
const inner = pre(
|
|
291
305
|
{ class: "mt-4 overflow-auto text-sm" },
|
|
292
306
|
code(
|
|
@@ -304,10 +318,11 @@ function Code({ children, file, lang, tag }) {
|
|
|
304
318
|
),
|
|
305
319
|
),
|
|
306
320
|
);
|
|
321
|
+
const more = note ? p({ class: "mt-5", ...sanitize(note) }) : undefined;
|
|
307
322
|
const style = `${darkBg} mb-4 mx-0 overflow-hidden p-4 rounded-xl`;
|
|
308
323
|
return tag == "details"
|
|
309
|
-
? details({ class: style }, summary(null, children), inner)
|
|
310
|
-
: figure({ class: style }, figcaption(null, children), inner);
|
|
324
|
+
? details({ class: style }, summary(null, children), inner, more)
|
|
325
|
+
: figure({ class: style }, figcaption(null, children), inner, more);
|
|
311
326
|
}
|
|
312
327
|
|
|
313
328
|
/** @param {string} html */
|
|
@@ -316,7 +331,7 @@ function sanitize(html) {
|
|
|
316
331
|
dangerouslySetInnerHTML: {
|
|
317
332
|
__html: html.replace(/<([^>]*)>/g, (match) =>
|
|
318
333
|
/^<\/?[a-z]+>$/.test(match) ||
|
|
319
|
-
/^<a href="[0-9A-Za-z
|
|
334
|
+
/^<a href="[0-9A-Za-z:/.#%-]*"( target="_top")?>$/.test(match)
|
|
320
335
|
? match
|
|
321
336
|
: "",
|
|
322
337
|
),
|
|
Binary file
|
|
Binary file
|