La recherche est là

Sur un site statique, avoir un petit moteur de recherche, c’est la classe. Même si je ne poste pas de manière régulière ni intensive, ça peut vite devenir pénible de retrouver une note. Alors je n’imagine même pas les blogs plus anciens que le mien ou les sites plus fournis.

Mais il y a plus pénible encore que trouver une info dans ces conditions. Il y a trouver comment faire !

J’ai finalement fini par intégrer lunrjs, avec quelques magouilles. Mais pour y arriver, ce fut un parcours étonnamment compliqué.

Compliqué pour pas grand chose donc, pourquoi ?

Flash-back

D’abord il y a eu le post de Lord sur un projet jeune appelé Tinysearch.

Je me suis dit « chouette ». Et j’ai commencé à installer le compilateur rust, utiliser cargo pour les dépendances, suivre les étapes dans le post. De manière un peu décousue j’avoue, donc au premier essai, raté pour les dépendances, j’avais oublié de les installer. Mais une fois cet oubli réparé, niet. Tinysearch, même compilé me refusait de générer les fichiers. Avec une erreur cryptique qui flaire bon le soucis avec les libs intégrées à la compilation.

Tant pis me dis-je, j’y reviendrai plus tard, quand le projet sera stable. Et puis le coup des performances de malade, bon, pour le moment le soucis ne se pose pas.

Direction les libs en javascript proposées sur le site de Hugo.

Et donc lunrjs

Stupeur et tremblement ! Du node à installer ? Utiliser gulp, ou grunt pour générer un fichier intermédiaire ? Hors de questions !

Mais pourtant, le nom de lunrjs m’interpelle. Sur le papier, ça sonne bien. Mais il a fallu chercher longtemps pour trouver des utilisations sans installation d’outils tiers. Et encore, sur le premier lien trouvé (j’aurais du me méfier, un blog blindé de pubs …) était une blague : utilisation de CDN encouragée, javascript qui ferait meme saigner des yeux un débutant, direction à suivre pas claire … Encore un échec.

Puis, finalement, dans un dernier espoir vint le blog de Palant avec ce post. Exemple complet, compréhensible, fonctionnel. Un peu de tuning de mon côté1 et HOP : La recherche !

Petite remarque toutefois si vous suivez le blog de Palant : il manque un élément DOM de classe .main-inner. Pensez-y, sinon votre recherche plantera lamentablement (merci la console du navigateur web pour l’astuce).

Et ça donne quoi de mon côté ?

[
  {{- range $index, $page := (where .Site.RegularPages "Section" "in" .Site.Params.section_on_frontpage ) -}}
    {{- if gt $index 0 -}} , {{- end -}}
    {{- $entry := dict "uri" $page.RelPermalink "title" $page.Title -}}
    {{- $entry = merge $entry (dict "content" ($page.Plain | htmlUnescape)) -}}
    {{- $entry = merge $entry (dict "tags" $page.Params.tags) -}}
    {{- $entry | jsonify -}}
  {{- end -}}
]
<form id="search" class="search" role="search">
  <input type="search" id="search-input" class="search-input" placeholder="recherche">
</form>

<div class="nombre-resultats"></div>
<ul class="liste-resultats"></ul>

<script src="/js/lunr-2.3.7.min.js"></script> <!-- lunr.js library -->
<script src="/js/lunr.stemmer.support.min.js"></script>
<script src="/js/lunr.fr.min.js"></script>
<script src="/js/recherche.js"></script>

Là y’a quelques modifs planquées dans pas mal de lignes donc je ne vais pas tout mettre. Mais globalement j’ai précisé mes champs de recherche à lunr : title, content, tags. Et j’ai bricolé l’ajout des liens en liste, dans un <ul>, comme ce que j’avais vu sur le blog de Lord.

J’ai préféré cette solution simple à copier un bout de html à partir d’un élément déjà dans le DOM (le <template> dans le code d’origine) pour faire une grosse liste avec plein de texte (le résumé, retronqué via JS en plus …). J’ai désactivé le scrollIntoView() aussi. C’est affreux comme idée.

[outputs]
   home = ["html","rss","json"]

Une fois tout ça fait, même plus besoin de réfléchir, vu que Hugo va générer l’index tout seul, qu’il sera poussé avec les autres fichiés (et gzippé) et appellé uniquement pour la recherche. Sobre, pas trop gourmand, et à priori efficace.

Pour tout le js, on est à 60K en non compressé. L’index fait entre 79 et 80K en brut. Compressé, on passe respectivement à 13K et 30K. Et même si l’index finira par grossir au fur et à mesure, pour le moment, c’est très raisonnable. Pour les performances, on verra au vil du temps.

MàJ : 2 ans plus tard

Le poids de l’index est maintenant d’environ 181 Ko en brut et 67K en compressé. 20 articles (de tailles diverses) ont été publiés depuis la mise en place de la recherche, plusieurs mises à jour ont eu lieu.

Je trouve l’évolution très raisonnable. La rapidité de la recherche est toujours satisfaisante.

Fin de l’histoire

Je dois dire que j’ai été très tatillon. Je ne voulais pas spécialement installer de trucs en plus. Je préférais un outil prévu pour ça, et qui soit utilisable sans dépendance ni appel à des services tiers. Le tout sans être trop lourd. J’ai fini par y arriver.

Après, si vous êtes à l’aise avec node, gulp, grunt etc et que les installer ne vous gène pas, allez par voir la liste sur le site de Hugo. Même si ce n’est pas votre générateur, il y aura forcément des idées à prendre. Mais souvent à base de gros scripts, de node, modules npm à foison, etc.

Il y a quand même un truc qui me chiffonne. Les blogs statiques, pour certains, on dirait que c’est juste une mode. Parce que rajouter masse appels externes à coups de CDN, ou déployer des monstres d’outillage pour la recherche … meh. A mon sens on est loin de la philosophie minimaliste et économe en ressources … D’ailleurs, certains, lors de mes recherchent, conseillaient même à d’autres d’utiliser directement les recherches personnalisées google, pour ne pas « réinventer la roue ». Mouais.

Enfin maintenant, vous saurez dans quel monde vous mettez les pieds.


  1. Indexation de tous les articles, mais exclusion des pages « En vrac » et « à propos ». L’affichage final est aussi largement modifié. ↩︎