<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: HARSH VATS</title>
    <description>The latest articles on Forem by HARSH VATS (@harshvats2000).</description>
    <link>https://forem.com/harshvats2000</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F427863%2F61c7aaca-5529-4c58-9470-44103fd5f279.jpeg</url>
      <title>Forem: HARSH VATS</title>
      <link>https://forem.com/harshvats2000</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/harshvats2000"/>
    <language>en</language>
    <item>
      <title>Creating a Next.js API to Convert HTML to PDF with Puppeteer (Vercel-Compatible)</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Fri, 11 Oct 2024 15:26:45 +0000</pubDate>
      <link>https://forem.com/harshvats2000/creating-a-nextjs-api-to-convert-html-to-pdf-with-puppeteer-vercel-compatible-16fc</link>
      <guid>https://forem.com/harshvats2000/creating-a-nextjs-api-to-convert-html-to-pdf-with-puppeteer-vercel-compatible-16fc</guid>
      <description>&lt;p&gt;Converting HTML to PDF is a common requirement in web applications. In this blog post, we'll explore how to create a Next.js API route that converts HTML to PDF using Puppeteer, and we'll ensure it works when deployed to Vercel.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;While Puppeteer is a powerful tool for HTML to PDF conversion, it presents challenges when deploying to serverless environments like Vercel. The main issues are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Puppeteer requires a Chromium binary, which exceeds Vercel's size limits.&lt;/li&gt;
&lt;li&gt;Serverless functions have limited execution time and resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;We'll use a combination of &lt;code&gt;@sparticuz/chromium-min&lt;/code&gt; and &lt;code&gt;puppeteer-core&lt;/code&gt; to overcome these limitations. Here's how we'll approach it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a minimal Chromium build designed for serverless environments.&lt;/li&gt;
&lt;li&gt;Configure Puppeteer to use this minimal Chromium version.&lt;/li&gt;
&lt;li&gt;Optimize the PDF generation process for serverless execution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Setting Up the Project
&lt;/h2&gt;

&lt;p&gt;First, create a new Next.js project or use an existing one. Then, install the necessary dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @sparticuz/chromium-min puppeteer-core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To ensure compatibility and optimal performance, it's important to use the correct versions of the required packages. As of the latest testing, the following versions are recommended:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@sparticuz/chromium-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^129.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"puppeteer-core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^23.5.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Creating the API Route
&lt;/h2&gt;

&lt;p&gt;Create a new file at &lt;code&gt;app/api/html-to-pdf/route.js&lt;/code&gt; (for Next.js 13+ app router) or &lt;code&gt;pages/api/html-to-pdf.js&lt;/code&gt; (for Pages router). Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@sparticuz/chromium-min&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;puppeteer-core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--hide-scrollbars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--disable-web-security&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;defaultViewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultViewport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`https://github.com/Sparticuz/chromium/releases/download/v129.0.0/chromium-v129.0.0-pack.tar`&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignoreHTTPSErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;networkidle0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;printBackground&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1cm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1cm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1cm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1cm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pdfBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Disposition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;attachment; filename="output.pdf"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error generating PDF:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to generate PDF&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Understanding the Code
&lt;/h2&gt;

&lt;p&gt;Let's break down the key parts of this code:&lt;/p&gt;

&lt;h3&gt;
  
  
  Browser Configuration
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;getBrowser&lt;/code&gt; function sets up Puppeteer with the minimal Chromium binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--hide-scrollbars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--disable-web-security&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;defaultViewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultViewport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`https://github.com/Sparticuz/chromium/releases/download/v129.0.0/chromium-v129.0.0-pack.tar`&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignoreHTTPSErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration uses the &lt;code&gt;@sparticuz/chromium-min&lt;/code&gt; package to provide a minimal Chromium binary compatible with serverless environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  PDF Generation
&lt;/h3&gt;

&lt;p&gt;The main logic for PDF generation is in the &lt;code&gt;POST&lt;/code&gt; function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract the HTML from the request body.&lt;/li&gt;
&lt;li&gt;Launch a browser instance using the &lt;code&gt;getBrowser&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Create a new page and set its content to the provided HTML.&lt;/li&gt;
&lt;li&gt;Generate a PDF from the page content.&lt;/li&gt;
&lt;li&gt;Close the browser to free up resources.&lt;/li&gt;
&lt;li&gt;Return the PDF as a response with appropriate headers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Using the API
&lt;/h2&gt;

&lt;p&gt;To use this API, send a POST request with the HTML content in the request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/html-to-pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;h1&amp;gt;Hello, World!&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Handle the PDF blob (e.g., download or display)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment Considerations
&lt;/h2&gt;

&lt;p&gt;When deploying to Vercel, keep these points in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Execution Time&lt;/strong&gt;: Vercel has a maximum execution time of 10 seconds for hobby plans and 60 seconds for pro plans. Optimize your HTML and PDF generation process to fit within these limits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Usage&lt;/strong&gt;: Be mindful of memory usage. The minimal Chromium binary helps, but complex PDFs might still use significant memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cold Starts&lt;/strong&gt;: Serverless functions can experience cold starts. The first invocation might be slower as it needs to download and set up the Chromium binary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Implement robust error handling to manage timeouts or resource constraints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;: Consider implementing caching strategies for frequently generated PDFs to reduce load on your serverless functions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This approach allows you to create a powerful HTML to PDF conversion API using Next.js and Puppeteer, compatible with Vercel's serverless environment. By leveraging &lt;code&gt;@sparticuz/chromium-min&lt;/code&gt; and &lt;code&gt;puppeteer-core&lt;/code&gt;, we overcome the main challenges of running Puppeteer in a serverless context.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>vercel</category>
      <category>puppeteer</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Github VS Gitlab Vs Bitbucket</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Fri, 06 Jan 2023 15:48:59 +0000</pubDate>
      <link>https://forem.com/harshvats2000/github-vs-gitlab-vs-bitbucket-52gl</link>
      <guid>https://forem.com/harshvats2000/github-vs-gitlab-vs-bitbucket-52gl</guid>
      <description>&lt;p&gt;GitHub, GitLab, and Bitbucket are like the three musketeers of version control. They all offer a wide range of tools for developers to track changes in their code and collaborate with their team, but they each have their own unique set of features and quirks.&lt;/p&gt;

&lt;p&gt;GitHub is like the cool, laid-back friend who is always down to hang out. It's cloud-based, so you don't have to worry about setting up your own servers. It's also free for open-source projects and has a pretty reasonable pricing model for private repositories. The only downside is that it's not as focused on CI/CD as GitLab and Bitbucket. But hey, at least you can use it to host your personal website and share your cat memes with the world.&lt;/p&gt;

&lt;p&gt;GitLab is like the organized, ambitious friend who always has a plan. It offers both cloud-based and self-hosted options, so you can choose the hosting solution that works best for you. It also has a ton of features for CI/CD and project management, which makes it a great choice for teams that want to streamline their development process. Just don't forget to bring snacks to their team meetings, because they'll probably be talking about pipelines and artifacts for a while.&lt;/p&gt;

&lt;p&gt;Bitbucket is like the nerdy, reliable friend who is always there when you need them. They also offer both cloud-based and self-hosted options, as well as a wide range of integrations with other tools and services. They might not be as flashy as the other two, but they get the job done and they do it well. Just don't be surprised if they start talking to you in Git commands during lunch.&lt;/p&gt;

&lt;p&gt;In the end, the choice between GitHub, GitLab, and Bitbucket will depend on your project's needs and your team's preferences. So whether you're a fan of the cool and casual approach, the ambitious and organized approach, or the nerdy and reliable approach, there's a version control platform out there for you. Just don't forget to invite all three musketeers to the code review party.&lt;/p&gt;

&lt;p&gt;What are your thoughts?&lt;/p&gt;

</description>
      <category>bitbucke</category>
      <category>github</category>
      <category>gitlab</category>
      <category>git</category>
    </item>
    <item>
      <title>How to stay motivated and focused as a developer?</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Sat, 05 Jun 2021 08:33:58 +0000</pubDate>
      <link>https://forem.com/harshvats2000/how-to-stay-motivated-and-focused-as-a-developer-37a</link>
      <guid>https://forem.com/harshvats2000/how-to-stay-motivated-and-focused-as-a-developer-37a</guid>
      <description>&lt;p&gt;The only way to stay motivated is to be around people who are doing something great daily. You can't stay motivated if you are around people who are doing the same stuff daily.&lt;/p&gt;

&lt;p&gt;Before learning to stay motivated, learn to not get demotivated. Things like your side projects can also demotivate you, trust me.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to avoid getting demotivated?
&lt;/h1&gt;

&lt;h3&gt;
  
  
  1. If you are not able to figure out something, even after spending hours on it, then call it off for that day.
&lt;/h3&gt;

&lt;p&gt;At first, you might think that how can you find the solution to a problem if you wouldn't spend more time on it, but that's not always the case. I'm saying it by experience that sometimes, you need to keep your mind off the problem. Start fresh the next day, with a different perspective towards the problem, and you might find a solution within minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. If someone tells you that you are in the wrong direction, don't just listen to them blindly.
&lt;/h3&gt;

&lt;p&gt;There will be several people who'll tell you to follow a different path to achieve the same target like becoming a web developer. There can be infinite ways to achieve the same thing and most people don't understand that. Don't make yourself uncomfortable with what they say. Instead, just keep going if you feel like you are making progress. You can't lie to yourself, you know whether you are making progress or not. If yes then keep going, if not, then take some time to reconsider.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Never feel guilty about time wasted.
&lt;/h3&gt;

&lt;p&gt;It happens to me many times. I play mobile games a lot(just one specifically called shadow fight arena). Sometimes, I think about it that I played that game for 2 hours last day, the precious time which I could've used to learn something or spend some time refactoring my old code. This generates a feeling of guilt and we don't feel like anything. Another day goes by doing nothing.&lt;/p&gt;

&lt;p&gt;I'm slowly trying to get out of this by inculcating a thought that playing a game should make me happy and relaxed Instead of filling me with guilt.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Don't let your college marks decide what you can do.
&lt;/h3&gt;

&lt;p&gt;I'll be honest here. I'm a below 6 pointer student who wants to learn more and more about how the web works. I want to learn how things work at a basic level. I don't just know React.js, I know what they do under the hood (almost and still learning). &lt;/p&gt;

&lt;p&gt;You can't call yourself a web lover if you don't know how DNS works.&lt;/p&gt;

&lt;p&gt;That's what I'm talking about, don't let my last sentence demotivate you. If you don't know how DNS works then learn it. This should be the attitude. If you don't have time right now, then make notes of what you need to learn and when. You will find yourself filled with motivation. You won't have time for the boring stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to stay motivated?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Read online articles/blogs and watch tutorials.
&lt;/h3&gt;

&lt;p&gt;You need to join a community of developers around you. The best part of being a developer is to have the freedom of creating anything that could reach millions of users overnight. But obviously, that requires a lot of skills other than being a developer. But at least you can think start building things on your own.&lt;/p&gt;

&lt;p&gt;You do know that Mark Zuckerberg made Facebook in his hostel room right?&lt;/p&gt;

&lt;p&gt;Well, I'm not saying go out there and make another Facebook, but there's a lot of other things that you can try. Remember one thing, you can't make it perfect just on the first try.&lt;/p&gt;

&lt;p&gt;If you knew success was a certainty, what would you attempt to do?&lt;/p&gt;

&lt;p&gt;That's the beauty of life. So keep trying and keep building stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Whatever you build, make sure you can show that to anyone.
&lt;/h3&gt;

&lt;p&gt;A negative feeling can arise if you built something and now you cannot show that to someone. Keep your projects on the git and also showcase them on platforms like LinkedIn, in your blogs, on your website.&lt;/p&gt;

&lt;p&gt;Also, make sure that the project you are showing is complete, otherwise, it'll leave a negative impact. You'll see that these things can boost your confidence. Don't make anything public until you are happy with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Always spend time on your old written code.
&lt;/h3&gt;

&lt;p&gt;This might not sound that effective but it works for me. Instead of wasting time just sitting idle, I like to spend some time refactoring my personal projects, add new features, or bug fixing.&lt;/p&gt;

&lt;p&gt;I am also making it a habit to spend some time on open source projects instead of just working on mine, that'll make me a really good developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Humans are social animal (Are you human?)
&lt;/h3&gt;

&lt;p&gt;Don't feel like you can do much by ditching friends and utilizing that time to code. You are a social animal, enjoy your life dude and keep exploring things.&lt;/p&gt;

&lt;p&gt;That's it for today. Have a good day devs. Let me know in the comments what else we can do to stay motivated and focused on our goal.&lt;/p&gt;

&lt;p&gt;Keep exploring things...&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Please refactor your code.</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Thu, 18 Mar 2021 03:40:09 +0000</pubDate>
      <link>https://forem.com/harshvats2000/please-refactor-your-code-1k3e</link>
      <guid>https://forem.com/harshvats2000/please-refactor-your-code-1k3e</guid>
      <description>&lt;p&gt;Try to refactor your code whenever you get time.&lt;/p&gt;

&lt;p&gt;This is a very small post(actually my linkedin post) but very helpful.&lt;/p&gt;

&lt;p&gt;If you don't have the habbit of refactoring your code, try now, this is going to be the best experience and learning for you.&lt;/p&gt;

&lt;p&gt;How code refactoring would help???&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You will realize that there are some pieces in your code which are not at all being used. Now you can delete them. This gives immense pleasure 😅.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can apply your newly learned things. For me, I was never confident in object destructuring in javascript but in refactoring the code, I applied my learning and became more confident like giving initial value, renaming in destructing. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As your code gets better and better and now that you have gone through it many times, you can now explain it to anybody about your project and how you did it. Most of the times, we are not able to explain our code just bcoz we left it after we realized that it's doing the required job and never cared to refactor it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Doesn't matter if project is big or small, you need to refactor it now.&lt;/p&gt;

&lt;p&gt;Let me know your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;That's it, have a good day dev 😊.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Any chrome extension to delete inactive tabs?</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Mon, 08 Mar 2021 17:14:17 +0000</pubDate>
      <link>https://forem.com/harshvats2000/any-chrome-extension-to-delete-inactive-tabs-41g7</link>
      <guid>https://forem.com/harshvats2000/any-chrome-extension-to-delete-inactive-tabs-41g7</guid>
      <description>&lt;p&gt;Do you know any chrome extension to automatically close all inactive tabs after some time.&lt;/p&gt;

&lt;p&gt;Also i should be able to change inactivity time for each website. Like if i have set 10 minutes of inactivity time, then extension should automatically close all stackoverflow tabs that i haven't visited in last 10 minutes.&lt;/p&gt;

&lt;p&gt;I can set less time for github repo's i've opened.&lt;/p&gt;

&lt;p&gt;I mean, i should have the flexibility to change websites and their inactivity time.&lt;/p&gt;

&lt;p&gt;I don't think there's any chrome extension there which can do that, that's why I'm working to make one.&lt;/p&gt;

&lt;p&gt;If there's any plz let me know now :)&lt;/p&gt;

&lt;p&gt;Thanks developers&lt;/p&gt;

</description>
      <category>help</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Rate my resume out of 10.</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Sat, 20 Feb 2021 07:45:10 +0000</pubDate>
      <link>https://forem.com/harshvats2000/rate-my-resume-out-of-10-49bk</link>
      <guid>https://forem.com/harshvats2000/rate-my-resume-out-of-10-49bk</guid>
      <description>&lt;p&gt;Hi, I am sick of googling "online resume builder". So I decided to make it from scratch. I ended up with some basic resume which looks same and exact to others. I wanted something unique.&lt;br&gt;
I recently learned figma almost 2 months ago to speed up my web development projects. So i also decided to use it for making resume. &lt;br&gt;
It's my first try on making resume. I want the help of dev.to community to rate this design so i can know what can be improved in this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1oks8pt1x13tcf3ewqr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1oks8pt1x13tcf3ewqr.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also if you want the same design for yourself for free, plz tell me in the comments.&lt;br&gt;
For those who are wondering why would I do it for free, you just need to follow me here on dev.to :)&lt;br&gt;
Thank you&lt;/p&gt;

</description>
      <category>help</category>
      <category>resume</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to get more web development clients in the early stages in India.</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Wed, 03 Feb 2021 10:03:49 +0000</pubDate>
      <link>https://forem.com/harshvats2000/how-to-get-more-web-development-clients-in-the-early-stages-in-india-3337</link>
      <guid>https://forem.com/harshvats2000/how-to-get-more-web-development-clients-in-the-early-stages-in-india-3337</guid>
      <description>&lt;p&gt;Hi, I'm Harsh Vats, a full stack web developer and a designer.&lt;/p&gt;

&lt;p&gt;I'm in my 6th semester while writing this blog post and I've done contributions to 3 startups and successfully delivered more than 20 websites to clients, some Indian and some International.&lt;/p&gt;

&lt;p&gt;The below points are some ways to get more website development clients. However, it's not necessary to follow them in order but that's how it worked for me atleast.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Find clients in your family or friends.
&lt;/h2&gt;

&lt;p&gt;This is where you should start. Don't charge too much. In India, if you are doing designing and development yourself, then you can easily charge minimum of 2000 rupees for static sites like a gym of your friend, real estate business of your uncle, etc.&lt;/p&gt;

&lt;p&gt;If you don't have any projects to show at this point, just ask them to pay for hosting and domain and do the development for free. Consider these are your projects which will help you later. A project is a project and no one knows how much you charged for the website.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Be active on social media.
&lt;/h2&gt;

&lt;p&gt;This one might seem a bit over work for now but trust me, it'll eventually help you build your profile and trust.&lt;/p&gt;

&lt;p&gt;I never worked on my social media and always thought that it's just a waste of time. But I realised later that social media is "The Thing" in coming times. &lt;/p&gt;

&lt;p&gt;You need to build your good presence on social media like instagram or linkedIn. LinkedIn can also help you in getting jobs or generating leads. Keep posting your original thoughts.&lt;/p&gt;

&lt;p&gt;Don't post any motivational stuff all the time. Sometimes it's okay but most of the time it just feels like someone is trying to make connections or increase followers without doing any effort. In short, it just feels annoying.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. You should have atleast 3 complete websites to show.
&lt;/h2&gt;

&lt;p&gt;Except your friends or family, nobody is going to believe that you can make good websites without actually seeing some of the websites that you have built in the past.&lt;/p&gt;

&lt;p&gt;So the more the good websites, the easier it would be for you to get web development clients.&lt;/p&gt;

&lt;p&gt;These websites can be those which you built for your family. You can tell clients that you built the website for "x" amount of money and there's high chance of getting your next project from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Print your visiting card
&lt;/h2&gt;

&lt;p&gt;Believe me, you need a visiting card to show that you actually are a professional developer and can make some great websites. &lt;/p&gt;

&lt;p&gt;Not only it reflects professionalism but also shows authenticity. &lt;/p&gt;

&lt;p&gt;In India, you can easily print cards with a rate of 2rupees/card.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.instagram.com/p/CKrQIRGh7Dh/" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is a great visiting card design for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Go to meetups/functions.
&lt;/h2&gt;

&lt;p&gt;This is very important to not miss meetups and functions. After my admission to IIT, I never really went to marriages because I thought that they won't benefit me.&lt;/p&gt;

&lt;p&gt;You know how many functions happen in India daily and we get invitaitions a lot. This is the best opportunity to go and meet different people and tell them that you make websites, give them your visiting card. &lt;/p&gt;

&lt;p&gt;They might call you one day for a website.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. It's time to go in the market and tell people about your service.
&lt;/h2&gt;

&lt;p&gt;You are now ready to go the market and talk to real customers where you can charge good amount. &lt;/p&gt;

&lt;p&gt;Show them your previous projects and tell them the benefits of having a website. &lt;/p&gt;

&lt;p&gt;If they want a website, it's good otherwise leave your card and tell them to call you if they change their mind or they know someone who wants a website.&lt;/p&gt;

&lt;p&gt;You are not only getting clients by this but also making connections and building your profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Start on online platforms like Upwork.
&lt;/h2&gt;

&lt;p&gt;There are many platforms for freelancers like &lt;a href="https://upwork.com" rel="noopener noreferrer"&gt;upwork&lt;/a&gt;, &lt;a href="https://freelancer.com" rel="noopener noreferrer"&gt;freelancer&lt;/a&gt; to start your freelancing but it's very tough to get work at the beginning.&lt;/p&gt;

&lt;p&gt;Keep applying and don't loose hope. Trust me, you will get some work eventually from these platform. I personally use upwork and have never used any other platform. It's very good source of income and I also build some good connections from here.&lt;/p&gt;

&lt;p&gt;Thank you for reading till here. I know it's hard to get clients in the starting but this is how the world works. You need to put some efforts. &lt;/p&gt;

&lt;p&gt;Getting clients is tough but not impossible.&lt;/p&gt;

&lt;p&gt;Thank you&lt;br&gt;
&lt;a href="https://harshvats.dev" rel="noopener noreferrer"&gt;Harsh Vats&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Do restaurants really need a website?</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Sun, 20 Dec 2020 06:26:02 +0000</pubDate>
      <link>https://forem.com/harshvats2000/do-restaurants-really-need-a-website-1jkl</link>
      <guid>https://forem.com/harshvats2000/do-restaurants-really-need-a-website-1jkl</guid>
      <description>&lt;p&gt;The answer is, yes and no.&lt;/p&gt;

&lt;p&gt;While there’s no doubt that websites help restaurateurs build direct relationships with customers, you can’t ignore the importance of third-party reservation sources. Platforms like Google My Business (GMB) and other online sources of reservation like TripAdvisor hold tremendous potential and can drive extra revenue for your business when used correctly.&lt;/p&gt;

&lt;p&gt;Let's the discuss both the sides, starting with how the capabilities of third-party platforms can make you think of getting rid of a website altogether.&lt;/p&gt;

&lt;h2&gt;
  
  
  No, Restaurants don't need a website
&lt;/h2&gt;

&lt;p&gt;As stated earlier, booking functionality is now available outside of standalone restaurant websites via Reserve with Google and other third-party reservation sources. Restaurateurs can use these channels to accept reservations through Google Maps, Google Search, as well as Google Voice Assistant.&lt;/p&gt;

&lt;p&gt;If you’re planning to use Reserve with Google, you’ll need to apply for a Google Reservation link. If you’re accepted, the “reserve a table” option will appear on your Google My Business profile, after which the tourists and residents in your city will be able to book a table at your restaurant via Google’s easy-to-use interface.&lt;/p&gt;

&lt;p&gt;Because Google owns the local search experience, you’ll find that your Google My Business profile (and the reservation link) always appears in a prominent place. It's vital to realize just how powerful Reserve with Google is for restaurant discovery online.&lt;/p&gt;

&lt;p&gt;In addition, Google My Business integrates with Google Maps, which means anyone searching for a restaurant via mobile or desktop can make reserve a table directly within Maps. Your restaurant’s GMB profile may even show up for certain keywords like “steakhouse” and “Italian” on Maps. As far as we know, a traditional restaurant website can’t offer this experience. &lt;/p&gt;

&lt;p&gt;So if you haven’t made a GMB profile yet, learn how to make one here. For restaurateurs who’ve already created their GMB listing, our optimization tips for Google My Business may help them generate more reservations.&lt;/p&gt;

&lt;p&gt;Of course, you’re not just restricted to Google’s offerings. You can also create or claim a listing on third-party aggregators like TripAdvisor and Zomato. These websites usually offer a better user experience, have reviews integrated into their backend, and even let you offer discounts for online reservations.&lt;/p&gt;

&lt;p&gt;You can’t replicate such features on a restaurant website without installing a plugin or two, which makes websites slow (not to mention, the review feature on booking aggregators looks and works much better).&lt;/p&gt;

&lt;p&gt;Moreover, it’s much easier to maintain and manage third-party profiles than a complete website. You don’t have to work with a drag-and-drop builder or write any sort of code. Just provide things like your restaurant name, booking times, and images, and you’ll have a listings page ready to go.&lt;/p&gt;

&lt;p&gt;Besides these booking platforms, you can promote your restaurant on social media instead of creating a restaurant website. This way, you can build a social community full of people that act as brand ambassadors for your restaurants.&lt;/p&gt;

&lt;p&gt;The best part? Some social networks will even let you add a “book now” button, so anyone checking out your posts can click that button to reserve a table through your reservation partner’s website.&lt;/p&gt;

&lt;p&gt;However, there are also clear benefits of having a more traditional website which shouldn’t be neglected. Below is a breakdown of why, despite the availability of all these booking platforms, it makes sense to invest in a restaurant website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yes, Restaurants really need a website
&lt;/h2&gt;

&lt;p&gt;A website serves as a key part of a restaurant’s brand. It can showcase your business in a way that third-party aggregators can’t – stories, design and content all help portray the “vibe” of your restaurant. Consider working with a web designer to infuse life into your site, or apply a pre-existing template that closely resembles the offline theme of your restaurant.&lt;/p&gt;

&lt;p&gt;Apart from web design and layout, a restaurant website allows you to control 100% of your content and marketing. You can create as many pages of web content as you like and share information via your custom-branded email newsletters. You’re not restricted by word limits, and you don’t have to settle for third-party email promotions.&lt;/p&gt;

&lt;p&gt;In terms of SEO, a restaurant website enables you to optimize for different searches and keywords beyond your brand name, like “restaurants that offer weekend discounts,” “restaurants for students,” etc. You can’t do this with profiles on third-party listings. Websites will even let you create a blog where you can post unlimited details and content about your promotions, people and business.&lt;/p&gt;

&lt;p&gt;But perhaps the most appealing aspect of having a restaurant website is that you’ll get to build your own database of clients, names, and users. What if a third-party website removes your listing and you are left with no information on your customers? Your business will take a hit.&lt;/p&gt;

&lt;p&gt;Therefore, it’s best to really own the customer data so that you can control the guest experience from start to finish. CRM for restaurants can help you gain insight into your guests’ demographics and preferences, allowing you to provide a tailored experience to each of your customers.&lt;/p&gt;

&lt;p&gt;Another benefit of having a website comes in the form of commission-free bookings. You can put up a “Reserve Your Table” button and take as many bookings as you like. Direct reservations are free whereas some third-party booking websites charge a commission per cover.&lt;/p&gt;

&lt;p&gt;All of this means there’s potential to quickly earn back whatever you spend on creating a website in a matter of months. And once you start making a profit, you can reinvest some of the income into your own digital property and keep earning more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, third-party platforms offer a range of benefits, but a restaurant website comes with its own set of perks which can’t be ignored.&lt;/p&gt;

&lt;p&gt;A good idea is to test waters on a third party website in the early days of your restaurant, and then reinvest any money you make to create a custom website. That way, you can slowly gain clout with online audiences and also learn how to run a site effectively. &lt;/p&gt;

&lt;p&gt;Then, after a few months, come up with a plan to optimize your third-party listing as well as your website. We don’t advise you to completely focus on one or the other because the best strategy, in our opinion, is to attain a balance between these two resources.&lt;/p&gt;

&lt;p&gt;Who knows, a customer who wasn’t impressed by your TripAdvisor listing decides to pay you a visit after looking at your restaurant website or vice versa. It’s all about smart cross-promotion of your various properties and optimum utilization of each and every one of them.&lt;/p&gt;

&lt;p&gt;Finally, If you have any restaurant and looking for a simple yet elegant website, contact us at &lt;a href="https://www.digivats.com/contact" rel="noopener noreferrer"&gt;DigiVats&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>restaurants</category>
      <category>showdev</category>
      <category>react</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to lazy load images in html with pure Javascript?</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Wed, 04 Nov 2020 17:58:37 +0000</pubDate>
      <link>https://forem.com/harshvats2000/how-to-lazy-load-images-in-html-with-pure-javascript-13m7</link>
      <guid>https://forem.com/harshvats2000/how-to-lazy-load-images-in-html-with-pure-javascript-13m7</guid>
      <description>&lt;p&gt;Let's read this article at my &lt;a href="https://www.harshvats.dev/blogs/how-to-lazy-load-images-in-html" rel="noopener noreferrer"&gt;place&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;If you just want to do image lazy loading without any understanding of the concepts involved because maybe this is your first time and you have to use in it your project then don't worry at all. I can assure you this article will give you everything already done so that you just need to copy paste.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Copy paste this code just before closing body tag
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.addEventListener('DOMContentLoaded', function () {
        var lazyloadImages = document.querySelectorAll('img.lazy');
        var lazyloadThrottleTimeout;

        function lazyload() {
          if (lazyloadThrottleTimeout) {
            clearTimeout(lazyloadThrottleTimeout);
          }

          lazyloadThrottleTimeout = setTimeout(function () {
            var scrollTop = window.pageYOffset;
            lazyloadImages.forEach(function (img) {
              if (img.offsetTop &amp;lt; window.innerHeight + scrollTop) {
                img.src = img.dataset.src;
                img.classList.remove('lazy');
              }
            });
            if (lazyloadImages.length == 0) {
              document.removeEventListener('scroll', lazyload);
              window.removeEventListener('resize', lazyload);
              window.removeEventListener('orientationChange', lazyload);
            }
          }, 20);
        }

        document.addEventListener('scroll', lazyload);
        window.addEventListener('resize', lazyload);
        window.addEventListener('orientationChange', lazyload);
      });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Replace image &lt;code&gt;src&lt;/code&gt; attribute with &lt;code&gt;data-src&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;If you have&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;img src="&amp;lt;url&amp;gt;" /&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;then replace it with&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;img data-src="&amp;lt;url&amp;gt;" /&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3. This is the last point. Add &lt;code&gt;class="lazy"&lt;/code&gt; to all the images you want to lazy load.
&lt;/h4&gt;

&lt;p&gt;Now you are good to go. Thank you for reading this article. I don't write articles for others, I write them for myself so I can use ready made code or revise my concepts. But if it helps you in any way then plz let me know &lt;a href="https://www.harshvats.dev/contact" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>html</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Will Typescript be more used than Javascript after 5 years??</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Mon, 12 Oct 2020 04:46:58 +0000</pubDate>
      <link>https://forem.com/harshvats2000/will-typescript-be-more-used-than-javascript-after-5-years-3al0</link>
      <guid>https://forem.com/harshvats2000/will-typescript-be-more-used-than-javascript-after-5-years-3al0</guid>
      <description></description>
      <category>javascript</category>
      <category>typescript</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Optional chaining in javascript (?.)</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Sun, 27 Sep 2020 14:43:52 +0000</pubDate>
      <link>https://forem.com/harshvats2000/optional-chaining-in-javascript-3lg</link>
      <guid>https://forem.com/harshvats2000/optional-chaining-in-javascript-3lg</guid>
      <description>&lt;p&gt;&lt;code&gt;?.&lt;/code&gt; is known as the chaining operator in javascript. This operator is so usefull that after reading this article you will start using this operator right away.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this optional chaining operator does?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;?.&lt;/code&gt; operator functions similarly to the &lt;code&gt;.&lt;/code&gt; chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined.&lt;br&gt;
Let's discuss some details so that it's more clear to you.&lt;/p&gt;

&lt;p&gt;Consider&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const person = {
  a: {
    b: 'c'
}
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What will happen if you will try to
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(person.a.b)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;??&lt;/p&gt;

&lt;p&gt;You are correct... It will definitely print 'c' in the console.&lt;/p&gt;

&lt;p&gt;But what if you try to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(person.d.e)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;??&lt;/p&gt;

&lt;p&gt;Hmmm...Tricky one?? Not at all... It will give you an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Uncaught reference error: Cannot read property e of undefined.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's because 'b' is not a property of object 'a'. So here's a big question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why on Earth would you try to print a property that you know does not exist??
&lt;/h2&gt;

&lt;p&gt;The answer is pretty straight forward. You want to print some data which will be in the object soon but is not available yet (e.g. fetching data using http requests). In ususal cases what you could have done is just apply if else condition that if the value exists only then print the data but using optional chaining operator it will become very simple. See below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (person.d) console.log(person.d.e)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(person.d.?e)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second one will not give an error even if the data is not fetched. It will just print undefined.&lt;br&gt;
That's really an awesome thing if you literally love js. I always love to teach the concept in as easy as possible way.&lt;/p&gt;

&lt;p&gt;Thank you for reading&lt;/p&gt;

&lt;p&gt;Happy javascripting....&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
      <category>showdev</category>
    </item>
    <item>
      <title>::after and ::before in CSS</title>
      <dc:creator>HARSH VATS</dc:creator>
      <pubDate>Wed, 02 Sep 2020 08:13:35 +0000</pubDate>
      <link>https://forem.com/harshvats2000/after-and-before-in-css-20de</link>
      <guid>https://forem.com/harshvats2000/after-and-before-in-css-20de</guid>
      <description>&lt;p&gt;One month before, I didn't knew about these ::after and ::before pseudo elements so i used to make an extra div if i wanted to include anything before a particular div. For example, if i wanted to underline a div without using border, or overlay a light image with dark background so that my light text is clearly visibile on light image, i usually do that by making another div which does not contain any content in it, just some background color and other styling. So it made my code look ugly, trust me if you want to have that overlay in many images, it would really make your code look poor as it would contain unnecessary markup in html, only for styling.&lt;/p&gt;

&lt;p&gt;So what i do in my free time is just find any good website with some great looking animations but still simple and pretty clean, and start making a copy of it. First i try myself and then look for their css in dev tools. It's a really really good practice to learn some extra skills in css and html. I learn a lot of great css properties. It increases your knowledge, like i recently was making a website &lt;a href="https://realestate01.vercel.app" rel="noopener noreferrer"&gt;https://realestate01.vercel.app&lt;/a&gt; by copying it from &lt;a href="https://adigedesign.com" rel="noopener noreferrer"&gt;https://adigedesign.com&lt;/a&gt; and then i see they have used &lt;code&gt;font-smoothing: antialiased;&lt;/code&gt; which i then searched on google, so i found out it was used earlier to smoothen the text and make it sharp on a webpage but now it's a not a web standard and mdn highly recommend to &lt;strong&gt;NOT&lt;/strong&gt; use it in production at all. So these are the things that you can also learn while trying to make a copy of website in your free time.&lt;/p&gt;

&lt;p&gt;In this website i have also used ::after in some images so that the text is clearly visible over image. Let's say you have a div which contains an image and a text over that image. It will look like this &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fahby06sj91nlr2f5yly6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fahby06sj91nlr2f5yly6.png" alt="Alt Text" width="342" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However if i use ::after on the div to make a slightly dark background, it will look like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhv4spzhf010ly9bapqpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhv4spzhf010ly9bapqpn.png" alt="Alt Text" width="343" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did you notice the slightly dark background of the second image? And i haven't even touched the html, it's just pure css. &lt;/p&gt;

&lt;h1&gt;
  
  
  Wanna see the code?
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div {
    position: relative;
}
div::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 40%;
    background-image: linear- 
    gradient(transparent, rgba(0,0,0,0.6));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me explain it to you. The div that contains image is the div in the css code above. Relative position is required so that the child of this div even pseudo child, will be positioned according to this div. &lt;br&gt;
content is an empty string because we don't want to put any text after the div. Anyways it's a lot better and efficient than using an empty div in the html. Agreed?? The ::after is given position absolute because we want it to overlap. Height is 40% because we don't want to overlap it completely. Height 40% should start from the bottom that's why bottom is 0. Background image, you can use anything but i am using linear gradient.&lt;/p&gt;

&lt;p&gt;I hope now power of ::after and ::before is clear to you.&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>react</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
