Vue normale

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
Hier — 26 août 2025Flux principal

Google lance par surprise un prof de langues gratuit qui va faire mal à Duolingo

26 août 2025 à 18:00

Lancé en 2006, le service Google Traduction va connaître une de ses plus grandes évolutions dans les prochains jours. Google, grâce aux grands modèles de langage, va intégrer un concurrent de Duolingo à l'application. Gemini Live va aussi permettre de discuter avec une personne qui ne parle pas la même langue

À partir d’avant-hierFlux principal

ChatGPT bientôt à 5 euros par mois ? OpenAI dévoile sa nouvelle stratégie

19 août 2025 à 10:35

ChatGPT OpenAI

D'abord lancée en Inde, la formule ChatGPT Go, qui permet de poser plus de questions à GPT-5 que dans la version gratuite, va faire son arrivée dans d'autres pays. OpenAI pourrait la lancer en France pour inciter plus d'utilisateurs à payer pour ChatGPT.

Comment j'ai divisé par 10 le temps de génération de mon site Hugo

Par : Korben
11 août 2025 à 13:46

Vous ne le savez peut-être pas, mais le site sur lequel vous êtes actuellement est un site 100% statique. Je gère le contenu côté back avec un CMS en PHP (rédaction, édition, workflow), mais la partie publique n’exécute aucun PHP : pas de base de données, juste des fichiers HTML/CSS/JS et des images. Et tout ça est généré à partir de fichiers Markdown avec Hugo.

Et optimiser tout ça c’est pas de la tarte car si vos templates sont mal pensés, Hugo peut mettre une plombe à générer le site. Entre partiels recalculés pour rien, boucles trop larges et images retraitées à chaque passage, on flingue les perfs sans s’en rendre compte.

Et c’était mon cas au début. Je regardais avec envie les mecs qui sortaient un build en moins d’une seconde tout en restant réaliste car j’ai quand même environ 60 000 pages à générer. Au final, je suis passé de plusieurs heures de build à environ 5 minutes en optimisant les templates, le cache et le pipeline d’assets.

Car oui, Hugo sait générer la plupart des sites en quelques secondes si vos templates sont propres. Depuis la “million pages release”, les builds sont streamés et la mémoire mieux gérée. Alors si votre génération est lente, c’est qu’il y a (souvent) un souci côté templates.

Tout ceci est encore en cours de tests, et ce n’est pas parfait donc il est possible que ça change à l’avenir et vous faites peut-être autrement (dans ce cas ça m’intéresse !!). Bref, voici mon retour d’XP sous forme de conseils pour transformer, vous aussi, votre escargot en fusée 🚀.

Partials - Cachez-moi tout ça (bien)

Hugo sait mettre en cache le rendu d’un partial. Utilisez partialCached (alias de partials.IncludeCached) partout où la sortie est identique sur beaucoup de pages.

{{/* baseof.html - Template de base optimisé */}}
{{ partialCached "header.html" . }}
{{ partialCached "nav.html" . }}
{{ partialCached "footer.html" . }}

Le truc malin, c’est d’utiliser des variantes (clés) pour changer le cache selon le contexte. Attention quand même car ces arguments de variante ne sont pas passés au partial. En réalité, ils servent uniquement à nommer l’entrée de cache. Si vous devez passer plus de données au partial, mettez-les dans le context via un dict.

{{/* Sidebar: cache par section et par numéro de page */}}
{{ $variant := printf "%s|p%d" .Section (cond .Paginator .Paginator.PageNumber 1) }}
{{ partialCached "sidebar.html" . $variant }}

{{/* Pagination: on passe un contexte enrichi, et on varie par numéro de page */}}
{{ $opts := dict "showCounts" true }}
{{ partialCached "pagination-taxonomy.html" (dict "Page" . "Opts" $opts) .Paginator.PageNumber }}

{{/* Bannières: cache par langue */}}
{{ partialCached "article/patreon-support-banner.html" . .Lang }}

Gardez aussi vos variantes stables et petites (ex. .Lang, .Section, .Title, .Paginator.PageNumber), sinon, vous allez exploser le cache pour rien.

Réf. : partials.IncludeCached / partialCached.

Hugo Pipes - Minify, fingerprint, bundle (et JS qui dépote)

Pour le basique, pas besoin de Gulp/Webpack car Hugo a tout ce qu’il faut, et c’est très rapide. Voici mon bundle CSS unique :

{{/* head/css.html - Bundle CSS optimisé */}}
{{- $styles := slice
"css/reset.css"
"css/main.css"
"css/components/home-cards.css"
"css/components/patreon-card.css"
"css/components/article-content-images.css"
"css/components/lazy-loading.css"
"css/youtube-placeholder.css"
-}}
{{- $cssResources := slice -}}
{{- range $styles -}}
{{- with resources.Get . -}}
{{- $cssResources = $cssResources | append . -}}
{{- end -}}
{{- end -}}

{{/* Concat + minify + fingerprint */}}
{{- $cssBundle := resources.Concat "css/bundle.css" $cssResources | minify | fingerprint -}}

{{/* Preload + feuille finale avec SRI */}}
<link rel="preload" as="style" href="{{ $cssBundle.RelPermalink }}" integrity="{{ $cssBundle.Data.Integrity }}" crossorigin="anonymous">
<link rel="stylesheet" href="{{ $cssBundle.RelPermalink }}" integrity="{{ $cssBundle.Data.Integrity }}" crossorigin="anonymous">

Je regroupe tout avec resources.Concat, puis minify et fingerprint (SRI + cache-busting). Le preload déclenche le chargement au plus tôt, et le link classique prend le relais.

Côté JavaScript, j’utilise js.Build (esbuild) et je bascule les sourcemaps selon l’environnement :

{{/* assets/js/app.js est mon point d'entrée */}}
{{ $opts := dict
"minify" (not hugo.IsDevelopment)
"targetPath" "js/app.js"
"sourceMap" (cond hugo.IsDevelopment "inline" "") /* inline en dev, rien en prod */
}}
{{ $js := resources.Get "js/app.js" | js.Build $opts | fingerprint }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous" defer></script>

Réfs : Minify, Fingerprint/SRI, js.Build (esbuild), resources.Concat.

Images - Cloudflare Image Resizing + lazy loading intelligent

J’ai également une approche hybride concernant la gestion des images. J’utilise Cloudflare Image Resizing qui génère les variantes côté CDN, et un partial Hugo prépare le srcset + LCP propre.

{{/* partials/responsive-image.html */}}
{{/* Paramètres attendus via dict:
- imageURL (string, chemin vers l'image d'origine dans /static)
- imgWidth, imgHeight (int)
- alt (string)
- class (string optionnelle)
- isLCP (bool) */}}

{{ $imageURL := .imageURL }}
{{ $imgWidth := .imgWidth }}
{{ $imgHeight := .imgHeight }}
{{ $alt := .alt | default "" }}
{{ $class := .class | default "" }}
{{ $isLCP := .isLCP | default false }}

{{ $widths := slice 320 640 960 1280 1920 }}
{{ $qualityMap := dict "320" 85 "640" 85 "960" 88 "1280" 90 "1920" 92 }}
{{ $srcset := slice }}

{{ range $w := $widths }}
{{ if or (eq $imgWidth 0) (ge $imgWidth $w) }}
{{ $q := index $qualityMap (printf "%d" $w) }}
{{ $srcset = $srcset | append (printf "/cdn-cgi/image/width=%d,quality=%d,f=avif%s %dw" $w $q $imageURL $w) }}
{{ end }}
{{ end }}

{{ if $isLCP }}
<img
src="/cdn-cgi/image/width=1280,quality=90,f=avif{{ $imageURL }}"
srcset="{{ delimit $srcset ", " }}"
sizes="(max-width: 1280px) 100vw, 1280px"
fetchpriority="high"
width="{{ $imgWidth }}" height="{{ $imgHeight }}"
alt="{{ $alt }}" class="{{ $class }}">
{{ else }}
{{/* LazySizes: placeholder + data-attrs et data-sizes='auto' */}}
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 {{ $imgWidth }} {{ $imgHeight }}'%3E%3C/svg%3E"
data-src="/cdn-cgi/image/width=1280,quality=90,f=avif{{ $imageURL }}"
data-srcset="{{ delimit $srcset ", " }}"
data-sizes="auto"
loading="lazy"
width="{{ $imgWidth }}" height="{{ $imgHeight }}"
alt="{{ $alt }}" class="lazyload {{ $class }}">
{{ end }}

Comme vous pouvez le voir, j’adapte la qualité selon la plateforme (85% pour mobile / 92% pour desktop), le format AVIF par défaut, et pour l’image LCP, je mets fetchpriority="high" et pas de lazy.

Voici un exemple d’appel :

{{ partial "responsive-image.html" (dict
"imageURL" .Params.featured_image
"imgWidth" 1280
"imgHeight" 720
"alt" .Title
"class" "article-cover"
"isLCP" true
) }}

Cache des ressources - Le secret des rebuilds rapides

Configurez aussi les caches pour éviter de retraiter à chaque build. Le plus important c’est le cache permanent pour les images et autres assets traités.

# hugo.toml
[caches]
[caches.getJSON]
dir = ":cacheDir/:project"
maxAge = "1h"
[caches.getCSV]
dir = ":cacheDir/:project"
maxAge = "1h"
[caches.images]
dir = ":resourceDir/_gen"
maxAge = -1 # NE JAMAIS expirer
[caches.assets]
dir = ":resourceDir/_gen"
maxAge = -1

Et en cas de besoin, pour forcer un refresh : hugo server --ignoreCache.

Réf. : Configure file caches.

Minifiez tout ce qui bouge (config complète)

J’ai aussi ajouté dans mon hugo.toml, une config de minification que voici :

# Minification HTML/CSS/JS/JSON/SVG/XML
[minify]
disableCSS = false
disableHTML = false
disableJS = false
disableJSON = false
disableSVG = false
disableXML = false
minifyOutput = true

[minify.tdewolff]
[minify.tdewolff.html]
keepWhitespace = false
[minify.tdewolff.css]
keepCSS2 = true
precision = 0
[minify.tdewolff.js]
keepVarNames = false
version = 2022
precision = 0

Avec hugo --minify, je gagne ~25% sur le HTML final (variable selon le site).

Réf. : Minify (config).

Organisation des templates - site.RegularPages est votre ami

En régle générale, c’est mieux d’éviter de boucler sur des pages inutiles (taxonomies, terms…). Utilisez aussi site.RegularPages plutôt que .Site.Pages.

{{/* sidebar/recent-posts.html - Articles récents optimisés */}}
{{ $recentPosts := first 6 (where site.RegularPages "Type" "posts") }}
{{ range $recentPosts }}
<li>
<a href="{{ .RelPermalink }}">
{{ $featuredImage := partial "get-image-optimized.html" (dict "page" .) }}
{{ if $featuredImage }}
<img src="{{ $featuredImage.RelPermalink }}" loading="lazy" width="80" height="60" alt="">
{{ else }}
<img src="/img/default-article-image.webp" loading="lazy" width="80" height="60" alt="">
{{ end }}
<h4>{{ truncate 40 .Title }}</h4>
</a>
</li>
{{ end }}

Réfs : site.RegularPages.

Et voici le petit helper image que j’utilise pour éviter les nil :

{{/* partials/get-image-optimized.html */}}
{{ $page := .page }}
{{ $imageName := .imageName | default $page.Params.featured_image }}

{{ $img := false }}
{{ if $imageName }}
{{ with $page.Resources.GetMatch $imageName }}
{{ $img = . }}
{{ end }}
{{ end }}

{{ return $img }}

Configuration globale - Chaque détail compte

Voici également quelques réglages utiles dans mon hugo.toml :

# Désactiver ce qu'on n'utilise pas
disableKinds = ["section"]

# Pagination moderne (Hugo ≥ 0.128)
[pagination]
pagerSize = 39 # 39 articles par page

# Traitement d'images
[imaging]
quality = 80
resampleFilter = "Lanczos"

# Optimisations de build
[build]
writeStats = false
noJSConfigInAssets = true
useResourceCacheWhen = "always"

# Mounts: exclure fichiers lourds
[module]
[[module.mounts]]
source = "content"
target = "content"
excludeFiles = ["**/*.zip", "**/*.log", "**/backup/**", "**/archives/**", "**/exports/**"]
[[module.mounts]]
source = "static"
target = "static"
excludeFiles = ["**/*.zip", "**/*.log", "**/backup/**", "**/archives/**"]

Je mets aussi un timeout large (timeout = "600s") et j’ignore certains warnings verbeux (ignoreLogs = ['warning-goldmark-raw-html']). Et pour la pagination, pagerSize a aussi remplacé les vieux réglages (bon à savoir si vous migrez).

Réf. : PagerSize, Pagination.

Les flags CLI utiles

Perso, j’utilise uniquement les flags suivants quand je lance Hugo :

  • Nettoyage : hugo --gc --cleanDestinationDir pour virer l’obsolète et garder public/ clean.
  • Dev rapide : gardez hugo server tel quel. --disableFastRender seulement si un glitch l’exige. --renderToMemory peut accélérer (au prix de la RAM).
  • Profiler de templates : hugo --templateMetrics --templateMetricsHints liste les templates lents et où placer vos partialCached. C’est comme ça que j’ai vu que ma sidebar coûtait une plombe.

Conditionnez ce que vous chargez

Selon la page, j’adapte aussi mon code. L’image LCP avec fetchpriority="high" (pour éviter le lazy), le reste en lazy + placeholder SVG qui respecte les dimensions (zéro layout shift). Et pour le JS, defer partout et pas de scripts inutiles sur les pages qui n’en ont pas besoin.

Le pattern qui tue - partialCached + variantes calculées

Mon combo préféré, selon le contexte c’est celui-ci :

{{/* Home: variante par numéro de page */}}
{{ partialCached "pagination-home.html" . (cond .Paginator .Paginator.PageNumber 1) }}

{{/* Grilles darticles: variante par (page, index de groupe) */}}
{{ partialCached "articles-grid.html"
(dict "articles" $groupArticles "Site" $.Site)
(printf "p%d|g%d" $paginator.PageNumber $groupIndex) }}

{{/* Éléments vraiment statiques: pas de variante */}}
{{ partialCached "footer.html" . }}

Il faut comme ça trouver le bon équilibre. C’est à dire avoir assez de variantes pour éviter les recalculs, mais pas trop, sinon votre cache devient inutile.

Et en bonus - Ma checklist express !

  • Remplacer les partial chauds par partialCached + variantes propres (au minimum : header, footer, nav, sidebar).
  • Pipeline assets : resources.Concatminifyfingerprint (SRI).
  • Images : Cloudflare Image Resizing (ou .Resize Hugo) + lazy intelligent + placeholder SVG.
  • getJSON : config de cache (maxAge) et --ignoreCache en dev.
  • --templateMetrics + --templateMetricsHints pour viser les pires templates.
  • Pagination : passer à [pagination].pagerSize si vous migrez.
  • Utiliser site.RegularPages au lieu de .Site.Pages dans les boucles.
  • Module mounts avec excludeFiles pour éviter que Hugo scanne backups/archives.
  • Prod : --gc + --cleanDestinationDir + --minify.
  • Cache permanent pour images/assets (maxAge = -1).

Voilà. Avec tout ça, je suis passé de plusieurs heures à quelques minutes pour ~60 000 pages. Les clés : partialCached partout où la sortie ne bouge pas, un bundle CSS/JS propre avec fingerprint/SRI, et site.RegularPages pour ne pas trimbaler les taxonomies dans les boucles.

N’oubliez pas de lancer hugo --templateMetrics --templateMetricsHints pour trouver ce qui coûte cher lors de la génération. Vous verrez, dans 90% des cas c’est un partial appelé 10 000 fois non mis en cache, ou une boucle sur .Site.Pages trop large. Réparez ça, et votre build respira de nouveau.

Et si après tout ça votre build met encore plus de 10 s pour builder moins de 1000 pages, c’est qu’il y a un loup dans vos templates. Réduisez la surface des boucles, chassez les recalculs, et mettez partialCached partout où c’est pertinent !

Bon courage !

GoSearch - 18 milliards de mots de passe compromis à portée de terminal

Par : Korben
8 août 2025 à 16:05

18 milliards, c’est le nombre de mots de passe compromis auxquels GoSearch peut accéder avec une simple clé API BreachDirectory. Et ce n’est que la partie émergée de l’iceberg de cet outil OSINT qui a récemment été salué dans la newsletter OSINT pour son approche innovante de la recherche d’empreintes numériques.

Vous vous souvenez de Sherlock, cet outil Python qui permettait de chercher des pseudos sur différentes plateformes ? Et bien GoSearch, c’est comme si Sherlock avait pris des stéroïdes et appris le Go. En effet, le développeur ibnaleem a créé ce projet au départ pour apprendre le langage Go, mais il s’est rapidement transformé en un véritable projet communautaire.

La différence fondamentale avec Sherlock c’est d’abord sa vitesse. Le Go se compile en binaire et utilise la concurrence de manière native, ce qui rend les recherches exponentiellement plus rapides. Mais surtout, GoSearch a résolu le problème majeur de Sherlock c’est à dire les faux négatifs. Quand Sherlock vous dit qu’un username n’existe pas alors qu’il est bien là, GoSearch le trouve. Et pour les résultats incertains, plutôt que de vous induire en erreur, il préfère les afficher en jaune pour vous signaler qu’il y a peut-être un doute.

Concrètement, GoSearch ne se contente pas de scanner plus de 300 sites web. Il accède aussi à 900 000 identifiants compromis via l’API HudsonRock’s Cybercrime Intelligence, 3,2 milliards via ProxyNova, et ces fameux 18 milliards via BreachDirectory si vous avez une clé API. Et quand il trouve des hashes de mots de passe, il tente de les cracker avec Weakpass, avec un taux de réussite proche de 100% selon le développeur (ahem…).

L’installation est ridiculement simple pour un outil aussi puissant :

go install github.com/ibnaleem/gosearch@latest

Ensuite, une recherche basique :

gosearch -u [username] --no-false-positives

Le flag --no-false-positives est important puisqu’il filtre les résultats pour ne montrer que ceux dont GoSearch est certain. Par exemple, pour une recherche approfondie avec BreachDirectory :

gosearch -u [username] -b [API-KEY] --no-false-positives

Ce qui est cool, c’est que GoSearch ne se limite pas aux pseudos. Il cherche aussi les domaines associés en testant les TLDs classiques (.com, .net, .org, etc.). Et si vous n’avez pas de pseudo précis, vous pouvez même utiliser username-anarchy pour générer des variantes à partir d’un nom et prénom.

Attention toutefois, sous Windows, Windows Defender peut parfois marquer GoSearch comme malware. C’est un faux positif et le code source est entièrement accessible sur GitHub pour vérification.

GoSearch est particulièrement efficace pour les enquêtes de sécurité et de confidentialité. Les entreprises peuvent par exemple l’utiliser pour vérifier si leurs employés ont des comptes compromis, les particuliers pour auditer leur propre empreinte numérique, et les chercheurs en sécurité pour leurs investigations OSINT.

En plus, le projet évolue constamment et les dev envisagent d’ajouter des fonctionnalités comme des options pour n’afficher que les résultats confirmés ou prioriser la détection des faux négatifs selon les besoins. Maintenant, pour ceux qui cherchent des alternatives, il existe Gopher Find (aussi en Go), Maigret, WhatsMyName ou le récent User Searcher qui prétend couvrir 2000+ sites. Mais GoSearch reste le plus équilibré entre vitesse, précision et accès aux bases de données d’identifiants compromis.

Pour le tester, c’est par ici !

La Radeon RX 9060 XT s’impose comme la référence pour du 1080p

28 juillet 2025 à 07:30

Radeon RX 9060 XT 16 Go ReaperVous cherchez une carte graphique équilibrée pour le 1080p à petit prix ? La Radeon RX 9060 XT 16 Go est la grande gagnante du moment.

Cet article La Radeon RX 9060 XT s’impose comme la référence pour du 1080p a été publié en premier par GinjFo.

❌
❌