<?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>DEV Community: Arunas Skirius</title>
    <description>The latest articles on DEV Community by Arunas Skirius (@arukomp).</description>
    <link>https://dev.to/arukomp</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%2F873684%2F16a8367e-4114-4715-8df8-5600420bf75f.jpg</url>
      <title>DEV Community: Arunas Skirius</title>
      <link>https://dev.to/arukomp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arukomp"/>
    <language>en</language>
    <item>
      <title>How to Sell API Credits in Laravel</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Fri, 24 Jan 2025 15:12:24 +0000</pubDate>
      <link>https://dev.to/arukomp/how-to-sell-api-credits-in-laravel-k30</link>
      <guid>https://dev.to/arukomp/how-to-sell-api-credits-in-laravel-k30</guid>
      <description>&lt;p&gt;In today's API economy, choosing the right monetization strategy can make or break your business. While subscription-based pricing remains popular, many companies are discovering the advantages of selling API credits – a flexible approach that lets customers prepay for usage and consume services at their own pace.&lt;/p&gt;

&lt;p&gt;Think of API credits as a digital currency specific to your service. Instead of charging customers based on calendar months or user seats, you let them purchase credits upfront and deduct them based on API calls or specific actions. Companies like OpenAI and Google Cloud have popularized this model, but it's equally effective for businesses of any size.&lt;/p&gt;

&lt;p&gt;In this guide, we'll explore why credit-based pricing might be the right choice for your API business and walk through a practical implementation using Laravel and Stripe. You'll learn how to set up the entire system – from selling credit packages to tracking usage in your application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://spike.opcodes.io/blog/how-to-sell-api-credits-in-laravel" rel="noopener noreferrer"&gt;👉 Read the original article here 👈&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1882807378124702083-192" src="https://platform.twitter.com/embed/Tweet.html?id=1882807378124702083"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1882807378124702083-192');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1882807378124702083&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>stripe</category>
      <category>api</category>
      <category>startup</category>
    </item>
    <item>
      <title>How to build a SaaS in a weekend</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Fri, 24 Nov 2023 08:37:55 +0000</pubDate>
      <link>https://dev.to/arukomp/how-to-build-a-saas-in-a-weekend-f1h</link>
      <guid>https://dev.to/arukomp/how-to-build-a-saas-in-a-weekend-f1h</guid>
      <description>&lt;p&gt;You might think the development of the software is the difficult part, but I’m here to put that in perspective. There are tons of templates and tools to automate a lot of the development of a standard SaaS (Software as a Service), which allows you to skip (or speed-through) a lot of steps and still deliver a quality product for your customers. Using existing tools will allow you time to focus on building out the business logic, the part that separates you from your competition, and iterate faster, testing new ideas and getting to profitability much quicker. Last but not least, you will have time to do marketing!&lt;/p&gt;

&lt;p&gt;As a proof of concept, I have built a fully-functional SaaS in a single weekend, and in this article I am going to show you how. Feel free to copy everything you see here and create a SaaS of your own. Let’s begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a SaaS need?
&lt;/h2&gt;

&lt;p&gt;First, let’s address what we need to achieve in terms of product. Customers of your SaaS have certain expectations, and if you don’t address some of them - you might not have a usable product. Here’s what a typical SaaS needs to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Business logic&lt;/strong&gt; - first and foremost, you need a feature to sell - whether it’s API access, an automation, report generation, a fully-fledged platform for agencies, or some other feature that provides value to your customer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; - ability to sign up, log in, reset password, perhaps even two-factor authentication for extra security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing&lt;/strong&gt; - ability to enter payment details, charge money, and create/display invoices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt; - your customers need to know how to use your product. Even the most well-thought software needs a help center or API documentation for your customers to get unstuck and get the most value from your product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Landing page&lt;/strong&gt; - your customers need a place to get a first impression and learn about your product before signing up. You will share this page across all of your marketing efforts later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting&lt;/strong&gt; - finally, your business needs to be available to the public. Once you’re done building it locally, let’s put it to the cloud!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think the above list is a great starting point for a SaaS, and will be perfectly usable for your customers, and all of the above can be built or set up in a single weekend!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arunas.dev/how-to-build-a-saas-in-a-weekend/"&gt;&lt;em&gt;Continue reading on arunas.dev&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>saas</category>
      <category>tutorial</category>
      <category>startup</category>
    </item>
    <item>
      <title>Log Viewer v3 is out</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Mon, 28 Aug 2023 11:46:43 +0000</pubDate>
      <link>https://dev.to/arukomp/log-viewer-v3-is-out-64f</link>
      <guid>https://dev.to/arukomp/log-viewer-v3-is-out-64f</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/opcodesio/log-viewer"&gt;Log Viewer v3&lt;/a&gt; brings several quality of life features that I'm sure you will enjoy - different log format support, and email previews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support for multiple log formats
&lt;/h2&gt;

&lt;p&gt;Log Viewer can now view not just Laravel logs, but also Apache, Nginx, Redis, Postgres, Supervisor, and more. &lt;a href="https://log-viewer.opcodes.io/docs/3.x/log-types/default?ref=dev.to"&gt;Here&lt;/a&gt; you can see the types of logs that are now supported by Log Viewer out of the box.&lt;/p&gt;

&lt;p&gt;Showing these logs in the new Log Viewer is as easy as adding the paths to your logs in the &lt;code&gt;config/log-viewer.php&lt;/code&gt; configuration, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="cm"&gt;/*
    |---------------------------------------------------------
    | Include file patterns
    |---------------------------------------------------------
    |
    */&lt;/span&gt;

    &lt;span class="s1"&gt;'include_files'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'*.log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'**/*.log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="c1"&gt;// You can include paths to other log types as well, such as apache, nginx, and more.&lt;/span&gt;
        &lt;span class="s1"&gt;'/var/log/httpd/*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'/var/log/nginx/*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="c1"&gt;// For example, logs can be found on MacOS Apple Silicon machines&lt;/span&gt;
        &lt;span class="s1"&gt;'/opt/homebrew/var/log/nginx/*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'/opt/homebrew/var/log/httpd/*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'/opt/homebrew/var/log/php-fpm.log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'/opt/homebrew/var/log/postgres*log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'/opt/homebrew/var/log/redis*log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'/opt/homebrew/var/log/supervisor*log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="c1"&gt;// '/absolute/paths/supported',&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't see a particular log format, don't worry - you can now &lt;a href="https://log-viewer.opcodes.io/docs/3.x/log-types/custom?ref=dev.to"&gt;define custom log formats&lt;/a&gt; which will allow you to browse these custom logs within the Log Viewer UI that you love. Defining custom logs also works for overriding the existing, built-in log formats. If, for example, your Laravel or HTTP logs are somehow different from factory defaults, you can extend the parser classes to include the custom modifications you've made. You can read all about extending log formats &lt;a href="https://log-viewer.opcodes.io/docs/3.x/log-types/default?ref=dev.to#extending-a-pre-built-log-type"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log type switcher
&lt;/h3&gt;

&lt;p&gt;Supporting multiple types of logs means there a lot more... logs... To help find exactly what you're looking for, or to focus your search on particular log types, we have added a log type selector. The selector will show up as soon as Log Viewer finds more than one type of log.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5-_02eTd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0zn53v0yh003lampnlr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5-_02eTd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0zn53v0yh003lampnlr4.png" alt="Log Viewer log type switcher in action" width="800" height="919"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Email previews
&lt;/h2&gt;

&lt;p&gt;How often do you use the &lt;code&gt;log&lt;/code&gt; mail driver? I know I don't, simply because it's very difficult to read these raw emails with headers and MIME parts, much less see how they actually look. I've always opted in for other solutions like Mailtrap, Helo, or just sending real emails.&lt;/p&gt;

&lt;p&gt;Well, all the other tools require additional setup, separate apps, or can be plain dangerous in test environments (ever sent a test email to a real person by mistake?)&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;log&lt;/code&gt; mail driver is the simplest, and safest approach to sending emails locally. It becomes even more useful with Log Viewer v3, which brings email previews directly within the Log Viewer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UceqtBYI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8dxhrrc639dlqmdy2lxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UceqtBYI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8dxhrrc639dlqmdy2lxh.png" alt="Log Viewer email previews in action" width="800" height="815"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All you need to make this work is to set this in your &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAIL_MAILER=log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The emails you send will instead be logged to your Laravel log, and they will then be viewable within the Log Viewer. Nifty little feature, don't you think? :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading
&lt;/h2&gt;

&lt;p&gt;Log Viewer v3 is an easy upgrade without any breaking changes for most users. You can learn how to &lt;a href="https://log-viewer.opcodes.io/docs/3.x/upgrade?ref=dev.to"&gt;upgrade from v2 to v3 here&lt;/a&gt;. The documentation has been updated for Log Viewer v3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions / Feedback
&lt;/h2&gt;

&lt;p&gt;If you have any questions, issues, bugs to report - please send them directly to the project's GitHub page - &lt;a href="https://github.com/opcodesio/log-viewer/issues?ref=dev.to"&gt;issues&lt;/a&gt; or &lt;a href="https://github.com/opcodesio/log-viewer/discussions?ref=dev.to"&gt;discussions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support
&lt;/h2&gt;

&lt;p&gt;If you enjoy using this &lt;strong&gt;free&lt;/strong&gt;, open-source project, there's several ways you can give back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submit a PR - fix a bug, add a new feature, refactor code. All PRs are welcome.&lt;/li&gt;
&lt;li&gt;Add support for additional log formats - there's tons of different log formats in the world, and the more we can support in the Log Viewer - the better. Submit a PR with a new format support.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.buymeacoffee.com/arunas?ref=dev.to"&gt;Buy me a coffee!&lt;/a&gt; ☕️ I'm an avid coffee drinker, which helps me work through the weekends after my full-time job to provide you with the Log Viewer for free :)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>package</category>
      <category>news</category>
    </item>
    <item>
      <title>How to automate Stripe invoice emailing Laravel</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Mon, 12 Jun 2023 06:00:47 +0000</pubDate>
      <link>https://dev.to/arukomp/how-to-automate-stripe-invoice-emailing-laravel-23e3</link>
      <guid>https://dev.to/arukomp/how-to-automate-stripe-invoice-emailing-laravel-23e3</guid>
      <description>&lt;p&gt;In this blog post, we will guide you through automating the process of generating and emailing invoices with Laravel, specifically using the Laravel Cashier package. By the end of this post, you'll be able to automatically generate professional-looking invoices, customized to your needs, and have them automatically emailed to your customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we dive into the main content, it's important to ensure you have the following prerequisites in place.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Laravel Setup:&lt;/strong&gt; You should have a Laravel application up and running. Laravel is a powerful PHP framework that simplifies the process of building complex web applications. &lt;a href="https://laravel.com/docs/10.x/installation?ref=spike.opcodes.io"&gt;Learn how to get started with Laravel&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Laravel Cashier:&lt;/strong&gt; Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services. It handles almost all of the boilerplate subscription billing code you are dreading writing. You should have it installed and configured with your Stripe account. &lt;a href="https://laravel.com/docs/10.x/billing?ref=spike.opcodes.io#installation"&gt;Learn how to set up Cashier&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscriptions:&lt;/strong&gt; You should have your subscription models set up in Laravel. If you haven't done that, you can refer to our previous guide on &lt;a href="https://spike.opcodes.io/blog/how-to-set-up-recurring-payments-in-laravel?ref=spike.opcodes.io"&gt;How to set up recurring payments in Laravel&lt;/a&gt; which will guide you step-by-step on setting up subscriptions using Laravel and Cashier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Provider:&lt;/strong&gt; Lastly, you should have access to an email provider for sending emails. In this guide, we will discuss some common email providers such as Mailgun and Sendgrid, which offer free tiers for small businesses or startups.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you have these prerequisites in place, you are ready to automate the process of invoice generation and emailing in your Laravel application. Let's begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Previewing the invoice
&lt;/h2&gt;

&lt;p&gt;This will only be used for us to test and to see what the final invoice looks like as a PDF. It is a great way to quickly iterate and make changes to the invoice before we start automating the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up a new subscription
&lt;/h3&gt;

&lt;p&gt;This article assumes you have already have a subscription for your user. If not, here's a quick reminder of how you would do that. After setting up Laravel Cashier, creating a new subscription for a user is quite straightforward. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;newSubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'premium'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$creditCardToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we find the user and create a new subscription for them. The &lt;code&gt;'default'&lt;/code&gt; in the &lt;code&gt;newSubscription()&lt;/code&gt; function is the name of the subscription, and &lt;code&gt;'premium'&lt;/code&gt; is the specific Stripe plan's ID to which the user is subscribing. The &lt;code&gt;$creditCardToken&lt;/code&gt; variable is obtained when collecting the user's payment method in the frontend with Stripe's tools. &lt;a href="https://spike.opcodes.io/blog/how-to-set-up-recurring-payments-in-laravel?ref=spike.opcodes.io"&gt;Read more about setting up subscriptions for users here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preview the invoice
&lt;/h3&gt;

&lt;p&gt;Now that we've created a subscription, we can generate an invoice for it. We'll create an HTTP route that fetches the first invoice and downloads it as a PDF.&lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;web.php&lt;/code&gt; file located at &lt;code&gt;routes/web.php&lt;/code&gt; and add the following route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/invoice/preview'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// fetch the authenticated user&lt;/span&gt;

    &lt;span class="nv"&gt;$invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;invoices&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// get the first invoice&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$invoice&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="nv"&gt;$invoice&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'vendor'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Your Company'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'product'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Your Product'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'street'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Main Str. 1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'location'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'2000 Antwerp, Belgium'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'phone'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'+32 499 00 00 00'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'info@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'url'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'vendorVat'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'BE123456789'&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;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="s1"&gt;'No invoice found'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&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;In the above route, we're authenticating the user, fetching their first invoice, and using the &lt;code&gt;downloadInvoice()&lt;/code&gt; method to generate and download the invoice as a PDF.&lt;/p&gt;

&lt;p&gt;You can now preview the invoice by navigating to &lt;code&gt;http://localhost/invoice/preview&lt;/code&gt; in your browser.&lt;/p&gt;

&lt;p&gt;You should now see a generated PDF of a subscription invoice. In the next section, we'll delve into how you can automate the process of emailing them to your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating emailing of invoices
&lt;/h2&gt;

&lt;p&gt;Having set up and customized our invoices, the next step is to automate the process of sending these invoices via email to our users. We can tap into webhooks to automatically react to new invoices and send them to your customers via email whenever they are created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://spike.opcodes.io/blog/automate-stripe-invoice-generation-and-emailing-with-laravel"&gt;&lt;em&gt;Read the rest of the article here&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>stripe</category>
      <category>invoicing</category>
      <category>emails</category>
    </item>
    <item>
      <title>How to delay Laravel jobs and listeners within database transactions</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Thu, 30 Mar 2023 07:07:10 +0000</pubDate>
      <link>https://dev.to/arukomp/how-to-delay-laravel-jobs-and-listeners-within-database-transactions-2aac</link>
      <guid>https://dev.to/arukomp/how-to-delay-laravel-jobs-and-listeners-within-database-transactions-2aac</guid>
      <description>&lt;p&gt;As a Laravel developer, you may have encountered issues with jobs and listeners fired within database transactions. These issues can lead to &lt;code&gt;ModelNotFoundException&lt;/code&gt;, inconsistencies in your data, and other problems that can affect the reliability of your application. In this blog post, we will explore why database transactions are important, common issues that can arise when using them, and how to properly handle jobs and listeners within transactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use database transactions?
&lt;/h2&gt;

&lt;p&gt;Database transactions allow you to group multiple database operations into a single atomic unit. If any part of the transaction fails, all changes are rolled back, ensuring that your database remains in a consistent state. In Laravel, you can use transactions to execute multiple database queries within a single transaction by using the &lt;code&gt;DB::transaction&lt;/code&gt; method. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Illuminate\Support\DB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Perform database queries here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, to have more control you can also use a non-callback method of controlling database transactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Illuminate\Support\Facades\DB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;beginTransaction&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="c1"&gt;// Perform database operations here&lt;/span&gt;
    &lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;commit&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="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle the exception here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But for the sake of this article, we will stick to the first option - using callbacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common issues with database transactions
&lt;/h2&gt;

&lt;p&gt;While database transactions are crucial for maintaining data consistency in Laravel, there are some common issues that developers may encounter when using them, particularly with jobs and listeners. In this section, we will discuss these issues in more detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  ModelNotFoundException in queued jobs
&lt;/h3&gt;

&lt;p&gt;Jobs firing with models that have never been saved because of rollbacks, a.k.a. &lt;code&gt;ModelNotFoundException&lt;/code&gt; in jobs.&lt;/p&gt;

&lt;p&gt;Consider a scenario where you use a job to create a new user and add some records to the database. However, if the transaction rolls back due to an error, the job may be dispatched with incomplete or non-existent data. This can cause the &lt;code&gt;ModelNotFoundException&lt;/code&gt; exception to be thrown, as the job will attempt to access a model that has never been saved. This can be particularly problematic if the job is responsible for sending important notifications or performing other critical actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event listeners performing actions that cannot be rolled back
&lt;/h3&gt;

&lt;p&gt;Suppose you have a listener that performs an external API call to sync data with a third-party service. If the transaction is rolled back, this action cannot be undone, leading to data inconsistencies between your application and the external service. This can cause significant problems, especially if the external service is business-critical.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solutions
&lt;/h2&gt;

&lt;p&gt;Laravel has great and easy solutions for both problems to ensure that the jobs, or listeners, are not executed until after the database transaction is committed.&lt;/p&gt;

&lt;p&gt;Let's have a look!&lt;/p&gt;

&lt;h3&gt;
  
  
  Dispatching a Laravel job after a transaction is committed
&lt;/h3&gt;

&lt;p&gt;To ensure that jobs are only dispatched after the transaction has been committed, you can use the &lt;code&gt;afterCommit&lt;/code&gt; method. This method will only dispatch the job after the transaction has been committed successfully. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Perform database queries here&lt;/span&gt;

    &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;afterCommit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// alternatively, if the job uses the Dispatchable trait:&lt;/span&gt;
    &lt;span class="c1"&gt;// MyJob::dispatch($data)-&amp;gt;afterCommit();&lt;/span&gt;

    &lt;span class="c1"&gt;// Perform other operations that could potentially fail&lt;/span&gt;
    &lt;span class="c1"&gt;// and roll back the transaction.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, for more control, you can also use a &lt;code&gt;DB::afterCommit()&lt;/code&gt; method to provide a callback that will run after the transaction is committed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Perform database queries here&lt;/span&gt;

    &lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;afterCommit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Perform other operations that could potentially fail&lt;/span&gt;
    &lt;span class="c1"&gt;// and roll back the transaction.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Delaying a Laravel event listener to run after a transaction is committed
&lt;/h3&gt;

&lt;p&gt;To ensure that listeners are only executed after the transaction has been committed, you can set the &lt;code&gt;$afterCommit&lt;/code&gt; property on your listener. This method will delay the execution of the listener until the transaction has been committed successfully. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendNotificationListener&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$afterCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MyEvent&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send notification email here&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;It does not matter whether the listener is synchronous or asynchronous (queued, implementing &lt;code&gt;ShouldQueue&lt;/code&gt; interface) - Laravel will only execute this event &lt;strong&gt;after&lt;/strong&gt; the database transaction is committed.&lt;/p&gt;

&lt;p&gt;Very convenient!&lt;/p&gt;




&lt;p&gt;Handling jobs and listeners within database transactions requires careful consideration to ensure that your application's data remains consistent. By using the &lt;code&gt;afterCommit&lt;/code&gt; method to dispatch jobs later, and the &lt;code&gt;$afterCommit = true&lt;/code&gt; property on listeners to delay them until after the transaction has been committed, you can avoid common issues such as &lt;code&gt;ModelNotFoundException&lt;/code&gt; and external API calls that cannot be rolled back. Using these methods you can ensure that your Laravel application operates reliably and consistently.&lt;/p&gt;

&lt;p&gt;Hope you learned something new today!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>programming</category>
    </item>
    <item>
      <title>What is complexity? Write Better Laravel</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Fri, 08 Jul 2022 13:40:27 +0000</pubDate>
      <link>https://dev.to/arukomp/what-is-complexity-write-better-laravel-4n6h</link>
      <guid>https://dev.to/arukomp/what-is-complexity-write-better-laravel-4n6h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Write Better Laravel” is a new blog series about designing sustainable, clean code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to write better code, we first must understand our enemy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is “complexity”?&lt;/li&gt;
&lt;li&gt;How can you tell if the system is unnecessarily complex?&lt;/li&gt;
&lt;li&gt;What causes the system to become complex?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you understand complexity and how to spot it, you will start writing better code that is simpler to understand, use, extend and maintain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Complexity&lt;/strong&gt; is anything related to the structure of a software system that makes it hard to understand and modify the system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://arunas.dev/write-better-laravel-what-is-complexity/"&gt;Click here to read the rest of the article...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>programming</category>
      <category>codequality</category>
      <category>php</category>
    </item>
    <item>
      <title>🚀 Spike billing has LAUNCHED!</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Tue, 05 Jul 2022 16:28:32 +0000</pubDate>
      <link>https://dev.to/arukomp/spike-billing-has-launched-3661</link>
      <guid>https://dev.to/arukomp/spike-billing-has-launched-3661</guid>
      <description>&lt;p&gt;Just wanted to announce that &lt;strong&gt;&lt;a href="https://spike.opcodes.io/"&gt;Spike billing&lt;/a&gt;&lt;/strong&gt; - a Laravel package to bootstrap your project with automatic subscription billing - &lt;strong&gt;has now launched&lt;/strong&gt;! 🎉🎉🎉&lt;/p&gt;




&lt;p&gt;Spike makes it easy to charge &lt;strong&gt;subscriptions&lt;/strong&gt; and &lt;strong&gt;one-off purchases&lt;/strong&gt; in your &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt; app.&lt;/p&gt;

&lt;p&gt;It comes with &lt;strong&gt;credit management solution&lt;/strong&gt; out of the box, so that your users/teams can purchase credits to spend on using your app - it's perfect for paid APIs.&lt;/p&gt;

&lt;p&gt;Users get a beautiful &lt;strong&gt;billing portal&lt;/strong&gt; where they can see the available purchases/subscriptions, manage their payment methods, see their invoices, and also view their activity and credit usage - tons of great stuff. &lt;/p&gt;

&lt;p&gt;You will save hundreds of hours of development time and be able to launch your project much faster.&lt;/p&gt;




&lt;p&gt;There are a few &lt;strong&gt;&lt;a href="https://spike.opcodes.io/#pricing"&gt;early bird licenses&lt;/a&gt;&lt;/strong&gt; available, so hurry before they're gone.&lt;/p&gt;

&lt;p&gt;Hope you like the project, and do let me know if you have any questions or feedback. &lt;/p&gt;

&lt;p&gt;Thanks! 🙌&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>package</category>
      <category>saas</category>
      <category>billing</category>
    </item>
    <item>
      <title>How to use Laravel Facades safely</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Mon, 13 Jun 2022 08:17:43 +0000</pubDate>
      <link>https://dev.to/arukomp/how-to-use-laravel-facades-safely-1lc5</link>
      <guid>https://dev.to/arukomp/how-to-use-laravel-facades-safely-1lc5</guid>
      <description>&lt;p&gt;It's not exactly clear in the &lt;a href="https://laravel.com/docs/9.x/facades"&gt;Laravel documentation&lt;/a&gt;, but there's one thing the Facades do that might introduce accidental bugs in your system:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Facades are like singletons.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike traditional service container bindings with anonymous functions, Facades &lt;strong&gt;retain&lt;/strong&gt; the resolved instance and use that in future Facade calls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arunas.dev/laravel-facades-gotcha/"&gt;In this article&lt;/a&gt; I explain why this is happening, and offer a couple solutions to prevent this bug in your code.&lt;/p&gt;

&lt;p&gt;Let me know what you think!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>programming</category>
      <category>beginners</category>
      <category>php</category>
    </item>
    <item>
      <title>Developer-friendly Landing Pages</title>
      <dc:creator>Arunas Skirius</dc:creator>
      <pubDate>Tue, 07 Jun 2022 11:11:00 +0000</pubDate>
      <link>https://dev.to/arukomp/developer-friendly-landing-pages-4hfn</link>
      <guid>https://dev.to/arukomp/developer-friendly-landing-pages-4hfn</guid>
      <description>&lt;p&gt;&lt;strong&gt;I don't like page builders.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As an "experienced" developer, I like having control over my websites. Being able to see, edit and publish any fine-tuned changes in HTML, CSS, JavaScript and all of the backend logic. &lt;/p&gt;

&lt;p&gt;That is not something many of the "Landing Page builders" can give or promise. They are often filled with unnecessary bloat, making for a worse experience for the visitor.&lt;/p&gt;

&lt;p&gt;They also cost a ton. 😵‍💫&lt;/p&gt;

&lt;p&gt;I went on to build the landing page myself from scratch, using some of the easiest and fastest frameworks available today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ok, then what?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build the pages yourself with &lt;em&gt;Next.js/Nuxt.js&lt;/em&gt; + &lt;em&gt;some CSS framework&lt;/em&gt; + &lt;em&gt;Vercel/Netlify&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Since I have experience with Vue.js + Tailwind, I chose the tools geared for that. You might choose different ones if you're into React, Angular or Svelte, but the point is - it's there, it's free, and really easy to use.&lt;/p&gt;

&lt;p&gt;By building these landing pages yourself, instead of using page builders - you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retain full control of the website. Make any changes at any time, no matter how complex they are&lt;/li&gt;
&lt;li&gt;don't have to pay hefty fees for the page builders&lt;/li&gt;
&lt;li&gt;the website is much much faster&lt;/li&gt;
&lt;li&gt;you get to write more code (isn't that the fun part??)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more about my experience of building a fast and beautiful landing page in just a few hours here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arunas.dev/developer-friendly-landing-pages/"&gt;https://arunas.dev/developer-friendly-landing-pages/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope this inspires some more of you to ditch the builders and make it your own! 😄 I mean, I know I'm in the right space, cos we're developers after all!&lt;/p&gt;

&lt;p&gt;Thanks everyone 🙌&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vercel</category>
      <category>tailwindcss</category>
      <category>landingpage</category>
    </item>
  </channel>
</rss>
