codegouvfr / react-dsfr

🇫🇷 The French Government Design system React toolkit
https://react-dsfr.codegouv.studio
MIT License
406 stars 51 forks source link

Gatsby / Static Website Generator support ? #204

Open wiwski opened 10 months ago

wiwski commented 10 months ago

Est-ce qu'il est possible d'utiliser la librairie avec Gatsby - en vue de générer un Static Website ? En mode développement ça fonctionne très bien, mais une erreur survient lors du build.

L'erreur est dans le module start.js sur cette ligne : https://github.com/codegouvfr/react-dsfr/blob/36086ba1a682ac9a9c629399b8509421c4e40beb/src/start.ts#L26

J'appelle startReactDsfr dans le code de ma page Index :

...
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
...
startReactDsfr({ defaultColorScheme: "system" });
...

const IndexPage: React.FC<PageProps<DataProps>> = ({ data, path }) => {
    ...
}
wiwski commented 10 months ago

En suivant les instructions pour Next.js App Router, le build a fonctionné ! Je vous laisse fermé l'issue ou la laisser ouverte pour ajouter de la documentation sur ce framework ?

garronej commented 10 months ago

Salut @wiwski,

Je n'ai pas fait d'intégration spécifique pour gatsby mais je pense que tu peut t'en tirer simplement en garentissant que le startReactDsfr() ne soit appeler que sur le navigateur.

import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";

if (typeof window !== "undefined") {
  // Seulement sur le client
  startReactDsfr({ defaultColorScheme: "system" });
}

Sa ne sera pas tout a fait aussi clean qu'avec l'integration Next, c'est à dire que si l'utilisateur a son navigateur en dark mode, il va voir quellques milliseconde l'app en blanc puis ça va passer en dark mode.

Si tu veux on peut fournir une intégration spécifique import { startReactDsfr } from "@codegouvfr/react-dsfr/gatsby. C'est pas un problème, je ne savais juste pas que Gatsby etais utiliser dans l'état.

Si tu me fait un repo minimal avec React-DSFR pre set up je peut regarder.

wiwski commented 10 months ago

@garronej Merci pour ta réponse ! Il semble que mettre <StartDsfr /> dans la balise <Head> comme indiqué dans la doc pour Next.js App Router fait l'affaire. Je vous ferai un retour si jamais je vois un pb spécifique à Gatsby mais je ne vois pas quoi pour l'instant, à part peut-être la navigation (qui n'utilise pas le Link de next. A voir...) :slightly_smiling_face:

garronej commented 10 months ago

Ok super. Ca me surrprend beaucoup mais c'est cool si ça marche.
Il faut quand même que tu puisse dire a react-dsfr quelle lib de routing tu utilise si non tu va avoir des full reload a chaque chaque clique sur un link.
Je suis preneur pour un retour d'expérience, et de pouvoir envoyer un link vers ton repo pour les autres qui utiliserais Gatsby.

wiwski commented 10 months ago

@garronej du nouveau : Pour éviter les full reload sur les Link, j'ai adapté le module startDsfr et ça semble fonctionner :

"use client";

import { Link as GatsbyLink } from "gatsby";
import { startReactDsfr } from "@codegouvfr/react-dsfr/next-appdir";
import { RegisteredLinkProps } from "@codegouvfr/react-dsfr/link";
import { defaultColorScheme } from "./defaultColorScheme";

const Link = ({ ...props }: RegisteredLinkProps) => {
  const { ref, href, ...newProps } = props;
  return <GatsbyLink to={href || "#"} {...newProps} />;
};

declare module "@codegouvfr/react-dsfr/next-appdir" {
  interface RegisterLink {
    GatsbyLink: typeof Link;
  }
}

startReactDsfr({ defaultColorScheme, Link });

export function StartDsfr() {
  //Yes, leave null here.
  return null;
}

Il y a probablement des choses à adapter pour avoir une totale conversion des liens Next vers Gatsby. D'ailleurs si tu as des idées je suis preneur.

Je continuerai à poster si je vois des améliorations. Et je posterai le lien du repo quand il sera sur github (probablement cette semaine).

garronej commented 10 months ago

Salut @wiwski,

je pense que le mieux serais de faire un adapter pour Gatsby.

Par contre attend, je crois que tu n'a pas bien compris ce que react-dsfr permet par rapport au rooting.

https://react-dsfr.codegouv.studio/routing

En fait tu peut déclarer le Link component que tu utilise, react-dsfr va l'utiliser en interne et a chaque fois que tu va avoir un truck linkProps tu va retrouver le type de props pour ton composant link.
Ici GatsbyLink.

Ce que tu veux faire c'est:

import React from "react";
import ReactDOM from "react-dom/client";
import { startReactDsfr } from "@codegouvfr/react-dsfr/next-appdir";
import { Link } from "gatsby";  

declare module "@codegouvfr/react-dsfr/next-appdir" {
    interface RegisterLink { 
        Link: typeof Link;
    }
}

startReactDsfr({ 
    defaultColorScheme: "system", 
    Link 
});

export function StartDsfr() {
  //Yes, leave null here.
  return null;
}

...Tout simplement.
Après tu vera sur tes bouttons et tout tu va pouvoir passer les même props que ton link gatsby accepte.

Je suis très dessu parce que le fait que react-dsfr puisse fonctionner avec nimporte quelle librairie de routing client est une des choses dont je suis le plus fier sur cette lib mais maleureusement tout le monde est mistifier par l'augmentation du type global. 😢

wiwski commented 10 months ago

@garronej Hello @garronej, c'est ce que j'ai essayé au début mais la prop Link de startReactDsfr n'est pas compatible avec le Link de Gatsby, d'où le petit bout de code pour effectuer la conversion. Ca a l'air de très bien marcher.

Bravo pour les différentes reflexions autour de react-dsfr, c'est bien pensé :+1:

garronej commented 10 months ago

Merci!
Mais la prop link de startDsfr elle est contrainte par toi. C'est toi qui dit a react-dsfr ce qu'est ˋLinkˋ, pas l'inverse.
Il faudrais que je bootstrap un projet Gatsby mais il n'y a pas de raison qu'on ne pluissent pas utiliser le Link de gatsby juste comme on peut utiliser le Link de Next ou celui de React Routeur.

Tu as essayé précisément mon code?

wiwski commented 10 months ago

Hmm.. Je comprends ton point en lisant la doc du routing pour react-router qui utilise la même prop to que le Link Gatsby.

Oui j'ai essayé en remplaçant import { startReactDsfr } from "@codegouvfr/react-dsfr/cra"; par import { startReactDsfr } from "@codegouvfr/react-dsfr/next-appdir"; car je n'ai pas de module cra dans mon package.

Alors j'ai une erreur sur la prop Link de startReactDsfr:

Type 'typeof Link' is not assignable to type '(props: Omit<HTMLAnchorProps, "children"> & { children: ReactNode; }) => ReactNode'.
  Type 'typeof Link' provides no match for the signature '(props: Omit<HTMLAnchorProps, "children"> & { children: ReactNode; }): ReactNode'.ts(2322)
garronej commented 10 months ago

En effet, @wiwski, c'était une erreur de ma part.
J'avais oublié l'existence des composants de classe. En fait, le <Link /> de Gatsby est un composant de classe, et mon type qui gère l'inférence n'arrivait pas à extraire les props du Link de Gatsby.
Je viens de corriger cela.
Pour aggraver les choses, dans le snippet que je t'ai partagé, j'ai importé /cra qui n'existe plus depuis longtemps. (J'ai supprimé toutes les références dans la documentation).
À ce jour, nous avons trois adaptateurs :

En attendant, voici le snippet que tu peux implémenter pour obtenir les types corrects au niveau du routage (après avoir mis à jour @codegouvfr/react-dsfr à la dernière version 0.78.5) :

"use client";

import React from "react";
import { startReactDsfr } from "@codegouvfr/react-dsfr/next-appdir";
import { Link } from "gatsby";

declare module "@codegouvfr/react-dsfr/next-appdir" {
    interface RegisterLink {
        Link: typeof Link;
    }
}

startReactDsfr({
    defaultColorScheme: "system",
    Link
});

export function StartDsfr() {
    // Oui, laissez null ici.
    return null;
}

Now if you use a component that includes hyperlink you'll get the correct type.

import { Card } from "@codegouvfr/react-dsfr/Card";

const node = (
    <Card
        linkProps={{
            to: '#'
        }}
        title="Intitulé de la carte (sur lequel se trouve le lien)"
    />
);
wiwski commented 9 months ago

Salut @garronej, j'ai mis à jour à la dernière version et utilisé ton snippet et ça fonctionne très bien, merci !

Pour info, c'est toujours en phase initial de développement, mais le repo est dispo ici : https://github.com/betagouv/euphrosyne-digilab