[{"data":1,"prerenderedAt":486},["ShallowReactive",2],{"i-ic:outline-arrow-upward":3,"Footer_afPiwGMwNiEyV4syWzw87ovzxHAgs4iwKtCn4zqBf8E":8,"\u002Farticles\u002Fvinext-1-nextjs-sur-vite":16,"i-material-symbols:home":459,"i-material-symbols:search":461,"i-material-symbols:ios-share":463,"Brand_bAcjTzQpW6OVpFK319jfMki97vH1GrZiqHmeI7Xg4o":465,"AppImg_IyX8AyXnvzxMhkQHFSbpXBHOtGi2gizwCEtOpbCcVEk":470,"ArticleDetails_XokQNcWZZazondsKaBGUloum49UzpExEOp3FqGB0OY":475},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"m4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8z\"\u002F>",["Island",9],{"key":10,"result":11},"Footer_afPiwGMwNiEyV4syWzw87ovzxHAgs4iwKtCn4zqBf8E",{"head":12},{"style":13},[14],{"innerHTML":15},":where(.i-mdi\\:github){display:inline-block;width:1em;height:1em;background-color:currentColor;-webkit-mask-image:var(--svg);mask-image:var(--svg);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;--svg:url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33s1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2'\u002F%3E%3C\u002Fsvg%3E\")}",{"id":17,"title":18,"author":19,"body":22,"description":451,"extension":452,"meta":453,"navigation":236,"path":454,"publicationDate":455,"seo":456,"stem":457,"__hash__":458},"articles\u002Farticles\u002Fvinext-1-nextjs-sur-vite.md","Vinext 1.0 : faire tourner une app Next.js sur Vite, pour de vrai",{"name":20,"url":21},"@patrickfaramaz ","https:\u002F\u002Ftwitter.com\u002Fpatrickfaramaz",{"type":23,"value":24,"toc":444},"minimark",[25,29,32,37,45,48,71,82,85,92,96,99,102,105,108,112,115,122,315,326,333,336,339,343,346,357,360,367,371,440],[26,27,28],"p",{},"En février, Cloudflare racontait comment un ingénieur et un modèle d'IA avaient reconstruit Next.js sur Vite en une semaine, pour environ 1 100 dollars de tokens. Le projet s'appelait vinext (prononcez « vee-next »), et beaucoup d'entre nous l'ont rangé dans la case « démo IA impressionnante, à revoir plus tard ».",[26,30,31],{},"Plus tard, c'est maintenant. Le 28 septembre 2026, Cloudflare a annoncé vinext 1.0, suivi d'un premier patch le 1er octobre. Le discours a changé : moins de prouesse IA, plus de compatibilité, de cache et de tests. Le projet devient sérieux et non plus une annonce marketing.",[33,34,36],"h2",{"id":35},"ce-qui-change-par-rapport-à-nextjs","Ce qui change par rapport à Next.js",[26,38,39,40,44],{},"Si vous avez déjà déployé du Next.js ailleurs que chez Vercel, vous connaissez le problème. L'outillage est maison, et pour tourner sur Cloudflare, Netlify ou AWS Lambda, il faut remodeler la sortie de ",[41,42,43],"code",{},"next build",". C'est le rôle d'OpenNext, et Cloudflare, qui y contribue, reconnaît que c'est fragile : chaque version de Next.js peut tout casser.",[26,46,47],{},"Sans parler d'un déploiement full Node.js sur plusieurs conteneurs où le partage de cache (ISR) est littéralement un enfer.",[26,49,50,51,54,55,58,59,62,63,66,67,70],{},"Vinext prend le problème par l'autre bout. Ce n'est pas un adaptateur, c'est une réimplémentation de l'API de Next.js sous forme de plugin Vite. Vos dossiers ",[41,52,53],{},"app\u002F"," ou ",[41,56,57],{},"pages\u002F",", vos composants et la plupart des imports ",[41,60,61],{},"next\u002F*"," restent en place. C'est Vite qui gère le dev et le build : les plugins Vite marchent, mais les plugins webpack et les réglages internes du build Next.js ne se reportent pas automatiquement. Si une app s’appuie sur ",[41,64,65],{},"@svgr\u002Fwebpack"," ou un loader custom, il faut l’équivalent Vite (",[41,68,69],{},"vite-plugin-svgr",", etc.)",[26,72,73,74,77,78,81],{},"Côté déploiement, Cloudflare Workers est la cible principale, avec une sortie Node standalone (",[41,75,76],{},"output: \"standalone\"",") et des adaptateurs pour les autres hébergeurs. Bonus appréciable : en dev, votre code serveur peut tourner dans le runtime de Workers, avec accès direct aux services Cloudflare, là où ",[41,79,80],{},"next dev"," reste cantonné à Node.",[26,83,84],{},"Sur les perfs, les seuls chiffres publiés datent de février : un build environ 4 fois plus rapide et un bundle client environ 57 % plus léger que Next.js, mesurés sur une seule app de test. Cloudflare lui-même invite à y voir une tendance, et je n'ai pas trouvé de benchmark mis à jour pour la 1.0.",[26,86,87,88,91],{},"Tout ne passe pas. Vinext vise l'API stable de Next.js 16, pas chaque feature expérimentale. Cache Components et Partial Prerendering restent incomplets, et l'optimisation des images et des fonts au build ne reproduit pas tout ce que fait Next.js. Sur Cache Components, Cloudflare assume : la plupart des équipes interrogées ne s'en servaient pas, donc le support de ",[41,89,90],{},"\"use cache\""," reste limité. Côté compatibilité, le dashboard public, qui fait tourner chaque nuit les tests de Next.js contre vinext, affichait au 6 octobre 99,7 % de réussite sur les fonctionnalités que vinext dit supporter.",[33,93,95],{"id":94},"le-pages-router-la-demande-que-cloudflare-a-entendue","Le Pages Router, la demande que Cloudflare a entendue",[26,97,98],{},"Au lancement, le Pages Router existait mais faisait figure de parent pauvre. En mars, quand un utilisateur demande le support d'une vieille API du Pages Router, un mainteneur admet qu'une bonne partie des fonctionnalités de ce router ne marche pas encore correctement.",[26,100,101],{},"Ça compte, parce que les applis Pages Router sont souvent anciennes et grosses, et que les migrer vers l'App Router n'a rien d'un après-midi de refacto. Cloudflare le reconnaît dans l'annonce : beaucoup de clients restent attachés au Pages Router, et l'équipe ne voulait pas d'un outil réservé aux dernières features de l'App Router.",[26,103,104],{},"La 1.0 supporte donc les deux routers, et même les applis qui mélangent les deux, avec middleware, API routes et navigation côté client. Tout n'est pas parfait : des bugs Pages Router remontent encore, et certains ont été corrigés dès le premier patch. Mais on est loin de l'état de mars.",[26,106,107],{},"L'autre grosse demande de la communauté, c'était le pré-rendu au build. La 1.0 y répond aussi, et ça nous amène à l'ISR.",[33,109,111],{"id":110},"lisr-expliqué-simplement","L'ISR, expliqué simplement",[26,113,114],{},"L'ISR (Incremental Static Regeneration), c'est un compromis entre site statique et rendu à chaque requête. Une page est générée une fois, stockée, puis servie depuis le cache. Quand elle devient périmée, le visiteur reçoit encore l'ancienne version pendant qu'une nouvelle est générée en arrière-plan. Vous pouvez aussi forcer la régénération à la demande, par exemple après une mise à jour dans votre CMS. C'est l'une des forces de Next.js !",[26,116,117,118,121],{},"Vinext reprend exactement les conventions de Next.js. Avec le Pages Router, la durée de vie se règle dans ",[41,119,120],{},"getStaticProps()"," :",[123,124,129],"pre",{"className":125,"code":126,"language":127,"meta":128,"style":128},"language-tsx shiki shiki-themes synthwave-84","\u002F\u002F pages\u002Findex.tsx\nexport async function getStaticProps() {\n  return {\n    props: { generatedAt: new Date().toISOString() },\n    revalidate: 60,\n  };\n}\n\nexport default function Page({ generatedAt }: { generatedAt: string }) {\n  return \u003Cp>Generated at {generatedAt}\u003C\u002Fp>;\n}\n","tsx","",[41,130,131,140,161,170,204,219,225,231,238,275,310],{"__ignoreMap":128},[132,133,136],"span",{"class":134,"line":135},"line",1,[132,137,139],{"class":138},"sjThu","\u002F\u002F pages\u002Findex.tsx\n",[132,141,143,147,150,153,157],{"class":134,"line":142},2,[132,144,146],{"class":145},"scrqX","export",[132,148,149],{"class":145}," async",[132,151,152],{"class":145}," function",[132,154,156],{"class":155},"sgRlq"," getStaticProps",[132,158,160],{"class":159},"soy-K","() {\n",[132,162,164,167],{"class":134,"line":163},3,[132,165,166],{"class":145},"  return",[132,168,169],{"class":159}," {\n",[132,171,173,177,181,184,187,189,192,195,198,201],{"class":134,"line":172},4,[132,174,176],{"class":175},"sqjNi","    props",[132,178,180],{"class":179},"s2hdG",":",[132,182,183],{"class":159}," { ",[132,185,186],{"class":175},"generatedAt",[132,188,180],{"class":179},[132,190,191],{"class":145}," new",[132,193,194],{"class":155}," Date",[132,196,197],{"class":159},"().",[132,199,200],{"class":155},"toISOString",[132,202,203],{"class":159},"() },\n",[132,205,207,210,212,216],{"class":134,"line":206},5,[132,208,209],{"class":175},"    revalidate",[132,211,180],{"class":179},[132,213,215],{"class":214},"sSmKr"," 60",[132,217,218],{"class":159},",\n",[132,220,222],{"class":134,"line":221},6,[132,223,224],{"class":159},"  };\n",[132,226,228],{"class":134,"line":227},7,[132,229,230],{"class":159},"}\n",[132,232,234],{"class":134,"line":233},8,[132,235,237],{"emptyLinePlaceholder":236},true,"\n",[132,239,241,243,246,248,251,254,257,260,262,264,266,268,272],{"class":134,"line":240},9,[132,242,146],{"class":145},[132,244,245],{"class":145}," default",[132,247,152],{"class":145},[132,249,250],{"class":155}," Page",[132,252,253],{"class":159},"({ ",[132,255,186],{"class":256},"sH7Js",[132,258,259],{"class":159}," }",[132,261,180],{"class":145},[132,263,183],{"class":159},[132,265,186],{"class":175},[132,267,180],{"class":145},[132,269,271],{"class":270},"sRQ1T"," string",[132,273,274],{"class":159}," }) {\n",[132,276,278,280,283,286,289,292,295,297,300,303,305,307],{"class":134,"line":277},10,[132,279,166],{"class":145},[132,281,282],{"class":155}," \u003C",[132,284,26],{"class":285},"sfE7D",[132,287,288],{"class":155},">",[132,290,291],{"class":159},"Generated at ",[132,293,294],{"class":145},"{",[132,296,186],{"class":175},[132,298,299],{"class":145},"}",[132,301,302],{"class":155},"\u003C\u002F",[132,304,26],{"class":285},[132,306,288],{"class":155},[132,308,309],{"class":159},";\n",[132,311,313],{"class":134,"line":312},11,[132,314,230],{"class":159},[26,316,317,318,321,322,325],{},"Ici, la page est régénérée au plus toutes les 60 secondes. Côté App Router, on retrouve ",[41,319,320],{},"revalidatePath()"," et ",[41,323,324],{},"revalidateTag()"," pour invalider à la demande.",[26,327,328,329,332],{},"Où est stocké ce cache ? Il passe par des adaptateurs, et sur Cloudflare la doc recommande le Workers Response Store. Un piège à connaître : avec cet adaptateur, ",[41,330,331],{},"res.revalidate()"," du Pages Router n'invalide pas encore les pages stockées. L'appel peut aboutir sans changer ce que voient les visiteurs ; l'ISR sur intervalle continue de marcher.",[26,334,335],{},"Ce que la 1.0 ajoute, c'est d'abord le pré-rendu au build. En février, une page n'entrait dans le cache qu'après sa première visite. Désormais, vinext peut générer les pages à l'avance, pour les deux routers, et même produire un site entièrement statique.",[26,337,338],{},"Et puis il y a le cache warming, l'idée la plus intéressante de la release. Ce n'est pas automatique : au deploy, vinext peut uploader la nouvelle version à 0 % de trafic, remplir le cache avec les pages éligibles, puis basculer les visiteurs dessus. Un second mode s'appuie sur vos analytics Cloudflare pour prioriser les plus visitées. Le build reste rapide, et le cache est chaud dès la mise en ligne.",[33,340,342],{"id":341},"alors-pourquoi-passer-à-vinext","Alors, pourquoi passer à vinext ?",[26,344,345],{},"Le cas évident : vous voulez faire tourner une app Next.js sur Cloudflare Workers sans passer par OpenNext. Cloudflare recommande d'ailleurs vinext comme méthode par défaut pour ça. Vous gagnez l'outillage Vite, les services Cloudflare dès le dev et un cache pensé pour l'edge.",[26,347,348,349,352,353,356],{},"Tester ne coûte pas cher. ",[41,350,351],{},"npx vinext check"," scanne votre projet, puis ",[41,354,355],{},"npx vinext init"," ajoute la config sans toucher à vos scripts Next.js, et vous pouvez faire tourner les deux en parallèle pour comparer.",[26,358,359],{},"Les limites sont réelles, cela dit. Malgré le « 1.0 », la doc Cloudflare parle encore de beta. Si votre appli repose sur Cache Components, PPR ou l'optimisation d'images au build, restez sur Next.js pour l'instant. Et un bon score de tests ne garantit pas que vos cas limites à vous sont couverts.",[26,361,362,363,366],{},"Mon avis : pour un projet Next.js « classique » destiné à Cloudflare, que ce soit en Pages Router ou en App Router, vinext 1.0 mérite un essai sur une branche. Pour un projet qui suit Next.js au plus près de ses nouveautés, ou qui tourne très bien chez Vercel, je ne vois pas de raison urgente de bouger. Lancez ",[41,364,365],{},"vinext check",", regardez le dashboard de compatibilité, et décidez avec vos propres données.",[33,368,370],{"id":369},"sources","Sources",[372,373,374,384,391,398,405,412,419,426,433],"ol",{},[375,376,377],"li",{},[378,379,383],"a",{"href":380,"rel":381},"https:\u002F\u002Fblog.cloudflare.com\u002Fvinext-nextjs-on-vite\u002F",[382],"nofollow","Next.js applications, powered by Vite: introducing Vinext 1.0 - Cloudflare Blog (28 septembre 2026)",[375,385,386],{},[378,387,390],{"href":388,"rel":389},"https:\u002F\u002Fblog.cloudflare.com\u002Fvinext\u002F",[382],"How we rebuilt Next.js with AI in one week - Cloudflare Blog (24 février 2026)",[375,392,393],{},[378,394,397],{"href":395,"rel":396},"https:\u002F\u002Fvinext.dev\u002Fdocs\u002Freference\u002Fdifferences",[382],"Differences from Next.js - documentation vinext",[375,399,400],{},[378,401,404],{"href":402,"rel":403},"https:\u002F\u002Fvinext.dev\u002Fdocs\u002Fguides\u002Fcaching",[382],"Caching on Cloudflare - documentation vinext",[375,406,407],{},[378,408,411],{"href":409,"rel":410},"https:\u002F\u002Fvinext.dev\u002Fcompatibility",[382],"Next.js compatibility dashboard - vinext.dev",[375,413,414],{},[378,415,418],{"href":416,"rel":417},"https:\u002F\u002Fgithub.com\u002Fcloudflare\u002Fvinext\u002Fissues\u002F675",[382],"getInitialProps support - issue GitHub cloudflare\u002Fvinext",[375,420,421],{},[378,422,425],{"href":423,"rel":424},"https:\u002F\u002Fgithub.com\u002Fcloudflare\u002Fvinext\u002Freleases\u002Ftag\u002Fvinext%401.0.1",[382],"Release vinext@1.0.1 - GitHub",[375,427,428],{},[378,429,432],{"href":430,"rel":431},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fworkers\u002Fframework-guides\u002Fweb-apps\u002Fnextjs\u002F",[382],"Next.js - Cloudflare Workers docs",[375,434,435],{},[378,436,439],{"href":437,"rel":438},"https:\u002F\u002Fvinext.dev\u002Fdocs\u002Fgetting-started\u002Fmigrating",[382],"Migrate a Next.js app - documentation vinext",[441,442,443],"style",{},"html pre.shiki code .sjThu, html code.shiki .sjThu{--shiki-default:#848BBD;--shiki-default-font-style:italic}html pre.shiki code .scrqX, html code.shiki .scrqX{--shiki-default:#FEDE5D}html pre.shiki code .sgRlq, html code.shiki .sgRlq{--shiki-default:#36F9F6}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sqjNi, html code.shiki .sqjNi{--shiki-default:#FF7EDB}html pre.shiki code .s2hdG, html code.shiki .s2hdG{--shiki-default:#B6B1B1}html pre.shiki code .sSmKr, html code.shiki .sSmKr{--shiki-default:#F97E72}html pre.shiki code .sH7Js, html code.shiki .sH7Js{--shiki-default:#FF7EDB;--shiki-default-font-style:italic}html pre.shiki code .sRQ1T, html code.shiki .sRQ1T{--shiki-default:#FE4450}html pre.shiki code .sfE7D, html code.shiki .sfE7D{--shiki-default:#72F1B8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":128,"searchDepth":142,"depth":142,"links":445},[446,447,448,449,450],{"id":35,"depth":142,"text":36},{"id":94,"depth":142,"text":95},{"id":110,"depth":142,"text":111},{"id":341,"depth":142,"text":342},{"id":369,"depth":142,"text":370},"vinext, la réimplémentation de Next.js sur Vite signée Cloudflare, passe en 1.0 : Pages Router, ISR, cache warming. Ce qui change et quand l'adopter.","md",{},"\u002Farticles\u002Fvinext-1-nextjs-sur-vite","2026-10-05",{"title":18,"description":451},"articles\u002Fvinext-1-nextjs-sur-vite","HUSFzq6pwKg3Dss-lgFAJEiA8ld8SeTkVKVguVePwCE",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":460},"\u003Cpath fill=\"currentColor\" d=\"M4 21V9l8-6l8 6v12h-6v-7h-4v7z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":462},"\u003Cpath fill=\"currentColor\" d=\"m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":464},"\u003Cpath fill=\"currentColor\" d=\"M6 22q-.825 0-1.412-.587T4 20V10q0-.825.588-1.412T6 8h3v2H6v10h12V10h-3V8h3q.825 0 1.413.588T20 10v10q0 .825-.587 1.413T18 22zm5-6V4.825l-1.6 1.6L8 5l4-4l4 4l-1.4 1.425l-1.6-1.6V16z\"\u002F>",["Island",466],{"key":467,"result":468},"Brand_bAcjTzQpW6OVpFK319jfMki97vH1GrZiqHmeI7Xg4o",{"head":469},{},["Island",471],{"key":472,"result":473},"AppImg_IyX8AyXnvzxMhkQHFSbpXBHOtGi2gizwCEtOpbCcVEk",{"head":474},{},["Island",476],{"key":477,"result":478},"ArticleDetails_XokQNcWZZazondsKaBGUloum49UzpExEOp3FqGB0OY",{"head":479},{"script":480},[481],{"key":482,"tagPosition":483,"tagPriority":484,"innerHTML":485},":Rq3LAwVg9E:","bodyClose","critical","document.querySelectorAll('[data-prehydrate-id*=\":Rq3LAwVg9E:\"]').forEach(e=>{let t=window._nuxtTimeNow||=Date.now(),n=(e,t)=>t>0?e[0].toUpperCase()+e.slice(1):e,r=e.getAttribute(`datetime`);if(!r)return;let i=new Date(r);if(Number.isNaN(i.getTime()))return;let a={};for(let t of e.getAttributeNames())if(t.startsWith(`data-`)){let r=t.slice(5).split(`-`).map(n).join(``);r===`relativeStyle`&&(r=`style`);let i=e.getAttribute(t);a[r]=i===`true`||i!==`false`&&i}if(a.relative){let n=(i.getTime()-t)\u002F1e3,r=[{unit:`second`,seconds:1,threshold:60},{unit:`minute`,seconds:60,threshold:60},{unit:`hour`,seconds:3600,threshold:24},{unit:`day`,seconds:86400,threshold:30},{unit:`month`,seconds:2592e3,threshold:12},{unit:`year`,seconds:31536e3,threshold:1\u002F0}],{unit:o,seconds:s}=r.find(({seconds:e,threshold:t})=>Math.abs(n\u002Fe)\u003Ct)||r[r.length-1],c=n\u002Fs;e.textContent=new Intl.RelativeTimeFormat(a.locale,a).format(Math.round(c),o)}else e.textContent=new Intl.DateTimeFormat(a.locale,a).format(i)})",1791298895720]