Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSS splitting #304

Open
revolunet opened this issue Sep 11, 2024 · 11 comments
Open

CSS splitting #304

revolunet opened this issue Sep 11, 2024 · 11 comments

Comments

@revolunet
Copy link
Collaborator

Hello :)

Le CSS du DSFR arrive à 800k, ça fait un gros paquet à télécharger/parser au démarrage.

Y-a-t-il des pistes pour améliorer ça ?

@l-vincent-l
Copy link

J’ai essayé sans succès de mettre purgecss, si certains ont réussi à le configurer dans un projet next pour qu’ils prennent en compte les composants utilisé je suis preneur.

@garronej
Copy link
Collaborator

Oui, c'est le problème avec ces feuilles de style monolithiques...

Pour remettre les choses en perspective, cela ne représente que 102k une fois minifié et compressé. Et en plus, ce n'est que pour la première visite, car ensuite, c'est mis en cache par le navigateur.

On obtient quand même un bon score Lighthouse :

image

@l-vincent-l, tu es sur Next.js avec App Router ?

Peut-être que PurgeCSS n'a pas fonctionné à cause de la présence de Sass dans le projet :

import "../assets/dsfr_plus_icons.scss";

C'est frustrant de devoir utiliser Sass simplement pour garantir que les feuilles de style soient chargées dans le bon ordre. Mais tant que ce problème n'est pas résolu, il n'y a pas vraiment d'alternative.

Je pourrais bien sûr importer les feuilles de style nécessaires composant par composant, mais cela introduirait des problèmes en cascade. Beaucoup de gens utilisent les classes CSS du DSFR pour créer leurs propres composants. Si j'opte pour cette approche, cela ne serait plus possible sans introduire une étape de build pour identifier quelles classes DSFR sont utilisées. C'est faisable, mais cela demande beaucoup de travail.

Cela dit, je serais curieux de voir si on peut faire fonctionner PurgeCSS.

Le compilateur CSS de Next.js fonctionne mieux avec le Page Router, et je n'ai pas besoin d'utiliser Sass dans ce mode.

Peut-être qu'il vaudrait la peine de tester ça sur l'app de démo Next Pages Router pour voir si l'approche PurgeCSS est viable...

@l-vincent-l
Copy link

l-vincent-l commented Sep 11, 2024

Le problème du poids je pense que c’est pas temps le chargement que le parsing, j’ai des reports de sentry sur des temps de chargement et de parsing de 2s.

J’utilise le PageRouter.

Je ne sais pas trop pourquoi ça n’a pas fonctionné, je suis débutant dans le développement front, j’ai tenté d’ajouter ce postcss.config.js pour ajouter les composants que j’utilise mais sans succès.

var path = require("path");

module.exports = {
  plugins: {
    "@fullhuman/postcss-purgecss": {
      content: [
        "./pages/**/*.{js,jsx,ts,tsx}",
        "./components/**/*.{js,jsx,ts,tsx}",
        path.join(
          __dirname,
          "node_modules/@codegouvfr/react-dsfr/Footer/Footer.js",
          "node_modules/@codegouvfr/react-dsfr/Header/Header.js",
          "node_modules/@codegouvfr/react-dsfr/MainNavigation/MainNavigation.js",
        ),
      ],
      defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
      safelist: ["html", "body"],
    },
  },
};

Pour info c’est sur ce projet https://gitlab.donnees.incubateur.anct.gouv.fr/infrastructure/generateur-fiches-anct/

@l-vincent-l
Copy link

Après avoir posté je me rends compte que le code était totalement foireux.

var path = require("path");

module.exports = {
  plugins: {
    "@fullhuman/postcss-purgecss": {
      content: [
        "./pages/**/*.{js,jsx,ts,tsx}",
        "./components/**/*.{js,jsx,ts,tsx}",
        path.join(
          __dirname,
          "node_modules/@codegouvfr/react-dsfr/Footer/Footer.js",
        ),
        path.join(
          __dirname,
          "node_modules/@codegouvfr/react-dsfr/Header/Header.js",
        ),
        path.join(
          __dirname,
          "node_modules/@codegouvfr/react-dsfr/MainNavigation/MainNavigation.js",
        ),
      ],
      defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
      safelist: ["html", "body"],
    },
  },
};

Fonctionne presque, j’obtiens un CSS de 150ko

@garronej
Copy link
Collaborator

garronej commented Sep 11, 2024

Deux secondes pour le parsing 😨 !!!

Je n'y crois pas, même sur une pomme de terre. Sentry n'y est pas.

En ce qui concerne le générateur de fiches ANCT, il n'y a pas de compression Gzip, du coup il y a litéralement une dixaine de Méga a télécharger!
Vous pouvez utiliser du webp pour vos images et réduire la résolution.

image

Rien qu'en appliquant ces deux optimisations, vous verrez des gains de performance bien plus significatifs que tout ce que nous pourrions obtenir avec de l'extraction CSS.

image

Vous voyez vous avez déjà 2.4Mo de l'API deux image pour un total de 3Mo et le CSS du DSFR pour a peut près 1Mo.

@garronej
Copy link
Collaborator

Fonctionne presque, j’obtiens un CSS de 150ko

Ok top!
A voir, çà peut probablement casser pas mal de truck mais c'est très prométeur en tout cas!

@l-vincent-l
Copy link

J’ai ajouté au script postbuild de mon package.json ça purgecss --css out/_next/static/css/*.css --content **/*.html --output out/_next/static/css/, ça fait passer le CSS de 818Kb à 164KB.

Je vais regarder pour les autres optimisations que tu m’as indiqué

@garronej
Copy link
Collaborator

@l-vincent-l While this is very intresting this will probably cause isue down the line.
There's a lot of css classes that can be added dynamically. I'm pretty sure that purgess can't predict what is actually needed and what isn't.

@l-vincent-l
Copy link

Yup,
I gave up, I noticed I had no border on table, because there's a data attribute data-fr-js-table added that's not catched by purgecss.

I tried with this purgecss.config.js

const purgeHtml = require("purgecss-from-html");

module.exports = {
  content: ["out/**/*.html", "out/**/*.js"],
  css: ["out/**/*.css"],
  extractors: [
    {
      extractor: purgeHtml,
      extensions: ["html"],
    },
  ],
  output: "out/_next/static/css/",
};

@enguerranws
Copy link
Collaborator

The JS part of the dsfr adds a lot of data-attributes on page load, and some CSS refers to those attributes.

That's a bummer.

But I think you could use dynamicAttributes or safeList option to list all this kind of attributes and make sure they will be left in the final CSS.

@mattboll
Copy link

À DossierFacile on utilise purgeCSS qui fait un bon nettoyage mais effectivement on a mis en place un safeList (de mémoire c'était juste les accordéons qui nous posaient problème mais on n'a pas de tableau)
notre config :

        safelist: [
          /-(leave|enter|appear)(|-(to|from|active))$/,
          /^(?!(|.*?:)cursor-move).+-move$/,
          /^router-link(|-exact)-active$/,
          /.*fr-accordion.*/,
          /.*fr-collapse.*/,
          /data-v-.*/
        ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants