[{"data":1,"prerenderedAt":549},["ShallowReactive",2],{"article__generer-un-pdf-avec-nodejs-et-puppeteer":3},{"id":4,"title":5,"body":6,"description":23,"extension":539,"meta":540,"navigation":148,"path":541,"seo":542,"stem":543,"tags":544,"__hash__":548},"article\u002Farticle\u002Fgenerer-un-pdf-avec-nodejs-et-puppeteer.md","Générer un PDF avec Node.js et Puppeteer à partir d'une page web",{"type":7,"value":8,"toc":532},"minimark",[9,14,18,24,29,41,45,57,87,94,98,103,437,441,448,454,496,500,515,528],[10,11,13],"h1",{"id":12},"générer-un-pdf-avec-nodejs-et-puppeteer","Générer un PDF avec Node.js et Puppeteer",[15,16,17],"p",{},"Vous en avez marre de maintenir votre script de génération de fiche produit PDF (ou votre CV), générez les directement à partir de votre site avec Node.js et Puppeteer.",[19,20,21],"blockquote",{},[15,22,23],{},"Pire que la mise en page d'un fichier Word, la mise en page d'un PDF généré par un script... Simplifiez-vous la vie en convertissant directement vos pages web en PDF.",[25,26,28],"h2",{"id":27},"introduction","Introduction",[15,30,31,32,36,37,40],{},"Nous allons voir ici comment créer un ",[33,34,35],"strong",{},"script Node.js"," qui vous permettra de ",[33,38,39],{},"générer un PDF à partir d'une page de votre site",".\nLe script tournera en local, mais vous pouvez l'intégrer de manière automatique dans votre CI\u002FCD.",[25,42,44],{"id":43},"installation","Installation",[15,46,47,48,56],{},"La seule dépendance dont vous avez besoin, ",[49,50,55],"a",{"href":51,"target":52,"className":53},"https:\u002F\u002Fpptr.dev\u002F","_blank",[54],"ypk__external-link","Puppeteer"," qui est un navigateur headless (ou plutôt, il contrôle votre navigateur).",[58,59,64],"pre",{"className":60,"code":61,"language":62,"meta":63,"style":63},"language-bash shiki shiki-themes monokai","npm install -D puppeteer\n","bash","",[65,66,67],"code",{"__ignoreMap":63},[68,69,72,76,80,84],"span",{"class":70,"line":71},"line",1,[68,73,75],{"class":74},"sHkqI","npm",[68,77,79],{"class":78},"s_Ekj"," install",[68,81,83],{"class":82},"s7s5_"," -D",[68,85,86],{"class":78}," puppeteer\n",[15,88,89],{},[33,90,93],{"className":91},[92],"ypk--error--no-background","Attention si vous utilisez PhantomJS ! La librairie était couramment utilisée, mais elle est officiellement stoppée car elle génére de trop grosses failles de sécurité.",[25,95,97],{"id":96},"le-script-complet","Le script complet",[15,99,100],{},[65,101,102],{},"tools\u002Fpdf-generator.js",[58,104,108],{"className":105,"code":106,"language":107,"meta":63,"style":63},"language-js shiki shiki-themes monokai","\u002F\u002F Chargement des dépendances\nconst puppeteer = require('puppeteer');\n\n(async () => {\n    \u002F\u002F Lancement de Puppeteer\n    const browser = await puppeteer.launch({\n        headless: true\n    });\n    \n    \u002F\u002F Ouverture et navigation vers la page à convertir\n    const page = await browser.newPage();\n    await page.goto('http:\u002F\u002Flocalhost\u002Fma-super-page-a-convertir', {waitUntil: 'networkidle2'});\n    \n    \u002F\u002F Génération du PDF\n    await page.pdf({\n        \u002F\u002F Chemin vers le PDF relatif à la racine de votre projet\n        path: 'src\u002Fpdf\u002Fmon-super-pdf.pdf',\n        format: 'A4',\n        \u002F\u002F N'oubliez pas de forcer le printBackground à true\n        \u002F\u002F Car il est possible que dans votre style CSS cela soit l'inverse pour plus d'éfficacité\n        \u002F\u002F Mais là on veut du beau\n        printBackground: true,\n        margin: {\n            top: '0.5cm',\n            right: '0.5cm',\n            bottom: '0.5cm',\n            left: '0.5cm'\n        }\n    });\n\n    \u002F\u002F Fermeture du navigateur et fin du script\n    await browser.close();\n})();\n","js",[65,109,110,116,143,150,167,173,196,205,211,217,223,244,270,275,281,293,299,311,322,328,334,340,351,357,368,378,388,397,403,408,413,419,431],{"__ignoreMap":63},[68,111,112],{"class":70,"line":71},[68,113,115],{"class":114},"snpHw","\u002F\u002F Chargement des dépendances\n",[68,117,119,123,127,131,134,137,140],{"class":70,"line":118},2,[68,120,122],{"class":121},"sOx1s","const",[68,124,126],{"class":125},"sCdxs"," puppeteer ",[68,128,130],{"class":129},"s8I7P","=",[68,132,133],{"class":74}," require",[68,135,136],{"class":125},"(",[68,138,139],{"class":78},"'puppeteer'",[68,141,142],{"class":125},");\n",[68,144,146],{"class":70,"line":145},3,[68,147,149],{"emptyLinePlaceholder":148},true,"\n",[68,151,153,155,158,161,164],{"class":70,"line":152},4,[68,154,136],{"class":125},[68,156,157],{"class":129},"async",[68,159,160],{"class":125}," () ",[68,162,163],{"class":121},"=>",[68,165,166],{"class":125}," {\n",[68,168,170],{"class":70,"line":169},5,[68,171,172],{"class":114},"    \u002F\u002F Lancement de Puppeteer\n",[68,174,176,179,182,184,187,190,193],{"class":70,"line":175},6,[68,177,178],{"class":121},"    const",[68,180,181],{"class":125}," browser ",[68,183,130],{"class":129},[68,185,186],{"class":129}," await",[68,188,189],{"class":125}," puppeteer.",[68,191,192],{"class":74},"launch",[68,194,195],{"class":125},"({\n",[68,197,199,202],{"class":70,"line":198},7,[68,200,201],{"class":125},"        headless: ",[68,203,204],{"class":82},"true\n",[68,206,208],{"class":70,"line":207},8,[68,209,210],{"class":125},"    });\n",[68,212,214],{"class":70,"line":213},9,[68,215,216],{"class":125},"    \n",[68,218,220],{"class":70,"line":219},10,[68,221,222],{"class":114},"    \u002F\u002F Ouverture et navigation vers la page à convertir\n",[68,224,226,228,231,233,235,238,241],{"class":70,"line":225},11,[68,227,178],{"class":121},[68,229,230],{"class":125}," page ",[68,232,130],{"class":129},[68,234,186],{"class":129},[68,236,237],{"class":125}," browser.",[68,239,240],{"class":74},"newPage",[68,242,243],{"class":125},"();\n",[68,245,247,250,253,256,258,261,264,267],{"class":70,"line":246},12,[68,248,249],{"class":129},"    await",[68,251,252],{"class":125}," page.",[68,254,255],{"class":74},"goto",[68,257,136],{"class":125},[68,259,260],{"class":78},"'http:\u002F\u002Flocalhost\u002Fma-super-page-a-convertir'",[68,262,263],{"class":125},", {waitUntil: ",[68,265,266],{"class":78},"'networkidle2'",[68,268,269],{"class":125},"});\n",[68,271,273],{"class":70,"line":272},13,[68,274,216],{"class":125},[68,276,278],{"class":70,"line":277},14,[68,279,280],{"class":114},"    \u002F\u002F Génération du PDF\n",[68,282,284,286,288,291],{"class":70,"line":283},15,[68,285,249],{"class":129},[68,287,252],{"class":125},[68,289,290],{"class":74},"pdf",[68,292,195],{"class":125},[68,294,296],{"class":70,"line":295},16,[68,297,298],{"class":114},"        \u002F\u002F Chemin vers le PDF relatif à la racine de votre projet\n",[68,300,302,305,308],{"class":70,"line":301},17,[68,303,304],{"class":125},"        path: ",[68,306,307],{"class":78},"'src\u002Fpdf\u002Fmon-super-pdf.pdf'",[68,309,310],{"class":125},",\n",[68,312,314,317,320],{"class":70,"line":313},18,[68,315,316],{"class":125},"        format: ",[68,318,319],{"class":78},"'A4'",[68,321,310],{"class":125},[68,323,325],{"class":70,"line":324},19,[68,326,327],{"class":114},"        \u002F\u002F N'oubliez pas de forcer le printBackground à true\n",[68,329,331],{"class":70,"line":330},20,[68,332,333],{"class":114},"        \u002F\u002F Car il est possible que dans votre style CSS cela soit l'inverse pour plus d'éfficacité\n",[68,335,337],{"class":70,"line":336},21,[68,338,339],{"class":114},"        \u002F\u002F Mais là on veut du beau\n",[68,341,343,346,349],{"class":70,"line":342},22,[68,344,345],{"class":125},"        printBackground: ",[68,347,348],{"class":82},"true",[68,350,310],{"class":125},[68,352,354],{"class":70,"line":353},23,[68,355,356],{"class":125},"        margin: {\n",[68,358,360,363,366],{"class":70,"line":359},24,[68,361,362],{"class":125},"            top: ",[68,364,365],{"class":78},"'0.5cm'",[68,367,310],{"class":125},[68,369,371,374,376],{"class":70,"line":370},25,[68,372,373],{"class":125},"            right: ",[68,375,365],{"class":78},[68,377,310],{"class":125},[68,379,381,384,386],{"class":70,"line":380},26,[68,382,383],{"class":125},"            bottom: ",[68,385,365],{"class":78},[68,387,310],{"class":125},[68,389,391,394],{"class":70,"line":390},27,[68,392,393],{"class":125},"            left: ",[68,395,396],{"class":78},"'0.5cm'\n",[68,398,400],{"class":70,"line":399},28,[68,401,402],{"class":125},"        }\n",[68,404,406],{"class":70,"line":405},29,[68,407,210],{"class":125},[68,409,411],{"class":70,"line":410},30,[68,412,149],{"emptyLinePlaceholder":148},[68,414,416],{"class":70,"line":415},31,[68,417,418],{"class":114},"    \u002F\u002F Fermeture du navigateur et fin du script\n",[68,420,422,424,426,429],{"class":70,"line":421},32,[68,423,249],{"class":129},[68,425,237],{"class":125},[68,427,428],{"class":74},"close",[68,430,243],{"class":125},[68,432,434],{"class":70,"line":433},33,[68,435,436],{"class":125},"})();\n",[25,438,440],{"id":439},"lancement-du-script","Lancement du script",[15,442,443,444,447],{},"Pour que le script fonctionne, ",[33,445,446],{},"il faut que votre site soit lancé et l'URL en localhost accessible",".",[15,449,450,451,447],{},"Pour plus de praticité, pensez à ajouter le script dans votre ",[65,452,453],{},"package.json",[58,455,459],{"className":456,"code":457,"language":458,"meta":63,"style":63},"language-json shiki shiki-themes monokai","{\n    \"scripts\": {\n        \"pdf:build\": \"node tools\u002Fpdf-generator.js\"\n    }\n}\n","json",[65,460,461,466,474,486,491],{"__ignoreMap":63},[68,462,463],{"class":70,"line":71},[68,464,465],{"class":125},"{\n",[68,467,468,471],{"class":70,"line":118},[68,469,470],{"class":121},"    \"scripts\"",[68,472,473],{"class":125},": {\n",[68,475,476,479,482],{"class":70,"line":145},[68,477,478],{"class":121},"        \"pdf:build\"",[68,480,481],{"class":125},": ",[68,483,485],{"class":484},"susgL","\"node tools\u002Fpdf-generator.js\"\n",[68,487,488],{"class":70,"line":152},[68,489,490],{"class":125},"    }\n",[68,492,493],{"class":70,"line":169},[68,494,495],{"class":125},"}\n",[25,497,499],{"id":498},"conclusion","Conclusion",[15,501,502,503,506,507,510,511,514],{},"Avec ceci, vous avez la possibilité de faire ",[33,504,505],{},"de beaux PDFs"," rapidement, ",[33,508,509],{},"automatiquement mis à jour"," et ne nécessitant ",[33,512,513],{},"pas une énième source de données"," et d'erreur.",[15,516,517,518,447,524,527],{},"Le style de vos PDFs sera logiquement ",[33,519,520,521],{},"basé sur votre feuille de style avec la media query ",[65,522,523],{},"print",[525,526],"br",{},"\nC'est parfait, vous avez déjà cela d'implémenté sur votre site... N'est-ce pas ???",[529,530,531],"style",{},"html pre.shiki code .snpHw, html code.shiki .snpHw{--shiki-default:#88846F}html pre.shiki code .sOx1s, html code.shiki .sOx1s{--shiki-default:#66D9EF;--shiki-default-font-style:italic}html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .s8I7P, html code.shiki .s8I7P{--shiki-default:#F92672}html pre.shiki code .sHkqI, html code.shiki .sHkqI{--shiki-default:#A6E22E}html pre.shiki code .s_Ekj, html code.shiki .s_Ekj{--shiki-default:#E6DB74}html pre.shiki code .s7s5_, html code.shiki .s7s5_{--shiki-default:#AE81FF}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);}html pre.shiki code .susgL, html code.shiki .susgL{--shiki-default:#CFCFC2}",{"title":63,"searchDepth":118,"depth":118,"links":533},[534,535,536,537,538],{"id":27,"depth":118,"text":28},{"id":43,"depth":118,"text":44},{"id":96,"depth":118,"text":97},{"id":439,"depth":118,"text":440},{"id":498,"depth":118,"text":499},"md",{},"\u002Farticle\u002Fgenerer-un-pdf-avec-nodejs-et-puppeteer",{"title":5,"description":23},"article\u002Fgenerer-un-pdf-avec-nodejs-et-puppeteer",[545,546,547],"technique","backend","nodejs","8uKQbJ3pWjfNBq_UJNdkLsndFDCsXtssEj0NxK_-4Ow",1775518747719]