Journaux liées à cette note :

Bilan de poc-sveltekit-custom-server #SvelteKit, #svelte, #node, #javascript, #projet, #POC

Contexte et objectifs

Dans le projet gibbon-replay, j'ai besoin d'exécuter une tâche une fois par jour pour supprimer des anciennes sessions.

gibbon-replay utilise une base de données SQLite qui ne dispose pas nativement de fonctionnalité de type Time To Live, comme on peut trouver dans Clickhouse.
SQLite ne propose pas non plus d'équivalent à pg_cron — ce qui est tout à fait normal étant donnée que SQLite est une librairie et non pas un service à part entière.

Le projet gibbon-replay est un monolith (j'aime les monoliths !) et je souhaite conserver ce choix.

Face à ces contraintes, une solution consiste à intégrer une solution comme Cron for Node.js directement dans l'application gibbon-replay.
Je pense que je dois implémenter cela dans un SvelteKit Custom Server, ce qui me permettrait d'exécuter cette tâche de purge à intervalles réguliers tout en conservant l'architecture monolithique.

Il y a quelques jours, j'ai décidé de tester cette idée dans un POC nommé : poc-sveltekit-custom-server.

J'ai aussi décidé d'expérimenter un objectif supplémentaire dans ce POC : lancer la migration du modèle de données dès le lancement du monolith et non plus lors de la première requête HTTP reçue par le service.

Enfin, je souhaitais ne pas dégrader l'expérience développeur (DX), c'est à dire, je souhaitais pouvoir continuer à simplement utiliser :

$ pnpm run dev

ou

$ pnpm run build
$ pnpm run preview

sans différence avec un projet SvelteKit "vanilla".

Résultats du POC et enseignements

Tout d'abord, le POC fonctionne parfaitement 🙂, sans dégrader l'expérience développeur (DX), qui ressemble à ceci :

$ mise install
$ pnpm install
$ pnpm run load-seed-data
Start data model migration…
Data model migration completed
Start load seed data...
seed data loaded

Lancement du projet en mode développement :

$ pnpm run dev
Start data model migration…
Data model migration completed
Server started on http://localhost:5173 in development mode

Lancement du projet "buildé" :

$ pnpm run build
$ pnpm run preview
Start data model migration…
Data model migration completed
Server started on http://localhost:3000 in production mode

Les migrations et les données "seed.sql" se trouvent dans le dossier /sqls/.

Le SvelteKit Custom Server est implémenté dans le fichier src/server.js et il ressemble à ceci :

import express from 'express';
import cron from 'node-cron';
import db, { migrate } from '@lib/server/db.js';

const isDev = process.env.ENV !== 'production';

migrate(); // Lancement de la migration du modèle de donnée dès de lancement du serveur

// Configuration d'une tâche exécuté toutes les heures
cron.schedule(
    '0 * * * *',
    async () => {
        console.log('Start task...');
        console.log(db().query('SELECT * FROM posts'));
        console.log('Task executed');
    }
);

async function createServer() {
    const app = express();

    ...

Personnellement, je trouve cela simple et minimaliste.

Point de difficulté

SvelteKit utilise des "module alias", comme par exemple $lib.
Problème, par défaut, ces "module alias" ne sont pas configurés lors de l'exécution de node src/server.js.

Pour me permettre d'importer dans src/server.js des modules de src/lib/server/* comme :

import db, { migrate } from '@lib/server/db.js';

j'ai utilisé la librairie esm-module-alias.

Ceci complexifie un peu le projet, j'ai dû configurer ceci dans /package.json :

{
    "scripts": {
        "dev": "ENV=development node --loader esm-module-alias/loader --no-warnings src/server.js",
        "preview": "ENV=production node --loader esm-module-alias/loader --no-warnings build/server.js",
        
    ...

	"aliases": {
        "@lib": "src/lib/"
    }
}
  • ajout de --loader esm-module-alias/loader --no-warnings
  • et la section aliases

Et dans /vite.config.js :

export default defineConfig({
    plugins: [sveltekit()],
    resolve: {
        alias: {
          '@lib': path.resolve('./src/lib')
        }
    }
});
  • ajout de alias

Le fichier src/server.js contient du code spécifique en fonction de son contexte d'exécution ("dev" ou "buildé") :

    if (isDev) {
        const { createServer: createViteServer } = await import('vite');

        const vite = await createViteServer({
            server: { middlewareMode: true },
            appType: 'custom'
        });

        app.use(vite.middlewares);
    } else {
        const { handler } = await import('./handler.js');
        app.use(handler);
    }

En mode "dev" il utilise Vite et en "buildé" il utilise le fichier build/handler.js généré par SvelteKit build en mode SSR.

Le fichier src/server.js est copié vers le dossier /build/ lors de l'exécution de pnpm run build.

J'ai testé le bon fonctionnement du POC dans un container Docker.

J'ai intégré au projet un deployment-playground : https://github.com/stephane-klein/poc-sveltekit-custom-server/tree/main/deployment-playground.

La suite...

Je souhaite rédiger cette note en anglais et la publier sur https://github.com/sveltejs/kit/discussions et https://old.reddit.com/r/sveltejs/ afin :

  • d'avoir des retours d'expérience
  • de découvrir des méthodes alternatives
  • et partager la méthode que j'ai utilisée, qui sera peut-être utile à d'autres développeurs Svelte 🙂

Update du 2025-05-29 à 00:07 - Je viens de publier ceci :


2025-05-29 : voir J'ai découvert la fonctionnalité SvelteKit Shared hooks init

Journal du mardi 03 décembre 2024 à 21:57 #javascript, #JaiDécouvert

Dans l'article "Dependency management fatigue, or why I forever ditched React for Go+HTMX+Templ" (from), #JaiDécouvert :

Datastar brings the functionality provided by libraries like Alpine.js (frontend reactivity) and htmx (backend reactivity) together, into one cohesive solution.

from

Cela me donne envie d'essayer ces technologies 🙂.

Pourquoi faire un refactoring de Nuxt.js vers HTMX ? 🤔 #WebDev, #htmx, #django, #Nuxt, #SvelteKit

En étudiant l'annonce Développeur(se) back-end en CDI de Brief.me j'ai été intrigué par :

Migrer notre front-end existant de Nuxt.js vers HTMX.

Je me suis demandé quelle est la motivation de passer d'un framework de type Nuxt.js, NextJS ou SvelteKit à htmx 🤔.

J'utilise SvelteKit depuis deux ans, qui est comparable Nuxt.js, principalement en mode SSR avec Hydration, et je suis totalement satisfait. Ma Developer eXperience est excellente. Je trouve ce framework minimaliste, conforme au principe Keep it simple, stupid! (KISS), et performant.

Après réflexion, j'ai réalisé que mon expérience de développeur (DX) serait moindre si j'héritais d'un backend codé dans un langage autre que Javascript : Python, PHP, Ruby, Golang

Et Brief.me semble être dans ce cas de figure :

Je me suis connecté à mon compte Brief.me et en regardant ce que me retourne Wappalyzer, je constate que le site est effectivement propulsé par Nuxt.js, VueJS.

En regardant ce qu'il se passe dans l'onglet Réseau de mon navigateur, je constate que https://app.brief.me est un site web de type SPA. Le contenu des articles est chargé via l'api https://www.brief.me/api/ qui est propulsée par Django REST framework.

Si je résume, la stack est la suivante : PostgreSQL => Django => Django REST framework <=> Nuxt.js => Rendu HTML via VueJS.

Je suppose que ce qui motive la migration de Nuxt.js vers HTMX est la suppression de couches.
Plus précisément, je suppose que l'équipe tech de Brief.me souhaite supprimer les couches suivantes :

Et utiliser simplement le système de template de Django en SSR pour afficher le contenu des articles et implémenter les quelques éléments dynamiques côté browser avec HTMX.
De mon point de vue, ceci a pour avantage de largement simplifier la stack, de simplifier le déploiement et d'accélérer le chargement des pages.

Ma conclusion : la librairie HTMX semble être un choix très pertinent quand elle est utilisée dans une stack non NodeJS.

Journal du vendredi 06 septembre 2024 à 17:05 #css, #SvelteKit, #skleinxyz

J'ai fait quelques recherches pour identifier quelle est la "meilleure" méthode pour implémenter un "Theme Switcher" pour un projet SvelteKit SSR.

J'ai trouvé cet article pertinent : How to implement a cookie-based dark mode toggle in SvelteKit.

En particulier, cette partie :

One might save the preference in the browser's local storage. With every page visit, we check with it if a theme is saved. This works well, but it will cause the website to flash because it takes some time to download and execute the JavaScript.

et un peu plus loin dans l'article :

After publishing this post, I was made aware that we can make the localStorage solution work also without flashing. Then we do not need any server-side logic and can also work with prerendered pages (such as a blog). In fact, the initial theme can be retrieved (via a media query or a localStorage value if it exists) in a script tag which is directly put into the body element of the app.html.

Voici une mise en pratique dans cet exemple : https://github.com/ScriptRaccoon/sveltekit-darkmode-toggler-localstorage/.

J'ai utilisé cette technique pour https://sklein.xyz.

Journal du jeudi 15 août 2024 à 20:00 #coding, #svelte, #SvelteKit, #icons, #JaiDécouvert, #JaiLu, #JaiDécidé

Depuis que j'utilise @tabler/icons-svelte pour intégrer des tabler-icons sur un projet SvelteKit SSR, je rencontre d'énormes problèmes de performance en mode développement (pnpm run dev).

Pour traiter le problème, j'ai essayé ce hack indiqué dans l'issue Slow experience in SvelteKit, mais cela ne fonctionne pas.

Toujours dans cette issue, #JaiDécouvert Iconify.

Je pense me souvenir d'avoir commencé à utiliser tabler-icons comme alternative Open source à Font Awesome.

J'ai lu la page page raconte l'histoire du projet et j'apprends que le projet s'est réellement lancé en 2020.

Iconify est devenu un projet Open source en 2021 :

In mid 2022 plans changed, thanks to people showing interest in sponsoring open source development.

The new plan is to:

  • Open source everything, encourage developers to create their own open source solutions that use Iconify.
  • Rely on sponsors to finance development.

-- from

Mais, d'après la page contributors le projet semble toujours très majoritairement développé par Vjacheslav Trushkin.

Je lis aussi :

Unlike fonts, it downloaded data only for icons used on page, rendered pixel perfect SVG. (from)

Par contre, je pense comprendre qu'Iconify n'est pas un projet de création d'icônes, mais un framework qui regroupe énormément d'icônes.

Par exemple, j'ai constaté qu'Iconify intègre entre autres :

Iconify propose des composants icônes pour Svelte : Iconify for Svelte.
Mais, je lis :

Loads icons on demand. No need to bundle icons, component will automatically load icon data for icons that you use from Iconify API. -- from

Cette technique « Loads icons on demand » ne me plait pas. Je souhaite réduire au maximum les latences dans mes applications web.

J'ai continué mes recherches.

#JaiLu Icon library for svelte? : sveltejs

#JaiDécouvert unplugin-icons (from).
unplugin-icons est un projet qui a commencé en 2021 et qui est basé sur Iconify.

Je constate que unplugin-icons propose une configuration SvelteKit.

J'ai testé et cela semble très bien fonctionner 🙂.

Le site https://icones.js.org permet de facilement copier-coller le code Javascript pour intégrer une icône. Par exemple, un click sur "Unplugin Icons" :

permet de copier :

import TablerChevronDown from '~icons/tabler/chevron-down'

Je ne constate aucun problème de lenteur au mode développement (pnpm run dev) et aucun chargement réseau externe des icônes dans la version de production.

#JaiDécidé d'adopter cette librairie pour gérer les icons de mes projets SvelteKit.

Journal du mercredi 01 mai 2024 à 12:05 #markdown, #mdsvex, #svelte, #SSR, #pensée, #veille-technologique, #JeMeDemande, #JaimeraisUnJour, #JaiDécouvert

#JeMeDemande si la librairie mdsvex me permet d'implémenter de manière agréable des nouveaux components qui ont la capacité d'aller chercher des données en backend, typiquement une base de données PostgreSQL.
J'aimerais que la requête soit décrite directement dans le markdown. Je souhaite aussi que le composant soit rendu seulement côté serveur (SSR).

J'aimerais pouvoir implémenter quelque chose comme :

# Mon titre

Mon paragraphe

``sql posts
SELECT title FROM posts ORDER BY created_at LIMIT 10
``

<ul>
    {#each posts as post}
        <li>{post}</li>
    {/each}
</ul>

(inspiration de https://evidence.dev/).

#JeMeDemande si mdsvex serait adapté pour cet objectif.

Je viens de voir ce thread Thoughts on Mdsvex moving away from Unified : sveltejs. Il contient un lien vers Penguin-flavoured markdown · pngwn/MDsveX · Discussion #293 · GitHub qui me semble intéressant #JaimeraisUnJour prendre le temps de le lire.

Autre thread What remark and rehype plugins are people using? · pngwn/MDsveX · Discussion #354 · GitHub.

#JeMeDemande si remark ou markdown-it serait mieux adapté pour atteindre mon objectif 🤔.

#JaiDécouvert (ou plutôt redécouvert) https://github.com/unifiedjs.

#JeMeDemande si je peux utiliser le moteur de template EJS pour parser et render le template présent dans le markdown pour ensuite lancer le rendu markdown.

Evidence semble implémenter un mécanisme qui ressemble à mon objectif et est codé en Svelte.