
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Wed, 15 Apr 2026 21:09:11 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Spice up your sites on Cloudflare Pages with Pages Functions General Availability]]></title>
            <link>https://blog.cloudflare.com/pages-function-goes-ga/</link>
            <pubDate>Thu, 17 Nov 2022 14:05:00 GMT</pubDate>
            <description><![CDATA[ Pages is officially a full stack platform with Pages Functions now Generally Available. Pages is harnessing the power and scalability of Workers and specializing them to align with the Pages developer experience. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4Qt2PNf7dtFOmbvvzhQvnn/03e6c9de323ee7a011607e61c5443610/image2-37.png" />
            
            </figure><p>Before we launched Pages back in April 2021, we knew it would be the start of something magical – an experience that felt “just right”. We envisioned an experience so simple yet so smooth that <b><i>any developer</i></b> could ship a website in seconds and add more to it by using the rest of our Cloudflare ecosystem.</p><p>A few months later, when we announced that Pages was a full stack platform in November 2021, that vision became a reality. Creating a development platform for just static sites was not the end of our Pages story, and with Cloudflare Workers already a part of our ecosystem, we knew we were sitting on untapped potential. With the introduction of Pages Functions, we empowered developers to take any static site and easily add in dynamic content with the power of Cloudflare Workers.</p><p>In the last year since Functions has been in open beta, we dove into an exploration on what kinds of full stack capabilities developers are looking for on their projects – and set out to fine tune the Functions experience into what it is today.</p><p><b>We’re thrilled to announce that Pages Functions is now generally available!</b></p>
    <div>
      <h2>Functions recap</h2>
      <a href="#functions-recap">
        
      </a>
    </div>
    <p>Though called “Functions” in the context of Pages, these functions running on our Cloudflare network are Cloudflare Workers in “disguise”. Pages harnesses the power and scalability of Workers and specializes them to align with the Pages experience our users know and love.</p><p>With Functions you can dream up the possibilities of dynamic functionality to add to your site – integrate with storage solutions, connect to third party services, use server side rendering with your favorite full stack frameworks and more. As Pages Functions opens its doors to production traffic, let’s explore some of the exciting features we’ve improved and added on this release.</p>
    <div>
      <h2>The experience</h2>
      <a href="#the-experience">
        
      </a>
    </div>
    
    <div>
      <h3>Deploy with Git</h3>
      <a href="#deploy-with-git">
        
      </a>
    </div>
    <p>Love to code? We’ll handle the infrastructure, and leave you to it.</p><p>Simply write a JavaScript/Typescript Function and drop it into a <b>functions</b> directory by committing your code to your Git provider. Our lightning fast CI system will build your code and deploy it alongside your static assets.</p>
    <div>
      <h3>Directly upload your Functions</h3>
      <a href="#directly-upload-your-functions">
        
      </a>
    </div>
    <p>Prefer to handle the build yourself? Have a special git provider not yet supported on Pages? No problem! After dropping your Function in your <b>functions</b> folder, you can build with your preferred CI tooling and then upload your project to Pages to be deployed.</p>
    <div>
      <h3>Debug your Functions</h3>
      <a href="#debug-your-functions">
        
      </a>
    </div>
    <p>While in beta, we learned that you and your teams value visibility above all. As on Cloudflare Workers, we’ve built a simple way for you to watch your functions as it processes requests – the faster you can understand an issue the faster you can react.</p><p>You can now easily view logs for your Functions by “tailing” your logs. For basic information like outcome and request IP, you can navigate to the Pages dashboard to obtain relevant logs.</p><div></div><p>For more specific filters, you can use</p>
            <pre><code>wrangler pages deployment tail</code></pre>
            <p>to receive a live feed of console and exception logs for each request your Function receives.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Bc7Zz0wMrVCuLV3Ll8RFN/e581f4cb24dc8c78f28346195d0cd789/image1-52.png" />
            
            </figure>
    <div>
      <h3>Get real time Functions metrics</h3>
      <a href="#get-real-time-functions-metrics">
        
      </a>
    </div>
    <p>In the dashboard, Pages aggregates data for your Functions in the form of request successes/error metrics and invocation status. You can refer to your metrics dashboard not only to better understand your usage on a per-project basis but also to get a pulse check on the health of your Functions by catching success/error volumes.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/20rgwkkI2erSSmySgkpdzV/8d1aba3bb5081816d1de891e28efb7eb/image4-20.png" />
            
            </figure>
    <div>
      <h3>Quickly integrate with the Cloudflare ecosystem</h3>
      <a href="#quickly-integrate-with-the-cloudflare-ecosystem">
        
      </a>
    </div>
    
    <div>
      <h4><b>Storage bindings</b></h4>
      <a href="#storage-bindings">
        
      </a>
    </div>
    <p>Want to go truly full stack? We know finding a storage solution that fits your needs and fits your ecosystem is not an easy task – but it doesn’t have to be!</p><p>With Functions, you can take advantage of our broad range of storage products including Workers KV, Durable Objects, R2, D1 and – very soon – <a href="https://developers.cloudflare.com/queues/">Queues</a> and <a href="https://developers.cloudflare.com/analytics/analytics-engine/">Workers Analytics Engine</a>! Simply create your namespace, bucket or database and add your binding in the Pages dashboard to get your full stack site up and running in just a few clicks.</p><p>From dropping in a quick comment system to rolling your own authentication to creating database-backed <a href="https://www.cloudflare.com/ecommerce/">eCommerce sites</a>, integrating with existing products in our developer platform unlocks an exponential set of use cases for your site.</p>
    <div>
      <h4><b>Secret bindings</b></h4>
      <a href="#secret-bindings">
        
      </a>
    </div>
    <p>In addition to adding environment variables that are available to your project at both build-time and runtime, you can now also add “secrets” to your project. These are encrypted environment variables which cannot be viewed by any dashboard interfaces, and are a great home for sensitive data like API tokens or passwords.</p>
    <div>
      <h3>Integrate with 3rd party services</h3>
      <a href="#integrate-with-3rd-party-services">
        
      </a>
    </div>
    <p>Our goal with Pages is always to meet you where you are when it comes to the tools you love to use. During this beta period we also noticed some consistent patterns in how you were employing Functions to integrate with common third party services. <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/">Pages Plugins</a> – our ready-made snippets of code – offers a plug and play experience for you to build the ecosystem of your choice around your application.</p><p>In essence, a Pages Plugin is a reusable – and customizable – chunk of runtime code that can be incorporated anywhere within your Pages application. It’s a “composable” Pages Function, granting Plugins the full power of Functions (i.e. Workers), including the ability to set up middleware, parameterized routes, and static assets.</p><p>With Pages Plugins you can integrate with a plethora of 3rd party applications – including officially supported <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/sentry/">Sentry</a>, <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/honeycomb/">Honeycomb</a>, <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/stytch/">Stytch</a>, <a href="https://developers.cloudflare.com/pages/platform/functions/plugins/mailchannels/">MailChannels</a> and more.</p>
    <div>
      <h3>Use your favorite full stack frameworks</h3>
      <a href="#use-your-favorite-full-stack-frameworks">
        
      </a>
    </div>
    <p>In the spirit of meeting developers where they are at, this sentiment also comes in the form of Javascript frameworks. As a big supporter of not only widely adopted frameworks but up and coming frameworks, our team works with a plethora of framework authors to create opportunities for you to play with their new tech and deploy on Pages right out of the box.</p>
    <div>
      <h4>Now compatible with Next.js 13 and more!</h4>
      <a href="#now-compatible-with-next-js-13-and-more">
        
      </a>
    </div>
    <p>Recently, we announced our <a href="/next-on-pages/">support for Next.js applications</a> which opt in to the Edge Runtime. Today we’re excited to announce we are now compatible with Next.js 13. Next.js 13 brings some most-requested modern paradigms to the Next.js framework, including nested routing, React 18's Server Components and streaming.</p><p>Have a different preference of framework? No problem.</p><p>Go full stack on Pages to take advantage of server side rendering (SSR) with one of many other officially supported frameworks like <a href="https://remix.run/">Remix</a>, <a href="https://kit.svelte.dev/">SvelteKit</a>, <a href="https://qwik.builder.io/qwikcity/overview/">QwikCity,</a> <a href="https://start.solidjs.com/getting-started/what-is-solidstart">SolidStart</a>, <a href="https://astro.build/">Astro</a> and <a href="https://nuxtjs.org/">Nuxt</a>. You can <a href="/pages-full-stack-frameworks">check out our blog post on SSR support on Pages</a> and how to get started with some of these frameworks.</p>
    <div>
      <h3>Go fast in advanced mode</h3>
      <a href="#go-fast-in-advanced-mode">
        
      </a>
    </div>
    <p>While Pages Functions are powered by Workers, we understand that at face-value they are not exactly the same. Nevertheless, for existing users who are perhaps using Workers and are keen on trying Cloudflare Pages, we’ve <a href="https://developers.cloudflare.com/pages/platform/functions/advanced-mode/">got a direct path</a> to get you started quickly.</p><p>If you already have a single Worker and want an easy way to go full stack on Pages, you can use Pages Function’s “advanced mode”. Generate an <a href="https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#syntax-module-worker">ES module Worker</a> called <code>_worker.js</code> in the output directory of your project and deploy!This can be especially helpful if you’re a framework author or perhaps have a more complex use case that does not fit into our file-based router.</p>
    <div>
      <h2>Scaling without limits</h2>
      <a href="#scaling-without-limits">
        
      </a>
    </div>
    <p>So today, as we announce Functions as generally available we are thrilled to allow your traffic to scale. During the Open Beta period, we imposed a daily limit of 100,000 free requests per day as a way to let you try out the feature. While 100,000 requests per day remains the free limit today, you can now pay to truly go unlimited.</p><p>Since Functions are just “special” Workers, with this announcement you will begin to see your Functions usage reflected on your bill under the Workers Paid subscription or via your Workers Enterprise contract. Like Workers, when on a paid plan, you have the option to choose between our two usage models – Bundled and Unbound – and will be billed accordingly.</p><p>Keeping Pages on brand as Cloudflare’s “gift to the Internet”, you will get unlimited free static asset requests and will be billed primarily on dynamic requests. You can <a href="https://developers.cloudflare.com/pages/platform/functions/pricing/">read more</a> about how billing with Functions works in our documentation.</p>
    <div>
      <h2>Get started today</h2>
      <a href="#get-started-today">
        
      </a>
    </div>
    <p>To start jamming, head over to the <a href="https://developers.cloudflare.com/pages/platform/functions/">Pages Functions docs</a> and <a href="/pages-full-stack-frameworks">check out our blog</a> on some of the best frameworks to use to deploy your first full stack application. As you begin building out your projects be sure to let us know in the <a href="https://discord.com/channels/595317990191398933/910978223968518144">#functions channel</a> under Pages of our <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a>. Happy building!</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Full Stack]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">0qAOpwZHFx8u2Lq0PKf8c</guid>
            <dc:creator>Nevi Shah</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Pages now partners with your favorite CMS]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-headless-cms-partnerships/</link>
            <pubDate>Wed, 17 Nov 2021 13:58:49 GMT</pubDate>
            <description><![CDATA[ Cloudflare Pages partners up with some of the biggest headless CMSs ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Interest in headless CMSes has seen spectacular growth over the past few years with many businesses looking to adopt the tooling. As audiences consume content through new interfaces taking different forms — smartphones, wearables, personal devices — the idea of decoupling content with its backend begins to provide a better experience both for developing teams and end users. Because of this, we believe there are and will be more opportunities in the future to utilize headless CMSes which is why today, we’re thrilled to announce our partnerships with <a href="https://sanity.io/">Sanity</a> and <a href="https://strapi.io/">Strapi</a> and also share existing integrations with <a href="https://www.contentful.com/">Contentful</a> and <a href="https://wordpress.org/">WordPress</a> — all your favorite CMS providers.</p>
    <div>
      <h3>A little on headless CMSes</h3>
      <a href="#a-little-on-headless-cmses">
        
      </a>
    </div>
    <p>Headless CMSes are one of the most common API integrations we’ve seen so far among you and your teams — whether it’s for your marketing site, blog or <a href="https://www.cloudflare.com/ecommerce/">e-commerce site</a>. It provides your teams the ability to input the contents of your site through a user-friendly interface and store them in a database, so that updates can easily be made to your site without touching the code base. As a Jamstack platform, a big part of our roadmap is understanding how we can build our own tools or provide integrations for tools that fit in with your development ecosystem and Pages, which is why in August this year we <a href="/introducing-deploy-hooks-for-cloudflare-pages/">announced Pages support for Deploy Hooks</a>.</p>
    <div>
      <h3>What’s a hook got to do with it?</h3>
      <a href="#whats-a-hook-got-to-do-with-it">
        
      </a>
    </div>
    <p>Deploy Hooks are the key to what allows you to connect and trigger deployments in Pages via updates made in your headless CMS. As developers, instead of getting pinged several times a day to make content updates to your site, your marketing team can update the site directly within the headless CMS’s interface by way of a Deploy Hook. This is a URL created on Pages that accepts an HTTP POST request to trigger new deployments outside the realm of your git commands. You can configure settings within your CMS to accept the Deploy Hook so that anytime content is updated within your CMS, a new deployment is started in the Pages dashboard automatically — it couldn’t be any easier!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7Ga9mYZKafjYTaWyk9Pyof/58187824144d2e7ad4066898b2a88272/image2-18.png" />
            
            </figure>
    <div>
      <h3>How can I create a Deploy Hook?</h3>
      <a href="#how-can-i-create-a-deploy-hook">
        
      </a>
    </div>
    <p>Within the Pages interface, there are two things you need to do to create your Deploy Hook:</p><ol><li><p><b>Choose your Deploy Hook name:</b> You can name your deploy hook anything you’d like</p></li><li><p><b>Select the Branch to Build:</b> You can specify which branch will be built and deployed when the URL is requested with the Deploy Hook.</p></li></ol><div></div><p>Once you are given your Deploy Hook, you’re all set to set up a webhook within your chosen CMS where you will paste your Deploy Hook.</p><p>That’s it! Now leave it to your marketing team to update their rich content and watch the builds trigger automatically to update your site!</p>
    <div>
      <h3>Our partners</h3>
      <a href="#our-partners">
        
      </a>
    </div>
    <p>Of course, Deploy Hooks is just a starting point of ways we can provide a better dev experience for your team when using the headless CMS of your choice with your Pages site. But our story of integrations does not stop here. Introducing our CMS partners and integrations: <a href="https://sanity.io/">Sanity</a>, <a href="https://strapi.io/">Strapi</a>, <a href="https://www.contentful.com/">Contentful</a>, and <a href="https://wordpress.org/">WordPress</a>!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4cHjlUzTb0cWXGCgL1rrbk/0b23895d03dfd20c477fed63199c9ed4/image1-38.png" />
            
            </figure><p>We continue to see the highest usage rates of these four CMSes on Pages among you and your teams, and in the months to come we’ll be working closely with our partners to build even more for you.</p><blockquote><p><i>We’re delighted to partner with Cloudflare and excited by this new release from Cloudflare Pages. At Sanity, we care deeply about people working with content on our platform. Cloudflare’s new deploy hooks allow developers to automate builds for static sites based on content changes, which is a huge improvement for content creators. Combining these with structured content and our GROQ-powered Webhooks, our customers can be strategic about when these builds should happen. We’re stoked to be part of this release and can’t wait to see what the community will build with Sanity and Cloudflare!</i>- <b>Even Westvang, Co-founder, Sanity.io</b></p></blockquote><p>Check out <a href="https://www.sanity.io/blog/deploying-a-next-js-site-on-cloudflare-pages-with-webhooks">Sanity’s video tutorial</a> on how to build your site using Pages and Sanity!</p><blockquote><p><i>At Strapi, we’re excited about this partnership with Cloudflare because it enables developers to abstract away the complexity of deploying changes to production for content teams. By using the Deploy Hook for Strapi, everyone can push new content and updates quickly and autonomously.</i>- <b>Pierre Burgy, CEO, Strapi.io</b></p></blockquote><blockquote><p>With this integration, our customers can work more efficiently and cross-functionally with their teams. Marketing teams can update Contentful directly to automatically trigger deployments without relying on their developers to update any of their code base, which results in a better, more productive experience for all teams involved.- <b>Jeff Blattel, Director of Technical Partnerships at Contentful</b></p></blockquote>
    <div>
      <h3>Get started</h3>
      <a href="#get-started">
        
      </a>
    </div>
    <p>For now, to learn more about how you can connect your Pages project to one of our partner CMSes, check out our <a href="https://developers.cloudflare.com/pages/platform/deploy-hooks">Deploy Hooks documentation</a> to deploy your first project today!</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Serverless]]></category>
            <guid isPermaLink="false">1eW2QQJIAbIQYiIuqUuz31</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Abhi Das</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Pages now offers GitLab support]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-partners-with-gitlab/</link>
            <pubDate>Wed, 17 Nov 2021 13:58:44 GMT</pubDate>
            <description><![CDATA[ Cloudflare Pages partners up with GitLab for full git integration. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In the early stages of our ideation of Pages, we set out to build a platform with a smooth developer experience that integrates seamlessly with your existing workflow. However, after <a href="/cloudflare-pages-ga/">announcing Pages’ general availability</a>, we realized our platform may not actually be usable by every developer. Before today, only those of you who used GitHub as your source code management tool could take advantage of the Pages experience.</p><p>As part of Full Stack Week, we’re opening the doors of our platform to even more users by announcing our <a href="https://gitlab.com/">integration with GitLab</a> — <a href="https://gitlab.com/">the DevOps platform</a>! You can now create new Pages projects by connecting your repos stored on GitLab and make site changes there via your usual git commands. And what’s more? We’re also launching an official partnership with GitLab to bring you even better integrations with the git provider in the months to come.</p>
    <div>
      <h3>Why GitLab?</h3>
      <a href="#why-gitlab">
        
      </a>
    </div>
    <p>As a <a href="https://www.cloudflare.com/the-net/jamstack-websites/">Jamstack platform</a>, our goal is to enable you, the developer, to focus on what you do best — code, code, code — without the heavy lifting! Not only does this mean giving you all the tools you need to build out a <a href="/cloudflare-pages-goes-full-stack">full stack site</a> but also provide you with integrations that fit your development needs. By expanding our platform ecosystem to GitLab, Cloudflare can now serve the needs of a broader developer community collaborating on their sites.</p><p>Since our April launch, one of the most common questions and pieces of feedback we’ve received in customer calls, on <a href="https://discord.com/invite/cloudflaredev">Discord</a>/<a href="https://twitter.com/CloudflareDev">Twitter</a>, and on our <a href="https://community.cloudflare.com/">community threads</a> centered around GitLab. We knew our git integration story couldn’t just stop at one provider, especially given the diversity in tooling we see among our community. So it became glaringly obvious we needed to extend Pages to the GitLab community.</p>
    <div>
      <h3>Our partnership</h3>
      <a href="#our-partnership">
        
      </a>
    </div>
    <p>Today, we’re proud to now be <a href="https://about.gitlab.com/partners/technology-partners/">official technology partners</a> with GitLab Inc. In addition to our git integration, the goal of our partnership is to improve existing and develop future integrations, so your teams can seamlessly collaborate and accelerate site delivery and updates at scale. As you begin using Pages with GitLab, our teams will be working closely together in a cross-collaborative approach for new integrations.</p><blockquote><p><i>Developers can be more productive when they create, test, secure and deploy software from a single devops application instead of bouncing between multiple different tools. Cloudflare Pages’ integration with GitLab makes it easier for joint users to develop and deploy new code to Cloudflare’s network using the same syntax and git commands they’re already comfortable using.</i>— Michael LeBeau, Alliance Manager at GitLab</p></blockquote>
    <div>
      <h3>Get started</h3>
      <a href="#get-started">
        
      </a>
    </div>
    <p>To set up your first project with GitLab, just create a new project in the <a href="https://dash.cloudflare.com/">Pages dashboard</a>. Select “GitLab” and Pages will bring you to your GitLab sign-in screen where you can sign in to your account. Then, select the repo with which you’d like to create your project, configure your build settings, and deploy! From here, you can begin making changes to your site directly via commits to GitLab, triggering a new build every time.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2HsCbBWpGhaEPdpzvysfeK/3c5f09439aae1ae7c8aecf9225e8540b/image2-16.png" />
            
            </figure><p>Have questions? To get started, check out the <a href="https://developers.cloudflare.com/pages/">Pages docs</a> and be sure to leave us some feedback by clicking the “Give Feedback” button there. Show us what you build by joining the chatter in our Discord channel.</p><p>Happy developing!</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">4XWE8zcAlcsyvCbdbnQDPW</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Sean Brant</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing WebSockets Support in Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/introducing-websockets-in-workers/</link>
            <pubDate>Wed, 14 Apr 2021 13:02:00 GMT</pubDate>
            <description><![CDATA[ WebSockets are a powerful new addition to the Workers platform that unlocks real-time use cases in your application. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>UPDATE - JAN, 24, 2022: We've made optimizations that can reduce your bill when using WebSockets with Workers Unbound. For more information, see <a href="/workers-optimization-reduces-your-bill/">A Workers optimization that reduces your bill</a>.</p><p>Today, we're releasing support for WebSockets in Cloudflare Workers.</p><p>WebSockets unlock powerful use-cases in your serverless applications — live-updating, interactive experiences that bridge the gap between your users and Workers' powerful network and runtime APIs.</p><p>In this blog post, we’ll walk you through the basics of using WebSockets with Workers. That being said, WebSockets on their own aren’t immediately useful -- to power the interactivity, you need to coordinate a storage layer to go with them. With the addition of Durable Objects as a solution to building coordinated state on the edge, you can combine the power of interactive compute (WebSockets) with coordinated state (Durable Objects), and build incredible real-time applications. Durable Objects was <a href="/durable-objects-open-beta/">released in open beta at the end of last month</a>, and later in this blog post, we’ll explore how Durable Objects are well-suited towards building with WebSockets.</p>
    <div>
      <h2>Getting started with WebSockets in Workers</h2>
      <a href="#getting-started-with-websockets-in-workers">
        
      </a>
    </div>
    <p>WebSockets allow clients to open a connection back to a server (or in our case, Cloudflare Workers) that can receive and send messages. Instead of polling a server continuously for new information, a single WebSocket connection can constantly receive data and unlock the kind of live use-cases that we're used to in modern applications: things like live scores for sports events, real-time chat, and more.</p><p>Let's dig into how to use WebSockets in Workers so you can understand how easy they are to pick up and start using in your application.</p>
    <div>
      <h3>Instantiating WebSocketPairs in Cloudflare Workers</h3>
      <a href="#instantiating-websocketpairs-in-cloudflare-workers">
        
      </a>
    </div>
    <p>Workers respond to HTTP requests sent from clients. A Request comes in, and a Response comes back. You can begin using WebSockets in your Workers code by looking for an Upgrade header in any incoming requests: this is an indication from the client that it's looking to set up a new WebSocket:</p>
            <pre><code>addEventListener('fetch', event =&gt; {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const upgradeHeader = request.headers.get("Upgrade")
  if (upgradeHeader !== "websocket") {
    return new Response("Expected websocket", { status: 400 })
  }

  // Set up WebSocket
}</code></pre>
            <p>If the Upgrade header is present, we set up a new instance of WebSocketPair — a set of two WebSockets, one for the client, and one for the server. In our code, we'll use the server WebSocket to set up our server-side logic, and return the client socket back to the client. Note the usage of the 101 status code (<a href="https://httpstatuses.com/101">"Switching Protocols"</a>) and the new webSocket property on Response:</p>
            <pre><code>addEventListener('fetch', event =&gt; {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const upgradeHeader = request.headers.get("Upgrade")
  if (upgradeHeader !== "websocket") {
    return new Response("Expected websocket", { status: 400 })
  }

  const [client, server] = Object.values(new WebSocketPair())
  await handleSession(server)

  return new Response(null, {
    status: 101,
    webSocket: client
  })
}</code></pre>
            <p>In our handleSession function, we call the accept function on our WebSocket. This tells the Workers runtime that it will be responsible for this server WebSocket from the WebSocketPair. We can then handle events on the WebSocket, by using addEventListener and providing callback functions, particularly for message events (when new data comes in), and close events, when the WebSocket connection closes:</p>
            <pre><code>async function handleSession(websocket) {
  websocket.accept()
  websocket.addEventListener("message", async message =&gt; {
    console.log(message)
  })

  websocket.addEventListener("close", async evt =&gt; {
    // Handle when a client closes the WebSocket connection
    console.log(evt)
  })
}</code></pre>
            
    <div>
      <h3>Connecting to WebSockets in a Browser Client</h3>
      <a href="#connecting-to-websockets-in-a-browser-client">
        
      </a>
    </div>
    <p>With WebSockets support added in the Workers function, we can now connect to it from a client. Workers' WebSocket support works directly with the browser-default WebSocket class, meaning that you can connect to it directly in vanilla JavaScript without any additional libraries.</p><p>In fact, this connection process is so simple that it almost explains itself by just looking at the code. Just pass the WebSocket URL to a new instance of WebSocket, and then watch for new events on the WebSocket itself, like open (when the WebSocket connection opens), message (when new data comes in), and close (when the WebSocket connection closes):</p>
            <pre><code>let websocket = new WebSocket(url)
if (!websocket) {
  throw new Error("Server didn't accept WebSocket")
}

websocket.addEventListener("open", () =&gt; {
  console.log('Opened websocket')
})

websocket.addEventListener("message", message =&gt; {
  console.log(message)
})

websocket.addEventListener(“close”, message =&gt; {
  console.log(‘Closed websocket’)
})

websocket.addEventListener(“error”, message =&gt; {
  console.log(‘Something went wrong with the WebSocket’)

  // Potentially reconnect the WebSocket connection, by instantiating a
  // new WebSocket as seen above, and connecting new events
  // websocket = new WebSocket(url)
  // websocket.addEventListener(...)
})

// Close WebSocket connection at a later point
const closeConnection = () =&gt; websocket.close()</code></pre>
            
    <div>
      <h2>Durable Objects and WebSockets</h2>
      <a href="#durable-objects-and-websockets">
        
      </a>
    </div>
    <p>WebSockets are a powerful addition to the Workers toolkit, but you'll notice that in the above example, your WebSocket connections are effectively stateless. I can click the "Click me" button a hundred times, send data back and forth in my WebSocket connection, but as soon as I refresh the page, all of that information is gone. How do we provide state for our WebSocket and for our application in general?</p><p>Our solution for this is Durable Objects. Instead of using external state solutions and making requests to origin servers for a database or API provider, Durable Objects provide simple APIs for accessing and updating stateful data directly at the edge, right alongside your serverless functions.</p><p>Durable Objects complements WebSockets perfectly, providing the stateful primitives needed to make WebSockets at the edge uniquely powerful and performant. When we initially announced the Durable Objects private beta, we also previewed WebSockets in Workers for the first time, as part of our live chat demo. That demo, <a href="https://edge-chat-demo.cloudflareworkers.com/">available here</a>, still serves as a great example of a more complex application that can be built entirely on Workers, Durable Objects, and WebSockets.</p>
    <div>
      <h2>Additional resources</h2>
      <a href="#additional-resources">
        
      </a>
    </div>
    <p>With the release of WebSocket support in Workers, we're providing two resources to help you get started.</p><p>First, a new websocket-template that will help you get started with WebSockets on Workers. The template includes a simple HTML page that shows you how to connect to a Workers-based WebSocket, send and receive messages, as well as how to close the connection and handle any unknown messages or data. This template is the logical extension of the code that I shared above, and could be extended for most use-cases with WebSockets in your application.</p><p><a href="https://websocket-template.cloudflare-docs.workers.dev/">You can see a demo version of the project here.</a></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2sdk1ix59XmdNLQcgcqR7W/0853ac10e9e44d7725107db975501057/image1-17.png" />
            
            </figure><p><a href="https://developers.cloudflare.com/workers/learning/using-websockets">We've also released documentation for WebSocket usage in Workers.</a> This includes a new Learning page on working with WebSockets, as well as a collection of reference documentation for <a href="https://developers.cloudflare.com/workers/runtime-apis/websockets">understanding the new WebSocketPair API</a>, and changes to the Response class to allow WebSocket upgrade responses, as seen in the code above.</p>
    <div>
      <h2>Pricing considerations</h2>
      <a href="#pricing-considerations">
        
      </a>
    </div>
    <p>Today, WebSockets incur a request charge when the connection is first established, followed by the underlying Worker’s duration charge as long as the WebSocket is active. There is no per-message fee for WebSockets.</p><p>This means that if you create a Worker on the Workers Unbound plan and then pass-through a WebSocket connection to another server or to a Durable Object, you’ll be billed wall-clock duration for the entire time the connection is open. This may be surprising, since the Worker itself is not participating in the request.</p><p>This is currently due to a limitation in the platform, where the Worker passing the WebSocket through remains active for the duration of the WebSocket connection. We’re working to make it so that you will not be charged duration time for proxying a WebSocket in the near future.</p><p>Until we make this fix, if you want to use WebSockets with Durable Objects, we recommend using Workers Bundled rather than Unbound to pass the WebSocket connection to the Durable Object to avoid surprise charges. You should not use Workers Unbound on a Worker that passes on a WebSocket connection to Durable Objects.</p><p>Today, while in beta, Durable Objects are not being billed, so there is no cost for terminating the WebSocket connection in a Durable Object.</p><p>We’re currently working on the best way to price WebSockets that are terminated in a Durable Object.</p><p>Our current thinking is that when using WebSockets, you'll be charged for wall clock time whenever a message is being processed by the Durable Object on any WebSocket connection - this charge would be shared across all WebSockets connected to a given Durable Object. When there is no CPU activity on a Durable Object, but any number of WebSocket connections remain established, you'll be billed a much lower active connection charge, per second.</p><p>We want your feedback on how this pricing would affect your usage of Workers! Send the <a href="#">Workers Product</a> team your thoughts on how we could improve your WebSockets experience, particularly on pricing.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Product News]]></category>
            <guid isPermaLink="false">3J6zqhA5gl24bC864TCSIy</guid>
            <dc:creator>Kristian Freeman</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Pages is now Generally Available]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-ga/</link>
            <pubDate>Mon, 12 Apr 2021 13:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re excited to announce that Cloudflare Pages is now Generally  Available and ready for your production needs. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In December, <a href="/cloudflare-pages/">we announced</a> the beta of <a href="https://pages.cloudflare.com/">Cloudflare Pages</a>: a fast, secure, and free way for frontend developers to build, <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">host</a>, and collaborate on <a href="https://www.cloudflare.com/the-net/jamstack-websites/">Jamstack sites</a>.</p><p>It’s been incredible to see what happens when you put a powerful tool in developers’ hands. In just a few months of beta, thousands of developers have deployed over ten thousand projects, reaching millions of people around the world.</p><p>Today, we’re excited to announce that Cloudflare Pages is now available for anyone and ready for your production needs. We’re also excited to show off some of the new features we’ve been working on over the course of the beta, including: web analytics, built in redirects, protected previews, live previews, and optimized images (oh, my!). Lastly, we’ll give you a sneak peek into what we'll be working on next to make Cloudflare Pages your go-to platform for deploying not just static sites, but full-stack applications.</p>
    <div>
      <h2>What is Cloudflare Pages?</h2>
      <a href="#what-is-cloudflare-pages">
        
      </a>
    </div>
    <p>Cloudflare Pages radically simplifies the process of developing and deploying sites by taking care of all the tedious parts of web development. Now, developers can focus on the fun and creative parts instead.</p>
    <div>
      <h3>Seamless builds for developers</h3>
      <a href="#seamless-builds-for-developers">
        
      </a>
    </div>
    <p>Getting started with Cloudflare Pages is as easy as connecting your repository and selecting your framework and build commands.</p><p>Once you’re set up, the only magic words you’ll need are `git commit` and `git push`. We’ll take care of building and deploying your sites for you, so you won’t ever have to leave your current workflow.</p>
    <div>
      <h3>Instant feedback for teams</h3>
      <a href="#instant-feedback-for-teams">
        
      </a>
    </div>
    <p>With every change, Cloudflare Pages generates a new preview link and posts it to the associated pull request. The preview link makes sharing your work with others easy, whether they’re reviewing the code or the content for each change.</p>
    <div>
      <h3>Bullet-proof security and scale for enterprises</h3>
      <a href="#bullet-proof-security-and-scale-for-enterprises">
        
      </a>
    </div>
    <p>Every site developed with Cloudflare Pages is deployed to Cloudflare’s network of data centers in over 100 countries — the same network we’ve been building out for the past 10 years with the best performance and security for our customers in mind.</p>
    <div>
      <h2>But wait, that’s not all</h2>
      <a href="#but-wait-thats-not-all">
        
      </a>
    </div>
    <p>Over the past few months, our developers have been busy too, hardening our offering from beta to general availability, fixing bugs, and working on new features to make building powerful websites even easier.</p><p>Here are some of the new and improved features you may have missed.</p>
    <div>
      <h3>Integrated experience, every step of the way</h3>
      <a href="#integrated-experience-every-step-of-the-way">
        
      </a>
    </div>
    <p>With Cloudflare Pages, we set out to make developing and deploying sites easy at every step, and that doesn’t stop at production. Launch day is usually when the real work begins.</p><p><b>Built-in, free web analytics</b>Speaking of launch days, if there’s one question that’s on my mind on a launch day, it’s: how are things going?</p><p>As soon as the go-live button is pressed, I want to know: how many views are we getting? Was the effort worth it? Are users running into errors?</p><p>The weeks, or months after the launch, I still want to know: is our growth steady? Where is the traffic coming from? Is there anything we can do to improve the user’s experience?</p><p>With Pages, Cloudflare’s privacy-first <a href="https://www.cloudflare.com/web-analytics/">Web Analytics</a> are available to answer all of these essential questions for successfully running your website at scale. Later this week, you will be able to enable analytics with a single click and start tracking your site’s progress <i>and</i> performance, including metrics about your traffic and web core vitals.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1pYTpiov3ECJoBsQ5yPdR4/2bc5746f045639d69a78c7e244a18cab/image2-6.png" />
            
            </figure><p><b>_redirects file support</b>Websites are living projects. As you make updates to your product names, blog post titles, and site layouts, your URLs are bound to change as well. The challenge is not letting those changes leave dead URLs behind for your users to stumble over.</p><p>To avoid leaving behind a trail of dead URLs, you should create redirects that automatically lead the user to your content’s new home. The challenge with creating redirects is coordinating the code change that changes the URL in tandem with the creation of the redirect.</p><p>You can now do both with one swift commit.</p><p>By adding a <code>_redirects</code> file to the <a href="https://developers.cloudflare.com/pages/platform/build-configuration">build output directory</a> for your project, you can easily redirect users to the right URL. Just add the redirects into the file in the following format:</p><p><code>[source] [destination] [http code]</code></p><p>Example:</p>
            <pre><code>/home / 301
/contact-me /contact 301
/blog https://www.ghost.org 301</code></pre>
            <p>Cloudflare Pages makes it easy to create new redirects and import existing redirects using our new support for <code>_redirects</code> files.</p>
    <div>
      <h3>Jam harder</h3>
      <a href="#jam-harder">
        
      </a>
    </div>
    <p>When we started Cloudflare, people believed performance and security were at odds with each other, and tradeoffs had to be made between the two. We set out to show that that was wrong.</p><p>Today, we similarly believe that working collaboratively and moving fast are at odds with each other. As the saying goes, “If you want to go fast, go alone. If you want to go far, go together.”</p><p>We previously discussed the ways in which Cloudflare Pages allows developers and their stakeholders to move fast together, and we’ve built two additional improvements to make it even easier!</p><p><b>Protected previews with Cloudflare Access integration</b>One of the ways Cloudflare Pages simplifies collaboration is by generating unique preview URLs for each commit. The preview URLs make it easy for anyone on your team to check out your work in progress, take it for a spin, and provide feedback before the changes go live.</p><p>While it’s great to shop ideas with your coworkers and stakeholders ahead of the big day, the surprise element is what makes the big day, <b>The Big Day</b>.</p><p>With our new Cloudflare Access integration, restricting access to your preview deployments is as easy as clicking a button.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6qNwNxvMTTteDgZfbUurnL/d6c7a9dff6a125189cd2cbca25ed5141/image3-1.gif" />
            
            </figure><p>Cloudflare Access is a <a href="https://www.cloudflare.com/learning/security/glossary/what-is-zero-trust/">Zero Trust solution</a> — think of it like a bouncer checking each request to your site at the door. By default, we add the members of your Cloudflare organization, so when you send them a new preview link, they’re prompted with a one-time PIN that is sent to their email for authentication. However, you can modify the policy to integrate with your preferred SSO provider.</p><p>Cloudflare Access comes with 50 seats included in the free tier — enough to make sure no one leaks your new “dark mode” feature before you want them to.</p><p><b>Live previews with Cloudflare Tunnel</b>While preview deployments make it easy to share progress when you’re working asynchronously, sometimes a live collaboration session is the best way to crank out those finishing touches and last minute copy changes.</p><p>With Cloudflare Tunnel, you can expose your localhost through a secure tunnel to an easily shareable URL, so you can get live feedback from your teammates before you commit (pun intended).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6MEgCUB5cLsiFlT4yZKvE6/48b162b04646414520eef22cf7036092/image4-1.gif" />
            
            </figure>
    <div>
      <h3>Speed, security &amp; scalability — no really, we got you</h3>
      <a href="#speed-security-scalability-no-really-we-got-you">
        
      </a>
    </div>
    <p><b>Assets, optimized</b></p><p>It’s easy to get excited about all the new features you can play with, one of the real killer features of Pages is the performance and reliability.</p><p>We got a bit of a head start on performance because we built Pages on the same network we’ve been optimizing for performance for the past ten years. As a result, we learned a thing or two about accelerating web performance along the way.</p><p>One of the best tools for improving your site performance is by serving smaller content, which takes less time to transfer. One way to make your content smaller is via compression. We’ve recently introduced two types of compression to Pages:</p><p><b>Image compression:</b> Since images represent some of the largest types of content we serve, <a href="https://www.cloudflare.com/learning/performance/glossary/what-is-image-compression/">serving them efficiently</a> can have great impact on performance. To improve efficiency, we now use <a href="https://support.cloudflare.com/hc/en-us/articles/360000607372-Using-Cloudflare-Polish-to-compress-images">Polish</a> to <a href="https://www.cloudflare.com/learning/performance/glossary/what-is-image-compression/">compress your images</a>, and serve fewer bytes over the wire. When possible, we’ll also serve a WebP version of your image (and AVIF too, coming soon).</p><p><b>Gzip and Brotli:</b> Even smaller assets, such as HTML or JavaScript can benefit from compression. Pages will now serve content compressed with gzip or Brotli, based on the type of compression the client can support.</p><p>While we’ve been offering compression for a long time now (dating all the way back to 2012), this is the first time we’re able to pre-process the assets, at the time of the build step, rather than on the fly, resulting in even better compression.</p><p>Another way to make content smaller is by literally shrinking it.</p><p><b>Device-based resizing:</b> To make users’ experiences even smoother, especially on less reliable mobile devices, we want to make sure we’re not sending large images that will only get previewed on a small screen. Our new optimization will appropriately resize the image based on whether the device is mobile or desktop.</p><p>If you’re interested in more image optimization features, we have some announcements planned for later in the week, so stay tuned.</p>
    <div>
      <h2>What’s next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>While today’s milestone marks Cloudflare Pages as a production-ready product, like I said, that’s where our true work begins, not ends.</p><p>There are so many features we’re excited to support in the future, and we wanted to give you a small glimpse into what it holds:</p><p><b>GitLab / Bitbucket support</b>We started out by offering direct integration with GitHub to reach as many developers as we possibly could, but we want to continuously grow out the ecosystem we interact with.</p><p><b>Webhooks</b>If you’re managing all of your code and content through source control, it’s sufficient to rely on committing your code as a way to trigger a new preview. However, if you’re managing your code in one place, but the content in another, such as a CMS, you may still want to preview your content changes before they go live.</p><p>To enable you to do so, we’ll be providing an endpoint you’ll be able to call in order to trigger a brand new deployment via a webhook.</p><p><b>A/B testing</b>No matter how much local testing you’ve done, or how many co-workers you’ve received feedback from, some unexpected behavior (whether a bug or a typo) is eventually bound to slip, only to get caught in production. Your reviewers are human too, after all.</p><p>When the inevitable happens, however, you don’t want it impacting all of your users at once.</p><p>To give you better control of rolling out changes into production, we’re looking forward to offering you the ability to roll out your changes to a percentage of your traffic to gain confidence in your changes before you go to 100%.</p>
    <div>
      <h2>The future: full stack applications with Cloudflare Workers and Durable Objects</h2>
      <a href="#the-future-full-stack-applications-with-cloudflare-workers-and-durable-objects">
        
      </a>
    </div>
    <p>Supporting static sites is just the beginning of the journey for Cloudflare Pages. With redirects support, we’re starting to introduce the first bit of dynamic functionality to Pages, but our ambitions extend far beyond.</p><p>Our long term goal with Pages is to make full-stack application development as breezy an experience as static site development is today. We want to make Pages the deployment target for your static assets, and the APIs that make them dynamic. With Workers and Durable Objects, we believe we have just the toolset to build upon.</p><p>We’ll be starting by allowing you to deploy a Worker function by including it in your /api or /functions directory. Over time, we’ll be introducing new ways for you to deploy Durable Objects or utilize the KV namespaces in the same way.</p><p>Imagine, your entire application —  frontend, APIs, storage, data — all deployed with a single commit, easily testable in staging, and a single merge to deploy to production.</p>
    <div>
      <h2>Get started</h2>
      <a href="#get-started">
        
      </a>
    </div>
    <p><a href="https://dash.cloudflare.com/sign-up/pages">Sign up</a> or check out <a href="https://developers.cloudflare.com/pages/">our docs</a> to get started.</p><p>The best part about this is getting to see what you build, so if you’re building something cool, make sure to pop into <a href="https://discord.com/invite/cloudflaredev">our Discord</a> and tell us all about it.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">4cvWBTO5my91MDyN3lvFO7</guid>
            <dc:creator>Rita Kozlov</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Acquires Linc]]></title>
            <link>https://blog.cloudflare.com/cloudflare-acquires-linc/</link>
            <pubDate>Tue, 22 Dec 2020 13:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re excited to announce the acquisition of Linc, an automation platform to help front-end developers collaborate and build powerful applications. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Cloudflare has always been about democratizing the Internet. For us, that means bringing the most powerful tools used by the largest of enterprises to the smallest development shops. Sometimes that looks like putting our global network to work defending against large-scale attacks. Other times it looks like giving Internet users simple and reliable privacy services like 1.1.1.1.  Last week, it looked like <a href="https://pages.cloudflare.com/">Cloudflare Pages</a> — a fast, secure and free way to build and host your <a href="https://www.cloudflare.com/learning/performance/what-is-jamstack/">JAMstack sites</a>.</p><p>We see a huge opportunity with Cloudflare Pages. It goes beyond making it as easy as possible to deploy static sites, and extending that same ease of use to building full dynamic applications. By creating a seamless integration between Pages and <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>, we will be able to host the frontend and backend together, at the edge of the Internet and close to your users. The <a href="https://linc.sh/">Linc</a> team is joining Cloudflare to help us do just that.</p><p>Today, we’re excited to announce the acquisition of <a href="https://linc.sh/">Linc</a>, an automation platform to help front-end developers collaborate and build powerful applications. Linc has done amazing work with <a href="https://fab.dev/">Frontend Application Bundles</a> (FABs), making dynamic backends more accessible to frontend developers. Their approach offers a straightforward path to building end-to-end applications on Pages, with both frontend logic and powerful backend logic in one bundle. With the addition of Linc, we will accelerate Pages to enable richer and more powerful full-stack applications.</p><p>Combining Cloudflare’s edge network with Linc’s approach to server-side rendering, we’re able to set a new standard for performance on the web by delivering the speed of powerful servers close to users. Now, I’ll hand it over to Glen Maddern, who was the CTO of Linc, to share why they joined Cloudflare.</p><hr /><p>Linc and the Frontend Application Bundle (FAB) specification were designed with a single goal in mind: to give frontend developers the best possible tools to build, review, refine, and deploy their applications. An important piece of that is making server-side logic and rendering much more accessible, regardless of what type of app you're building.</p>
    <div>
      <h3>Static vs Dynamic frontends</h3>
      <a href="#static-vs-dynamic-frontends">
        
      </a>
    </div>
    <p>One of the biggest problems in frontend web development today is the dramatic difference in complexity when moving from generating static sites (e.g. building a directory full of HTML, JS, and CSS files) to hosting a full application (traditionally using NodeJS and a web server like Express). While you gain the flexibility of being able to render everything on-demand and customised for the current user, you increase your maintenance cost — you now have servers that you need to keep running. And unless you're operating at a global scale already, you'll often see worse end-user performance as your requests are only being served from one or maybe a couple of locations worldwide.</p><p>While serverless platforms have arisen to solve these problems for backend services and can be brought to bear on frontend apps, they're much less cost-effective than using static hosting, especially if the bulk of your frontend assets are static. As such, we've seen a rise of technologies under the umbrella term of "<a href="https://www.cloudflare.com/the-net/jamstack-websites/">JAMstack</a>"; they aim at making static sites more powerful (like rebuilding based off CMS updates), or at making it possible to deploy small pieces of server-side APIs as "cloud functions", along with each update of your app. But it's still fundamentally a limited architecture — you always have a static layer between you and your users, so the more dynamic your needs, the more complex your build pipeline becomes, or the more you're forced to rely on client-side logic.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3nHs2UUyT6chrUyhl6xyw0/c83dec72860b29808ddc81d5b23cc3e6/image4-26.png" />
            
            </figure><p>FABs took a different approach: a deployment artefact that could support the full range of server-side needs, from entirely static sites, apps with some API routes or cloud functions, all the way to full server-side streaming rendering. We also made it compatible with all the cloud hosting providers you might want, so that deploying becomes as easy as uploading a ZIP file. Then, as your needs change, as dynamic content becomes more important, as new frameworks arise that offer increasing performance or you look at moving which provider you're hosting with, you never need to change your tooling and deployment processes.</p>
    <div>
      <h3>The FAB approach</h3>
      <a href="#the-fab-approach">
        
      </a>
    </div>
    <p>Regardless of what framework you're working with, the FAB compiler generates a fab.zip file that has two components: a server.js file that acts as a server-side entry point, and an _assets directory that stores the HTML, CSS, JS, images, and fonts that are sent to the client.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6hCbaeFsNVeN579nyOCVfZ/e24bb3feb541c696d50cee8736cb629a/image3-43.png" />
            
            </figure><p>This simple structure gives us enough flexibility to handle all kinds of apps. For example, a static site will have a server.js of only a few auto-generated lines of server-side code, just enough to add redirects for any files outside the _assets directory. On the other end of the spectrum, an app with full server rendering looks and works exactly the same. It just has a lot more code inside its server.js file.</p><p>On a server running NodeJS, serving a compiled FAB is as easy as fab serve fab.zip, but FABs are really designed with production class hosting in mind. They make use of world-class <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDNs</a> and the best serverless hosting platforms around.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5iIRJAFAloTN8spJ8zbEIT/082f423dc57e5a03ba6a312e6675cbd7/image5-27.png" />
            
            </figure><p>When a FAB is deployed, it's often split into these component parts and deployed separately. Assets are sent to a <a href="https://www.cloudflare.com/developer-platform/products/r2/">low-cost object storage platform</a> with a CDN in front of it, and the server component is sent to dedicated serverless hosting. It's all deployed in an atomic, idempotent manner that feels as simple as uploading static files, but completely unlocks dynamic server-side code as part of your architecture.</p><p>That generic architecture works great and is compatible with virtually every hosting platform around, but it works slightly differently on Cloudflare Workers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5xdv1Txo6E6IuxLGuBUj6d/735efdbf5f13d90225e4e4dfa11e2c04/image2-43.png" />
            
            </figure><p>Workers, unlike other serverless platforms, truly runs at the edge: there is no CDN or load balancer in front of it to split off /_assets routes and send them directly to the Assets storage. This means that every request hits the worker, whether it's triggering a full page render or piping through the bytes for an image file. It might feel like a downside, but with Workers' performance and cost profile, it's quite the opposite — it actually gives us much more flexibility in what we end up building, and gets us closer to the goal of fully unlocking server-side code.</p><p>To give just one example, we no longer need to store our asset files on a dedicated static file host — instead, we can use Cloudflare's global key-value storage: Workers KV. Our server.js running inside a Worker can then map /_assets requests directly into the KV store and stream the result to the user. This results in significantly better performance than proxying to a third-party asset host.</p><p>What we've found is that Cloudflare offered the most "FAB-native" hosting option, and so it's very exciting to have the opportunity to further develop what they can do.</p>
    <div>
      <h3>Linc + Cloudflare</h3>
      <a href="#linc-cloudflare">
        
      </a>
    </div>
    <p>As we stated above, Linc's goal was to give frontend developers the best tooling to build and refine their apps, regardless of which hosting they were using. But we started to notice an important trend —  if a team had a free choice for where to host their frontend, they inevitably chose Cloudflare Workers. In some cases, for a period, teams even used Linc to deploy a FAB to Workers alongside their existing hosting to demonstrate the performance improvement before migrating permanently.</p><p>At the same time, we started to see more and more opportunities to fully embrace edge-rendering and make global serverless hosting more powerful and accessible. But the most exciting ideas required deep integration with the hosting providers themselves. Which is why, when we started talking to Cloudflare, everything fell into place.</p><p>We're so excited to join the Cloudflare effort and work on expanding Cloudflare Pages to cover the full spectrum of applications. Not only do they share our goal of bringing sophisticated technology to every development team, but with innovations like Durable Objects starting to offer new storage paradigms, the potential for a truly next-generation deployment, review &amp;  hosting platform is tantalisingly close.</p> ]]></content:encoded>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Acquisitions]]></category>
            <guid isPermaLink="false">5qB64EMTsm3aXN4gkJN1yx</guid>
            <dc:creator>Aly Cabral</dc:creator>
            <dc:creator>Glen Maddern</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing Cloudflare Pages: the best way to build JAMstack websites]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages/</link>
            <pubDate>Thu, 17 Dec 2020 14:00:00 GMT</pubDate>
            <description><![CDATA[ Across multiple cultures around the world, this time of year is a time of celebration and sharing of gifts with the people we care the most about. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Across multiple cultures around the world, this time of year is a time of celebration and sharing of gifts with the people we care the most about. In that spirit, we thought we'd take this time to give back to the developer community that has been so supportive of Cloudflare for the last 10 years.</p><p>Today, we’re excited to announce <a href="https://www.cloudflare.com/developer-platform/pages/">Cloudflare Pages</a>: a fast, secure and free way to <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">build and host</a> your <a href="https://www.cloudflare.com/learning/performance/what-is-jamstack/">JAMstack sites</a>.</p>
    <div>
      <h2>Today, the path from an idea to a website is paved with good intentions</h2>
      <a href="#today-the-path-from-an-idea-to-a-website-is-paved-with-good-intentions">
        
      </a>
    </div>
    <p>Websites are the way we express ourselves on the web. It doesn’t matter if you’re a hobbyist with a blog, or the largest of corporations with millions of customers — if you want to reach people outside the confines of 140 280 characters, the web is the place to be.</p><p>As a frontend developer, it’s your responsibility to bring this expression to life. And make no mistake — with so many frontend frameworks, tooling, and static site generators at your disposal — it’s a great time to be in your line of work.</p><p>That is, of course, right up until the point when you’re ready to show your work off to the world. That’s when things can start to get a little hairy.</p><p>At this point, continuing to keep things local rather than committing to source starts to become… irresponsible. But then: how do you quickly iterate and maintain momentum? As you change things, you need to make sure those changes don’t get lost — saving them to source control — while keeping in sync with what’s currently deployed to production.</p><p>There are no great solutions.</p><p>If you’re in a larger organization, you might have a DevOps organization devoted to exactly that: automating deployments using Continuous Integration (CI) tooling.</p><p>Most CI tooling, however, is quite cumbersome, and for good reason — to allow organizations to customize their automation, regardless of their stack and setup. But for the purpose of developing a website, it can still feel like an unnecessary and frustrating diversion on the road to delivering your web project. Configuring a .yaml file, adding and removing commands, waiting minutes for each build to run, and praying to the CI gods at each one that these are the right commands. Hopelessly rerunning the same build over and over, and expecting a different result.  </p><p>Often, hours are lost. The process stands in the way of you and doing your best work.</p>
    <div>
      <h2>Cloudflare Pages: letting frontend devs do what they do best</h2>
      <a href="#cloudflare-pages-letting-frontend-devs-do-what-they-do-best">
        
      </a>
    </div>
    <p>We think there’s a better way.</p><p>With Cloudflare Pages, we set out to simplify every step along the journey by tying deployment to your existing development workflow.</p>
    <div>
      <h3>Seamless Git integration, with builds built-in</h3>
      <a href="#seamless-git-integration-with-builds-built-in">
        
      </a>
    </div>
    <p>With Cloudflare Pages, all you have to do is select your repo, and tell us which framework you’re using. We’ll take care of chanting CI incantations on your behalf, while you keep doing what you were already doing: <code>git commit</code> and <code>git push</code> your changes — we’ll build and deploy them for you.</p><p>As the project grows, so do the stakes, and the number of collaborators.</p><p>For a site in production, changes need to be reviewed thoroughly. As the reviewer, looking at the code, and skimming for red flags only gets you so far. To thoroughly review, you have to commit or <code>git stash</code> your changes, pull down locally, get it running to make sure it actually works — looking at code alone won’t catch everything!</p><p>The other developers on the team are not the only stakeholders. There are designers, marketers, PMs who want to provide feedback before the changes go out.</p>
    <div>
      <h3>Unique preview URLs</h3>
      <a href="#unique-preview-urls">
        
      </a>
    </div>
    <p>With Cloudflare Pages, each commit gets its own unique URL. Preview URLs make it easier to get meaningful code reviews without the overhead of pulling down the branch. They also make it easier to get feedback from PMs, designers and marketers on the latest iteration, bridging the gap between mocks and code.</p>
    <div>
      <h3>Infinite staging</h3>
      <a href="#infinite-staging">
        
      </a>
    </div>
    <p><i>“Does anyone mind if I take over staging?”</i> might also sound like a familiar question. With Cloudflare Pages, each feature branch will have its own dedicated consistent alias, allowing you to have a consistent URL for the latest changes.</p><p>With Preview and Production environments, all feature branches and preview links will be built with preview variables, so you can experiment without impacting production data.</p><p>When you’re ready to deploy to production, we’ll redeploy to production for you with the updated production environment variables.</p>
    <div>
      <h3>Collaboration for all</h3>
      <a href="#collaboration-for-all">
        
      </a>
    </div>
    <p>Collaboration is the key to building amazing websites and products — the more the merrier! As a security company, we definitely don’t want you sharing password and credentials. Which is why we provide multi user access for free for unlimited users — invite all your friends, on us!</p>
    <div>
      <h3>Modern sites with modern standards</h3>
      <a href="#modern-sites-with-modern-standards">
        
      </a>
    </div>
    <p>We all know premature optimization is a cardinal sin, but once your project is in front of customers you want to have the best performance possible. If it’s successful, you also want it to be available!</p><p>Today, this is time you have to spend optimizing performance (chasing those 100 lighthouse scores), and scaling, from a few to millions of users.</p><p>Luckily, we happen to know a thing or two about running a global network of 200 data centers though, so we’ve got you covered.</p><p>With Pages, your site is deployed directly to our edge, milliseconds away from customers, and at global scale.</p><p>The latest web standards are fun to read about on Hacker News but not fun to implement yourself. With Cloudflare Pages, we’ll do the heavy lifting to keep you ahead of the curve: IPv6, <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>, <a href="https://www.cloudflare.com/learning/ssl/why-use-tls-1.3/">TLS 1.3</a>, all the latest image formats.</p>
    <div>
      <h2>Oh, and one more thing</h2>
      <a href="#oh-and-one-more-thing">
        
      </a>
    </div>
    <p>We’re really excited for developers and their teams to use Cloudflare Pages to collaborate on the best static sites together. There’s just one thing that didn’t sit quite right with us: why stop at static sites?</p><p>What if we could make building <i>full-blown, dynamic applications just as easy</i>?</p><p>Although APIs are a core part of the <a href="https://www.cloudflare.com/the-net/jamstack-websites/">JAMstack</a>, today that refers primarily to the robust API economy developers have access to. And while that’s great, it’s not always enough. If you want to build your own APIs, and store user or application data, you need more than third party APIs. What to do, though?</p><p>Well, this is the point at which it’s mighty helpful we’ve already built a global <a href="https://www.cloudflare.com/learning/serverless/what-is-serverless/">serverless</a> platform: <a href="https://www.cloudflare.com/developer-platform/workers/">Cloudflare Workers</a>. Workers allows frontend developers to easily write scalable backends to their applications in the same language as the frontend, JavaScript.</p><p>Over the coming months, we’ll be working on integrating Workers and Pages into a seamless experience. It’ll work the exact same way Pages does: just write your code, git push, and we’ll deploy it for you. The only difference is, it won’t just be your frontend, it’ll be your backend, too. And just to be clear: this is not just for stateless functions. With <a href="https://www.cloudflare.com/developer-platform/workers-kv/">Workers KV</a> and <a href="https://www.cloudflare.com/developer-platform/durable-objects/">Durable Objects</a>, we see a huge opportunity to really enable any web application to be built on this platform.</p><p>We’re super excited about the future of Pages, and how with the power of Cloudflare Workers behind it, it represents a bold vision for how new applications are going to be built on the web.</p><p>But you know the thing about gifts? They’re no good without someone to receive them. We’d love for you to sign up for our beta and (<a href="/cloudflare-pages-ga/">the beta is over because this is now GA!</a>) try out <a href="https://pages.cloudflare.com/">Cloudflare Pages</a>!</p>
    <div>
      <h2>PS: we’re hiring!</h2>
      <a href="#ps-were-hiring">
        
      </a>
    </div>
    <p>Want to help us shape the future of development on the web? <a href="https://www.cloudflare.com/careers/">Join our team</a>.</p> ]]></content:encoded>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">5SKXYEZbxTiNUKBoYQWXOt</guid>
            <dc:creator>Rita Kozlov</dc:creator>
        </item>
        <item>
            <title><![CDATA[Building Black Friday e-commerce experiences with JAMstack and Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/building-black-friday-e-commerce-experiences-with-jamstack-and-cloudflare-workers/</link>
            <pubDate>Thu, 26 Nov 2020 18:03:23 GMT</pubDate>
            <description><![CDATA[ Cloudflare Workers continues to excel as a JAMstack deployment platform, and be used to power e-commerce experiences, integrating with familiar tools like Stripe, Nuxt.js, and Sanity.io. ]]></description>
            <content:encoded><![CDATA[ <p>The idea of serverless is to allow developers to focus on writing code rather than operations — the hardest of which is scaling applications. A predictably great deal of traffic that flows through Cloudflare's network every year is Black Friday. As John wrote at the end of last year, <a href="/this-holidays-biggest-online-shopping-day-was-black-friday/">Black Friday is the Internet's biggest online shopping day</a>. In a past <a href="https://www.cloudflare.com/case-studies/cordial-workers-black-friday">case study</a>, we talked about how Cordial, a marketing automation platform, used Cloudflare Workers to <a href="https://www.cloudflare.com/solutions/ecommerce/optimization/">reduce their API server latency</a> and handle the busiest shopping day of the year without breaking a sweat.</p><p>The ability to handle immense scale is well-trodden territory for us on the Cloudflare blog, but scale is not always the first thing developers think about when building an application — developer experience is likely to come first. And developer experience is something Workers does just as well; through Wrangler and APIs like Workers KV, Workers is an awesome place to hack on new projects.</p><p>Over the past few weeks, I've been working on a sample <a href="https://github.com/signalnerve/ecommerce-bundles-workers-example">open-source</a> e-commerce app for selling software, educational products, and bundles. Inspired by Humble Bundle, it's built entirely on Workers, and it integrates powerfully with all kinds of first-class modern tooling: <a href="https://stripe.com/">Stripe</a>, an API for accepting payments (both <i>from</i> customers and <i>to</i> authors, as we’ll see later), and <a href="https://www.sanity.io/">Sanity.io</a>, a headless CMS for data management.</p><p>This kind of project is perfectly suited for Workers. We can lean into Workers as a <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">static site hosting platform</a> (via <a href="https://workers.cloudflare.com/sites">Workers Sites</a>), API server, and webhook consumer, all within a single codebase, and deployed instantly around the world on Cloudflare's network.</p><p>If you want to see a deployed version of this template, check out <a href="https://ecommerce-example.signalnerve.workers.dev/">ecommerce-example.signalnerve.workers.dev</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/74ASlUQIruTiQ3vb7IofzP/d92115dd93a237a2a383c7ec4df6a31e/image2-14.png" />
            
            </figure><p><i>The frontend of the e-commerce Workers template.</i></p><p>In this blog post, I'll dive deeper into the implementation details of the site, covering how Workers <a href="/jamstack-at-the-edge-how-we-built-built-with-workers-on-workers/">continues to excel as a JAMstack deployment platform</a>. I’ll also cover some new territory in integrating Workers with Stripe. The project is <a href="https://github.com/cloudflare/ecommerce-bundles-workers-example">open-source on GitHub</a>, and I'm actively working on improving the documentation, so that you can take the codebase and build on it for your own <a href="https://www.cloudflare.com/ecommerce/">e-commerce sites</a> and use cases.</p>
    <div>
      <h3>The frontend</h3>
      <a href="#the-frontend">
        
      </a>
    </div>
    <p>As I wrote last year, Workers continues to be an <a href="/jamstack-at-the-edge-how-we-built-built-with-workers-on-workers/">amazing platform for JAMstack apps</a>. When I started building this template, I wanted to use some things I already knew — Sanity.io for managing data, and of course, Workers Sites for deploying — but some new tools as well.</p><p>Workers Sites is incredibly simple to use: just point it at a directory of static assets, and you're good to go. With this project, I decided to try out <a href="https://nuxtjs.org/">Nuxt.js</a>, a Vue-based static site generator, to power the frontend for the application.</p><p>Using Sanity.io, the data representing the bundles (and the products inside of those bundles) is stored on Sanity.io's own CDN, and retrieved client-side by the Nuxt.js application.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/hCZNF9X1W2MNRgsSEJMbl/524eaed1ef2c971d9d5486227a9fc74b/image3-18.png" />
            
            </figure><p><i>Managing data inside Sanity.io’s headless CMS interface.</i></p><p>When a potential customer visits a bundle, they'll see a list of products from Sanity.io, and a checkout button provided by Stripe.</p>
    <div>
      <h3>Responding to new checkout sessions and purchases</h3>
      <a href="#responding-to-new-checkout-sessions-and-purchases">
        
      </a>
    </div>
    <p>Making API requests with Stripe's Node SDK isn't currently supported in Workers (check out the GitHub issue where we're <a href="https://github.com/stripe/stripe-node/issues/997">discussing a fix</a>), but because it's just REST underneath, we can easily make REST requests using the library.</p><p>When a user clicks the checkout button on a bundle page, it makes a request to the Cloudflare Workers API, and securely generates a new session for the user to checkout with Stripe.</p>
            <pre><code>import { json, stripe } from '../helpers'

export default async (request) =&gt; {
  const body = await request.json()
  const { price_id } = body

  const session = await stripe('/checkout/sessions', {
    payment_method_types: ['card'],
    line_items: [{
        price: price_id,
        quantity: 1,
      }],
    mode: 'payment'
  }, 'POST')

  return json({ session_id: session.id })
}</code></pre>
            <p>This is where Workers excels as a <a href="https://www.cloudflare.com/the-net/jamstack-websites/">JAMstack platform</a>. Yes, it can do static site hosting, but with just a few extra lines of routing code, I can deploy a highly scalable API <b>right alongside</b> my Nuxt.js application.</p>
    <div>
      <h3>Webhooks and working with external services</h3>
      <a href="#webhooks-and-working-with-external-services">
        
      </a>
    </div>
    <p>This idea extends throughout the rest of the checkout process. When a customer is successfully charged for their purchase, Stripe sends a webhook back to Cloudflare Workers. In order to complete the transaction on our end, the Workers application:</p><ul><li><p><b>Validates the incoming data from Stripe to ensure that it’s legitimate</b>. This means that every incoming webhook request is explicitly validated using your Stripe account details, and can be confirmed to be valid before the function acts on it.</p></li><li><p><b>Distributes payments to the authors using Stripe Connect</b>. When a customer buys a bundle for $20, that $20 (minus Stripe fees) gets distributed evenly between the authors in that bundle — all of this calculation and the associated transfer requests happen inside the Worker.</p></li><li><p><b>Sends a unique download link to the customer</b>. Using Workers KV, a unique token is set up that corresponds to the customer's email, which can be used to retrieve the content the customer purchased. This integration uses Mailgun to construct an email and send it entirely over REST APIs.</p></li></ul><p>By the time the purchase is complete, the Workers serverless API will have interfaced with four distinct APIs, persisting records, sending emails, and handling and distributing payments to everyone involved in the e-commerce transaction. With Workers, this all happens in a single codebase, with low latency and a superb developer experience. The entire API is type-checked and validated before it ever gets shipped to production, thanks to our <a href="https://github.com/cloudflare/worker-typescript-template">TypeScript template</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/28P0T9V4Vr2rUjFGafTKbg/8f3cca1ca86cd49a0e4360cbfb52af79/image1-19.png" />
            
            </figure><p>Each of these tasks involves a pretty serious level of complexity, but by using Workers, we can abstract each of them into smaller pieces of functionality, and compose powerful, on-demand, and infinitely scalable webhooks directly on the serverless edge.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>I'm really excited about the launch of this template and, of course, it wouldn't have been possible to ship something like this in just a few weeks without using Cloudflare Workers. If you're interested in digging into how any of the above stuff works, <a href="https://github.com/cloudflare/ecommerce-bundles-workers-example">check out the project on GitHub</a>!</p><p>With the recent announcement of our <a href="/workers-kv-free-tier/">Workers KV free tier</a>, this project is perfect to fork and build your own e-commerce products with. Let me know what you build and <a href="https://twitter.com/signalnerve">say hi on Twitter</a>!</p> ]]></content:encoded>
            <category><![CDATA[eCommerce]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">1Bs9ynEmg6BZJaONeoaoxx</guid>
            <dc:creator>Kristian Freeman</dc:creator>
        </item>
        <item>
            <title><![CDATA[JAMstack at the Edge: How we built Built with Workers… on Workers]]></title>
            <link>https://blog.cloudflare.com/jamstack-at-the-edge-how-we-built-built-with-workers-on-workers/</link>
            <pubDate>Wed, 29 Jan 2020 13:00:00 GMT</pubDate>
            <description><![CDATA[ Announcing Built with Workers – a resource for exploring what you can build with Cloudflare Workers. This resource showcases developers building incredible projects with tools like Workers KV  ]]></description>
            <content:encoded><![CDATA[ <p>I'm extremely stoked to announce <a href="https://workers.cloudflare.com/built-with">Built with Workers</a> today – it's an awesome resource for exploring what you can build with <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>. As Adam explained in <a href="/built-with-workers/">our launch post</a>, showcasing developers building incredible projects with tools like Workers KV or our <a href="https://developers.cloudflare.com/workers/reference/apis/html-rewriter/">streaming HTML rewriter</a> is a great way to celebrate users of our platform. It also helps encourage developers to try building their dream app on top of Workers. In this post, I’ll explore some of the architectural and implementation designs we made while building the site.</p><p>When we first started planning Built with Workers, we wanted to use the site as an opportunity to build a new greenfield application, showcasing the strength of the Workers platform. The Workers Developer Experience team is cross-functional: while we might spend most of our time improving our docs, or developing features for our command-line interface <a href="https://github.com/cloudflare/wrangler">Wrangler,</a> most of us have spent years developing on the web. The prospect of starting a new application is always fun, but in this instance, it was a prime chance to ask (and answer) the question, <i>"If I could build this site on Workers with whatever tools I want, what would I choose?"</i></p><p>A guiding principle for the Workers platform is ease-of-use. The programming model is simple: it's just JavaScript (or, via WASM, Rust, C, and C++), and you have complete control over the requests coming in and the requests going out from your Workers script. In the same way, while building Built with Workers, it was <b>crucial</b> to find a set of tools that could enable something like this throughout the process of building the entire application. To enable this, we've embraced <a href="https://www.cloudflare.com/the-net/jamstack-websites/"><b>JAMstack</b></a> – a software stack comprised of JavaScript, <a href="https://www.cloudflare.com/learning/security/api/what-is-an-api/">APIs</a>, and markup – with Built with Workers, deploying always up-to-date static builds of the site <i>directly to the edge</i>, using <a href="https://workers.cloudflare.com/sites">Workers Sites</a>. Our framework of choice, <a href="https://www.gatsbyjs.org/">Gatsby.js</a>), provides a set of sane defaults to build a modern web application. To manage content and the layout of the site, we've chosen <a href="https://www.sanity.io/">Sanity.io</a>, a powerful <a href="https://en.wikipedia.org/wiki/Headless_content_management_system">headless CMS</a> that allows us to model the entire website without needing to deploy any databases or spin up any additional infrastructure.</p><p>Personally, I'm excited about JAMstack as a methodology for building web applications <i>because</i> of this emphasis on reducing infrastructure: it's incredibly similar to the motivations behind deploying serverless applications using Cloudflare Workers, and as we developed Built with Workers, we discovered a number of these philosophical similarities in JAMstack and Cloudflare Workers – exciting! To help encourage developers to explore building their own JAMstack applications on Workers, I'm also announcing today that we've made the Built with Workers codebase open-source on GitHub – you can check out how the application is developed, built and deployed from start to finish.</p><p>In this post, we'll dig into Built with Workers, exploring how it works, the technical decisions we've made, and some of the most fascinating aspects of what it means to build applications on the edge.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1umidSCuFOnPav3ZdYthdC/31579479c96cf58508268af85780f38e/bww.png" />
            
            </figure><p>A screenshot of the Built with Workers homepage</p>
    <div>
      <h2>Exploring the JAMstack</h2>
      <a href="#exploring-the-jamstack">
        
      </a>
    </div>
    <p>My first encounter with tooling that would ultimately become part of "JAMstack" was in 2013. I noticed the huge proliferation of developers building personal "static" sites – taking blog posts written primarily in <a href="https://blog.cloudflare.com/markdown-for-agents/">Markdown</a>, and pushing them through frameworks like Jekyll to build full websites that could easily be deployed to a number of <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDNs</a> and file hosting platforms. These static sites were <b>fast</b> – they are just HTML, CSS, and JavaScript – and <b>easy to update</b>. The average developer spends their days maintaining large and complex software systems, so it was relaxing to just write Markdown, plug in some re-usable HTML and CSS, and deploy your website. The advent of static sites, of course, isn't new – but after years of increasingly complex full-stack technology, the return to simplicity was a promising development for many kinds of websites that didn't need databases, or any dynamic content.</p><p>In the last couple years, JAMstack has built upon that resurgence, and represents an approach to building complete, complex applications using the same tooling that has become the first choice for developers building their simple personal sites. JAMstack is comprised of three conceptual pieces – <i>JavaScript</i>, <i>APIs</i>, and <i>Markup</i> – each of which is a crucial aspect of simplifying our web applications and making them easy to write, build, and deploy.</p>
    <div>
      <h3>J is for JavaScript</h3>
      <a href="#j-is-for-javascript">
        
      </a>
    </div>
    <p>The JAMstack architecture relies heavily on the ubiquity of JavaScript as the language of the web. Many modern web applications use powerful, dynamic front-end frameworks like <i>React</i> and <i>Vue</i> to render user interfaces and process state on the client for users. On the backend, or in Workers' case, on the edge, any dynamic functionality in your JAMstack application should be built on top of JavaScript, often working in the request-response model that full-stack developers are accustomed to.</p><p>The Workers platform is <b>perfectly</b> suited to this requirement! As a developer building on Workers, you have total control of incoming requests and outgoing responses, using the JavaScript Service Worker APIs you know and love. We built <a href="https://workers.cloudflare.com/sites">Workers Sites</a> as an extension of the Workers platform (and Workers KV as a storage mechanism at the edge), making it possible to deploy your site assets using a single command in Wrangler: <code>wrangler publish</code>.</p><p>When your Workers Site receives a new request, we'll execute JavaScript at the edge to look up a piece of content from Workers KV, and serve it back to the client at lightning speed. Remarkably, you can deploy JAMstack applications on Workers with no additional configuration besides <a href="https://developers.cloudflare.com/workers/sites/start-from-existing">generating your Workers Site</a> – <b>by design, Workers Sites is built to serve as an exceptional JAMstack deployment platform</b>.</p>
    <div>
      <h3>A is for APIs</h3>
      <a href="#a-is-for-apis">
        
      </a>
    </div>
    <p>The advent of static site tooling for personal sites makes sense: your site is a few pages: a few blog posts, for instance, and the classic "About" or "Contact" page. When it's compiled to HTML, the footprint is quite small! This small footprint is what makes static sites easy to reason about: they're trivial to host in terms of bandwidth and storage costs, and they rarely change, so they're easily cacheable.</p><p>While that works for personal sites, complex applications actually have data requirements! We need to talk to the user data in our databases, and analytics information in our data warehouses. JAMstack apps tackle this by definitively stating that these data sources should be accessible via HTTPS APIs, consumable by the application as a way to provide dynamic information to clients.</p><p>Workers is a <b>fascinating</b> platform in regards to JAMstack APIs. It can serve as a gateway to your data, or as a place to persist and return data itself. I can, for instance, expose an API endpoint via my Workers script without giving clients access to my origin. I can also use tooling like <a href="https://www.cloudflare.com/products/workers-kv/">Workers KV</a> to persist data directly on the edge, and when a user requests that data, I can resolve the data by returning JSON directly from my application.</p><p>This flexibility has been an unexpected part of the experience of developing Built with Workers. In a later section of this post, I'll talk about how we developed an integral feature of the site based on the unique strengths of Workers as a way to <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">host static assets</a> <i>and</i> as a dynamic JavaScript execution platform. This has remarkable implications that blur the lines between classic static sites and dynamic applications, and I'm <b>really</b> excited about it.</p>
    <div>
      <h3>M is for Markup</h3>
      <a href="#m-is-for-markup">
        
      </a>
    </div>
    <p>A breakthrough moment in my understanding of JAMstack came at the beginning of this year. I was working on a job board for frontend developers, using the static site framework Gatsby.js and Sanity.io, a headless CMS tool that allows developers to model content without maintaining a database or any infrastructure. (As a reminder – this set of tools is <i>identical</i> to what we ultimately used to develop Built with Workers. It's a very good stack!)</p><p>SEO is crucial to a job board, and as I began to explore how to drive more traffic to my job board, I landed on the idea of generating a huge amount of search-oriented content automatically from the job data I already had. For instance, if I had job posts with the keywords <i>"React"</i>, <i>"Europe"</i>, and <i>"Senior"</i> (as in <i>"senior developer"</i>), what if I created pages with titles like <i>"Senior React developer jobs in Europe"</i>, or <i>"Remote Angular jobs"</i>? This approach would allow the site to begin ranking for a variety of job positions, locations, and experience levels, and as more jobs were posted on the site, each of these pages would be enriched with more useful information and relevant content, helping it rank higher in search.</p><p><i>"But static sites are... static!"</i>, I told myself. Would I need to build an entire dynamic API on top of my static site, just to be able to serve these search-engine optimized pages? This led me to a "eureka" moment with Gatsby – I could define markup (the <i>"M"</i> in JAMstack), and when I'm building my site, I could look at all the available job data I had, cycling through every available keyword combination and inserting it into my markup to generate thousands of these pages. As I later learned, this idea is not necessarily unique to Gatsby – it is possible, for instance, to automate getting data from your API and writing it to data files in earlier static site frameworks like <a href="https://gohugo.io/">Hugo</a> – but it is a first-class citizen in Gatsby. There are a <i>ton</i> of data sources available via Gatsby plugins, and because they're all exposed via HTTPS, the workflow is standardized inside of the framework.</p><p>In Built with Workers, we connect to the Sanity.io CMS instance at <i>build-time</i>: crucially, by the time that the site has been deployed to Workers, the application effectively has <i>no idea</i> what Sanity even is! Our Gatsby application connects to Sanity.io via an HTTPS API, and using GraphQL, we look at all the data that we have in our CMS, and make decisions about what pages to generate and how to render the site's interface, ultimately resulting in a statically-built application that is derived from dynamic data.</p><p>This emphasis on the <i>build</i> step in JAMstack is quite different than the classic web application. In the past, a user requested data, a web server looked at what the user was requesting, and then the user <i>waits</i>, as the server gets that data, returns JSON, or interpolates it into templates written in tools like <a href="https://pugjs.org/">Pug</a> or <a href="https://en.wikipedia.org/wiki/ERuby">ERB</a>. With JAMstack, the pages are already built, and the deployed application is just a collection of plain HTML, CSS, and JavaScript.</p>
    <div>
      <h3>Why Cloudflare Workers?</h3>
      <a href="#why-cloudflare-workers">
        
      </a>
    </div>
    <p>Cloudflare's network is a fascinating place to deploy JAMstack applications. Yes, Cloudflare's edge network can act as a CDN for your static assets, like your CSS stylesheets, or your client-side JavaScript code. But with Workers, we now have the ability to run JavaScript side-by-side with our static assets. In most JAMstack applications, the CDN is simply a bucket where your application ends up. Usually, the CDN is the most boring part of the stack! <b>With Cloudflare Workers, we don't just have a CDN: we also have access to an extremely low-latency, fully-featured JavaScript runtime.</b></p><p>The implications of this on the standard JAMstack workflow are, frankly, <i>mind-boggling</i>, and as part of developing Built with Workers, we've been exploring what it means to have this runtime available side-by-side with our statically-built JAMstack application.</p><p>To demonstrate this, we’ve implemented a bookmarking feature, which allows users of Built with Workers to bookmark projects. If you look at a project's usage of our streaming HTML rewriter and say <i>"Wow, that's cool!"</i>, you can also bookmark for the project to show your support. This feature, rendered as a <code>button</code> tag is deceptively simple: it's a single piece of the user interface that makes use of the entirety of the Workers platform, to provide user-specific dynamic functionality. We'll explore this in greater detail later in the post – see <i>"Enhancing static sites at the edge"</i>.</p><blockquote><p>i'm super excited about this and spent some time this morning re-writing my first take at this to be something that i think is super compelling</p><p>??<a href="https://t.co/LJltC6j20S">https://t.co/LJltC6j20S</a></p><p>— ً (@signalnerve) <a href="https://twitter.com/signalnerve/status/1199379423608344576?ref_src=twsrc%5Etfw">November 26, 2019</a></p></blockquote>
    <div>
      <h2>A modern development and content workflow</h2>
      <a href="#a-modern-development-and-content-workflow">
        
      </a>
    </div>
    <p>In the <a href="/workers-sites/">announcement post</a> for Workers Sites, Rita outlined the motivations behind launching Workers Sites as a modern way to deploy sites:</p><p><i>"Born on the edge, Workers Sites is what we think modern development on the web should look like, natively secure, fast, and massively scalable. Less of your time is spent on configuration, and more of your time is spent on your code, and content itself."</i></p><p>A few months later, I can say definitively that Workers Sites has enabled us to develop Built with Workers and spend almost no time on configuration. Using <a href="https://github.com/cloudflare/wrangler-action">our GitHub Action</a> for deploying Workers applications with Wrangler, the site has been continuously deploying to a staging environment for the past couple weeks. The simplicity around this continuous deployment workflow has allowed us to focus on the important aspects of the project: development and content.</p><p>The static site framework ecosystem is fairly competitive, but as we considered our options for this site, I advocated strongly for Gatsby.js. It's an incredible tool for building JAMstack applications, with a great set of default for performant applications. It's common to see Gatsby sites with <a href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a> scores in the upper 90s, and the decision to use React for implementing the UI makes it straightforward to onboard new developers if they're familiar with React.</p><p>As I mentioned in a previous section, Gatsby shines at <i>build-time</i>. Gatsby's APIs for creating pages during the build process based on API data are incredibly powerful, allowing developers to concretely define every statically-generated page on their web application, as well as any relevant data that needs to be passed in.</p><p>With Gatsby decided upon as our static site framework, we needed to evaluate where our content would live. Built with Workers has two primary data models, used to generate the UI:</p><ul><li><p><b>Projects</b>: websites, applications, and APIs created by developers using Cloudflare Workers. For instance, Built with Workers!</p></li><li><p><b>Features</b>: features available on the Workers platform used to build applications. For instance, Workers KV, or our streaming HTML rewriter/parser.</p></li></ul><p>Given these requirements, there were a number of potential approaches to take to store this data, and make it accessible. Keeping in line with JAMstack, we know that we probably should expose it via an HTTPS API, but from where? In what format?</p><p>As a full-stack developer who's comfortable with databases, it's easy to envision a world where we spin up a PostgreSQL instance, write a REST API, and write all kinds of <code>fetch('/api/projects')</code> to get the information we need. This method works, but we can do better! In the same way we built Workers Sites to simplify the deployment process, it was worthwhile to explore the JAMstack ecosystem and see what solutions exist for modeling data without being on the hook for more infrastructure.</p><p>Of the different tools in the ecosystem – databases, whether SQL or NoSQL, key-value stores (such as our own, Workers KV), etc. – the growth of "headless CMS" tools has made the largest impact on my development workflow.</p><p>On CSS Tricks, Chris Coyier wrote about the rise of headless CMS tools back in March 2016, and <a href="https://css-tricks.com/what-is-a-headless-cms/">summarizes their function</a> well:</p><p><i>[Headless CMSes are] very related to The Big Conversation™ on the web the last many years. How are we going to handle bringing Our Stuff™ all these different devices/screens/inputs.Responsive design says "let's let our design and media accommodate as much variation in screens as possible."Progressive enhancement says "let's make the functionality of this site work no matter what."Designing for accessibility says "let's ensure everyone can use this regardless of their capabilities as a person."A headless CMS says "let's not tie our data to any one way of doing things."</i></p><p>Using our headless CMS, Sanity.io, we can get every project inside our dataset, and call Gatsby's <code>createPage</code> function to create a new page for each project, using a pre-defined project template file:</p>
            <pre><code>// gatsby-node.js

exports.createPages = async ({ graphql, actions }) =&gt; {
  const { createPage } = actions;

  const result = await graphql(`
    {
      allSanityProject {
        edges {
          node {
            slug
          }
        }
      }
    }
  `);

  if (result.errors) {
    throw result.errors;
  }

  const {
    data: { allSanityProject }
  } = result;

  const projects = allSanityProject.edges.map(({ node }) =&gt; node);
  projects.forEach((node, _index) =&gt; {
    const path = `/built-with/projects/${node.slug}`;

    createPage({
      path,
      component: require.resolve("./src/templates/project.js"),
      context: { slug: node.slug }
    });
  });
};</code></pre>
            <p>Using Sanity to drive the content for Built with Workers has been a <i>huge</i> win for our team. We're no longer constrained by code deploys to make changes to content on the site – we don't need to make a pull request to create a new project, and edits to a project's name or description aren't constrained by someone with the ability to deploy the project. Instead, we can empower members of our team to log in directly to the CMS and make changes, and be confident that once the corresponding deploy has completed (see <i>"The CDN is the deployment platform"</i> below), their changes will be live on the site.</p>
    <div>
      <h3>Dynamic JAMstack layouts</h3>
      <a href="#dynamic-jamstack-layouts">
        
      </a>
    </div>
    <p>As our team got up and running with Sanity.io, we found that the flexibility of a headless CMS platform was useful not just for creating our original data requirements – projects and features – but in rethinking and innovating on how we actually format the application itself.</p><p>With our previous objective of empowering non-technical folks to make changes to the site without deploying any code in consideration, we've also taken the entire homepage of Built with Workers and defined it as an instance of the "layout" data model in Sanity.io. By doing this, we can define corresponding "collections", which are sets of projects. When a layout has many collections defined inside of the CMS, we can rapidly re-order, re-arrange, and experiment with new collections on the homepage, seeing the updated version of the site reflected immediately, and live on the production site within only a few minutes, after our continuous deployment process has finished.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1x7v7SMVVKcuM48wKvz22T/50e4a31742d85f60e689574f75af1541/bww-demo.gif" />
            
            </figure><p>Updating the layout of Built with Workers live from Sanity's studio</p><p>With this work implemented, it's easy to envision a world where our React code is purely concerned with rendering each individual aspect of the application's interface – for instance, the project title component, or the "card" for an individual project – and the CMS drives the entire layout of the site. In the future, I'd like to continue exploring this idea in other pages in Built with Workers, including the project pages and any other future content we put on the site.</p>
    <div>
      <h2>Enhancing static sites at the edge</h2>
      <a href="#enhancing-static-sites-at-the-edge">
        
      </a>
    </div>
    <p>Much of what we've discussed so far can be thought of as features and workflows that have great DX (developer experience), but not specific to Workers. Gatsby and Sanity.io are great, and although Workers Sites is a great platform for deploying JAMstack applications due to the Workers platform's low-latency and performance characteristics, you could deploy the site to a number of different providers with no real differentiating features.</p><p>As we began building a JAMstack application on top of Built with Workers, we also wanted to explore how the Workers platform could allow developers to combine the simplicity of static site deployments with the dynamism of having a JavaScript runtime immediately available.</p><p>In particular, our recently-released streaming HTML rewriter seems like a perfect fit for "enhancing" our static sites. Our application is being served by Workers Sites, which itself is a Workers template that can be customized. By passing each HTML page through the HTML rewriter on its way to the client, we had an opportunity to customize the content without any negative performance implications.</p><p>As I mentioned previously, we landed on a first exploration of this platform advantage via the "bookmark" button. Users of Built with Workers can "bookmark" for a project – this action sends a request back up to the Workers application, storing the bookmark data as JSON in Workers KV.</p>
            <pre><code>// User-specific data stored in Workers KV, representing
// per-project bookmark information

{
  "bytesized_scraper_bookmarked": false,
  "web_scraper_bookmarked": true
}</code></pre>
            <p>When a user returns to Built with Workers, we can make a request to Workers KV, looking for corresponding data for that user and the project they're currently viewing. If that data exists, we can embed the "edge state" directly into the HTML using the streaming HTML rewriter.</p>
            <pre><code>// workers-site/index.js

import { getAssetFromKV } from "@cloudflare/kv-asset-handler"

addEventListener("fetch", event =&gt; { 
  event.respondWith(handleEvent(event)) 
})

class EdgeStateEmbed {
  constructor(state) {
    this._state = state
  }
  
  element(element) {
    const edgeStateElement = `
      &lt;script id='edge_state' type='application/json'&gt;
        ${JSON.stringify(this._state)}
      &lt;/script&gt;
    `
    element.prepend(edgeStateElement, { html: true })
  }
}

const hydrateEdgeState = async ({ state, response }) =&gt; {
  const rewriter = new HTMLRewriter().on(
    "body",
    new EdgeStateEmbed(await state)
  )
  return rewriter.transform(await response)
}

async function handleEvent(event) {
  return hydrateEdgeState({
    response: getAssetFromKV(event, options),
    // Get associated state for a request, based on the user and URL
    state: transformBookmark(event.request),
  })
}</code></pre>
            <p>When the React application is rendered on the client, it can then check for that embedded edge state, which influences how the "bookmark" icon is rendered - either as "bookmarked", or "bookmarked". To support this, we've leaned on React's <code>useContext</code>, which allows any component inside of the application component tree to pull out the edge state and use it inside of the component:</p>
            <pre><code>// edge_state.js

import React from "react"
import { useSSR } from "../utils"

const parseDocumentState = () =&gt; {
  const edgeStateElement = document.querySelector("#edge_state")
  return edgeStateElement ? JSON.parse(edgeStateElement.innerText) : {}
}

export const EdgeStateContext = React.createContext([{}, () =&gt; {}])
export const EdgeStateProvider = ({ children }) =&gt; {
  const { isBrowser } = useSSR()
  if (!isBrowser) {
    return &lt;&gt;{children}&lt;/&gt;
  }
  
  const edgeState = parseDocumentState()
  const [state, setState] = React.useState(edgeState)
  const updateState = (newState, options = { immutable: true }) =&gt; options.immutable
    ? setState(Object.assign({}, state, newState))
    : setState(newState)
  
  return (
    &lt;EdgeStateContext.Provider value={[state, updateState]}&gt;
      {children}
    &lt;/EdgeStateContext.Provider&gt;
  )
}

// Inside of a React component
const Bookmark = ({ bookmarked, project, setBookmarked, setLoaded }) =&gt; {
const [state, setState] = React.useContext(EdgeStateContext)
// `bookmarked` value is a simplification of actual code
return &lt;BookmarkButton bookmarked={state[project.id]} /&gt;
}</code></pre>
            <p>The combination of a straightforward JAMstack deployment platform with dynamic key-value <a href="https://www.cloudflare.com/learning/cloud/what-is-object-storage/">object storage</a> and a streaming HTML rewriter is really, really cool. This is an initial exploration into what I consider to be <i>a platform-defining feature</i>, and if you're interested in this stuff and want to continue to explore how this will influence how we write web applications, <a href="https://twitter.com/signalnerve">get in touch with me on Twitter</a>!</p>
    <div>
      <h2>The CDN is the deployment platform</h2>
      <a href="#the-cdn-is-the-deployment-platform">
        
      </a>
    </div>
    <p>While it doesn't appear in the acronym, an unsung hero of the JAMstack architecture is <b>deployment</b>. In my local terminal, when I run <code>gatsby build</code> inside of the Built with Workers project, the result is a folder of static HTML, CSS, and JavaScript. <i>It should be easy to deploy!</i></p><p>The recent release of <a href="https://github.com/features/actions">GitHub Actions</a> has proven to be a great companion to building JAMstack applications with Cloudflare Workers – we've open-sourced our own <a href="https://github.com/cloudflare/wrangler-action">wrangler-action</a>, which allows developers to build their Workers applications and deploy directly from GitHub.</p><p>The standard workflows in the continuous deployment world – deploy every hour, deploy on new changes to the <code>master</code> branch, etc – are possible and already being used by many developers who make use of our <code>wrangler-action</code> workflow in their projects. Particular to JAMstack and to headless CMS tools is the idea of "build-on-change": namely, when someone publishes a change in Sanity.io, we want to do a new deploy of the site to immediately reflect our new content in production.</p><p>The versatility of Workers as a place to deploy JavaScript code comes to the rescue, again! By telling Sanity.io to make a GET request to a deployed Workers webhook, we can trigger a <code>repository_event</code> on GitHub Actions for our repository, allowing new deploys to happen immediately after a change is detected in the CMS:</p>
            <pre><code>const headers = {
  Accept: 'application/vnd.github.everest-preview+json',
  Authorization: 'Bearer $token',
}

const body = JSON.stringify({ event_type: 'repository_dispatch' })

const url = `https://api.github.com/repos/cloudflare/built-with-workers/dispatches`

const handleRequest = async evt =&gt; {
  await fetch(url, { method: 'POST', headers, body })
  return new Response('OK')
}

addEventListener('fetch', handleRequest)</code></pre>
            <p>In doing this, we've made it possible to completely abstract away <i>every</i> deployment task around the Built with Workers project. Not only does the site deploy on a schedule, and on new commits to <code>master</code>, but it can also do additional deploys as the content changes, so that the site is always reflective of the current content in our CMS.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2CR3w7eC9bk2QZXFlirn1o/fea6c2fe3b3e137c1b78aacabba44d4c/i6sG6fa_qL9h3uHrSQWI5adnC41xFKaS3vwBIKqk_WqqjSzQ_qZhT5VGnMo8DTMyfyqc8YiPUgTiw77EzopT9cyVWUn1HSrVxsFbKCPHkI-MVtbzTxLJZH8KbYrw.png" />
            
            </figure><p>The GitHub Actions deployment workflow for Built with Workers</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We're <b>super</b> excited about Built with Workers, not only because it will serve as a great place to showcase the incredible things people are building with the Cloudflare Workers platform, but because it also has allowed us to explore what the future of web development may look like. I've been advocating for what I've seen referred to as <a href="https://www.bytesized.xyz/full-stack-serverless">"full-stack serverless"</a> development throughout 2019, and I couldn't be happier to start 2020 with launching a project like Built with Workers. The full-stack serverless stack feels like the future, and it's actually fun to build with on a daily basis!</p><p>If you're building something awesome with Cloudflare Workers, we're looking for submissions to the site! Get in touch with us via <a href="https://forms.gle/k6fZaXJbrUygvZhp6">this form</a> – we're excited to speak with you!</p><p>Finally, if topics like JAMstack on Cloudflare Workers, "edge state" and dynamic static site hydration, or continuous deployment interest you, the Built with Workers repository is open-source! <a href="https://github.com/cloudflare/built-with-workers">Check it out</a>, and if you're inspired to build something cool with Workers after checking out the code, make sure to let us know!</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">6tUTWYaVjn742TLZMm1TXo</guid>
            <dc:creator>Kristian Freeman</dc:creator>
        </item>
        <item>
            <title><![CDATA[Announcing Built with Workers]]></title>
            <link>https://blog.cloudflare.com/built-with-workers/</link>
            <pubDate>Wed, 29 Jan 2020 13:00:00 GMT</pubDate>
            <description><![CDATA[ Ever since its initial release, Cloudflare Workers has given JavaScript developers a platform to enable building high-performance applications with automatic scaling. ]]></description>
            <content:encoded><![CDATA[ <p>Ever since <a href="/introducing-cloudflare-workers/">its initial release</a>, Cloudflare Workers has given JavaScript developers a platform to enable building high-performance applications with automatic scaling.</p><p>As with any new technology, we know it can be a bit intimidating to get started. For one thing, running code on the edge is a paradigm shift—forcing us to rethink classic web architecture problems, or removing them altogether. For another, since you can build just about anything, it can be challenging to figure out what to build first.</p><hr /><p>Today we’re launching <a href="http://workers.cloudflare.com/built-with">Built with Workers</a>, a new site designed to help get those creative juices flowing and unblock you, by answering that simple but important question: What <i>can</i> I build with Cloudflare Workers?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6gt7YhlENP7sKGvfJfDn4X/c8c4d3c840725073de04a7d11e4915b7/built-with-workers.png" />
            
            </figure><p>Some time in 1999, at age 11, I received my first graphing calculator. It was a <a href="https://en.wikipedia.org/wiki/TI-82">TI-82</a> that my older sister no longer needed. It was on this very calculator that I learned to write code. Looking back, I’m not sure how exactly I had the patience or sanity to figure it all out.</p><p>It was a mess. Among the many difficulties were that I had to type the code out on the calculator’s non-QWERTY keyboard, <a href="https://en.wikipedia.org/wiki/TI-BASIC">the language</a> I was writing in didn’t have <i>functions</i>, and oh yeah, the text editor would frequently bug out and I’d inexplicably lose half or all of my code.</p><p>But what was perhaps more challenging than all of that, was that I had absolutely zero code examples to draw inspiration from.</p><p>I remember when I stumbled on a design pattern to handle input. It was quite the eureka moment. With only labels and gotos, I would have to check if each key was pressed and then loop back around to do it all over again. Little did I know I’d be programming games just about the same way today using  <code>requestAnimationFrame</code> .</p><p>Though I was able to make a few simple programs hunting around like this, I quickly hit my limits and stopped writing them.</p><p>A couple of years later, a friend of mine, with his fancy-pantsed TI-83 <i>Silver Edition</i> calculator with 4× the RAM of mine—I was a bit jealous—showed me a program that came with his fancy new calculator.</p><p>It was called <a href="https://www.youtube.com/watch?v=LTRujnUvgHU">Phoenix</a>. If you ever played any graphing calculator games, it was probably this one. It was fast and action packed, flying a spaceship around shooting enemies. It was beautiful.</p><p>Seeing this game totally changed my perspective on the platform. I went on to create a couple of games involving similar mechanics and a similar animation style, all because I’d seen this game on a friend’s calculator.</p><p>It opened up my eyes to what was possible, gave me the confidence to try things I previously thought were impossible, and brought out the detective inside me to want to figure out how they were able to build each piece of functionality.</p><p>A few other friends of mine started writing programs too. We would trade our programs in the back of math class together using a cable to attach the two calculators together.</p><p>Importantly, when you’d receive a program from another friend’s calculator, you could run it <i>and</i> you could view and manipulate the source code. This allowed us to collaborate on games, by passing them back and forth.</p><p>Our apps and games became more complex and interesting. Non-coder friends of ours were becoming interested in our projects too, and we started sharing games at lunch. We would get great feedback from them, leading us to fix bugs, build more stylish graphics and intro sequences, and streamline the player experience.</p><p>I’m sure our teachers loved us...</p><hr /><p>A few years later, I got the Internet.</p><p>What made the Internet so exciting to me was that by design, the source code of any website was just sitting right there, one keyboard command away. Just like the calculators.</p><p>So I did what many of us did back then—and still do today: if I saw something cool, I stole it. <i>Oh nice hover animation: I’ll take that thank you very much. Cool button design: yup, that’s mine now.</i></p><p>Back then we called them websites not apps, and ourselves web designers not frontend engineers, but in all of the time since then, the web platform hasn’t really changed.</p><p>Although the web today is more complex, often with many more layers of abstraction, it’s still the case that if you can see something in your browser, most likely you can quickly access, study, copy, manipulate, borrow and steal the source code that created it in just a few seconds.</p><p>This is why I’m personally so excited to bring <a href="https://workers.cloudflare.com/built-with">Built with Workers</a> to the community, and to learn from the projects on it myself.</p><p>Every project page has a section in which the creators get to describe how their project uses Cloudflare Workers. Many projects use Workers KV, our distributed key-value store, and Workers Sites, our edge-based <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">static site hosting</a>, and some projects are entirely written, built, tested, and deployed with Cloudflare Workers.</p><p>Even better than that, many projects on Built with Workers are open-source, featuring a direct link to the Github repo, allowing you to quickly get at the source. The <a href="http://workers.cloudflare.com/built-with/projects/built-with-workers">Built with Workers site itself</a> is one of these open-source projects on the Built with Workers site.</p><p>We hope that the projects on Built with Workers will help inspire you to build your next project, by seeing just what’s possible.</p><p><a href="https://workers.cloudflare.com/built-with">Visit <b>Built with Workers</b> →</a></p><p>It’s been thrilling to see the incredible projects people are building. If you’ve got a project you’d like to share, please <a href="https://docs.google.com/forms/d/e/1FAIpQLSeIZmgY5ste4LZi-hNaJzbXHBbeD2DHWe8R2xxp0wKO0byRYA/viewform">fill out this form</a>.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[JAMstack]]></category>
            <guid isPermaLink="false">3xA1dqQzdeyqzvVCK7XCKp</guid>
            <dc:creator>Adam Schwartz</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing the HTMLRewriter API to Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/introducing-htmlrewriter/</link>
            <pubDate>Thu, 28 Nov 2019 08:00:00 GMT</pubDate>
            <description><![CDATA[ HTMLRewriter helps solve big problems web developers face today: making changes to the HTML at the server level, and making it possible for HTML to live on the edge— without sacrificing functionality. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>We are excited to announce that the HTMLRewriter API for Cloudflare Workers is now GA! You can get started today by checking out our <a href="https://developers.cloudflare.com/workers/reference/apis/html-rewriter/">documentation</a>, or trying out our <a href="https://developers.cloudflare.com/workers/tutorials/localize-a-website/">tutorial</a> for localizing your site with the HTMLRewriter.</p><p>Want to know how it works under the hood? We are excited to tell you everything you wanted to know but were afraid to ask, about building a streaming HTML parser on the edge; read about it in <a href="/html-parsing-1">part 1</a> (and stay tuned for part two coming tomorrow!).</p>
    <div>
      <h2>Faster, more scalable applications at the edge</h2>
      <a href="#faster-more-scalable-applications-at-the-edge">
        
      </a>
    </div>
    <p>The HTMLRewriter can help solve two big problems web developers face today: making changes to the HTML, when they are hard to make at the server level, and making it possible for HTML to live on the edge, closer to the user — without sacrificing dynamic functionality.</p><p>Since the introduction of Workers, Workers have helped customers regain control where control either wasn’t provided, or very hard to obtain at the origin level. Just like Workers can help you set CORS headers at the middleware layer, between your users and the origin, the HTMLRewriter can assist with things like URL rewrites (see the example below!).</p><p>Back in January, we <a href="/introducing-the-workers-cache-api-giving-you-control-over-how-your-content-is-cached/">introduced the Cache API</a>, giving you more control than ever over what you could store in our edge caches, and how. By helping users have closer control of the cache, users could push experiences that were previously only able to live at the origin server to the network edge. A great example of this is the ability to <a href="https://developers.cloudflare.com/workers/templates/pages/cache_api/">cache POST requests</a>, where previously only GET requests were able to benefit from living on the edge.</p><p>Later this year, during Birthday Week, we announced <a href="/workers-sites/">Workers Sites</a>, taking the idea of content on the edge one step further, and allowing you to fully deploy your static sites to the edge.</p><p>We were not the first to realize that the web could benefit from more content being accessible from the CDN level. The motivation behind the resurgence of static sites is to have a canonical version of HTML that can easily be cached by a <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDN</a>.</p><p>This has been great progress for static content on the web, but what about so much of the content that’s <i>almost</i> static, but not quite? Imagine an e-commerce website: the items being offered, and the promotions are all the same — except that pesky shopping cart on the top right. That small difference means the HTML can no longer be cached, and sent to the edge. That tiny little number of items in the cart requires you to travel all the way to your origin, and make a call to the database, for every user that visits your site. This time of year, around <a href="https://blog.cloudflare.com/the-truth-about-black-friday-and-cyber-monday/">Black Friday, and Cyber Monday</a>, this means you have to make sure that your origin, and database are able to scale to the maximum load of all the excited shoppers eager to buy presents for their loved ones.</p>
    <div>
      <h2>Edge-side JAMstack with HTMLRewriter</h2>
      <a href="#edge-side-jamstack-with-htmlrewriter">
        
      </a>
    </div>
    <p>One way to solve this problem of reducing origin load while retaining dynamic functionality is to move more of the logic to the client — this approach of making the HTML content static, leveraging CDN for caching, and relying on client-side API calls for dynamic content is known as the <a href="https://www.cloudflare.com/the-net/jamstack-websites/">JAMstack</a> (JavaScript, APIs, <a href="https://blog.cloudflare.com/markdown-for-agents/">Markdown</a>). The JAMstack is certainly a move in the right direction, trying to maximize content on the edge. We’re excited to embrace that approach even further, by allowing dynamic logic of the site to live on the edge as well.</p><p>In September, we introduced the <a href="/html-rewriter-beta/">HTMLRewriter API in beta</a> to the Cloudflare Workers runtime — a streaming parser API to allow developers to develop fully dynamic applications on the edge. HTMLRewriter is a jQuery-like experience inside your Workers application, allowing you to manipulate the DOM using selectors and handlers. The same way jQuery revolutionized front-end development, we’re excited for the HTMLRewriter to change how we think about architecting dynamic applications.</p><p>There are a few advantages to rewriting HTML on the edge, rather than on the client. First, updating content client-side introduces a tradeoff between the performance and consistency of the application — that is, if you want to, update a page to a logged in version client side, the user will either be presented with the static version first, and witness the page update (resulting in an inconsistency known as a flicker), or the rendering will be blocked until the customization can be fully rendered. Having the DOM modifications made edge-side provides the benefits of a scalable application, without the degradation of user experience. The second problem is the inevitable client-side bloat. Most of the world today is connected to the internet on a mobile phone with significantly less powerful CPU, and on shaky last-mile connections where each additional API call risks never making it back to the client. With the HTMLRewriter within Cloudflare Workers, the API calls for dynamic content, (or even calls directly to <a href="https://www.cloudflare.com/products/workers-kv/">Workers KV</a> for user-specific data) can be made from the Worker instead, on a much more powerful machine, over much more resilient backbone connections.</p><p>Here’s what the developers at Happy Cog have to say about HTMLRewriter:</p><p><i>"At </i><a href="https://www.happycog.com/"><i>Happy Cog</i></a><i>, we're excited about the JAMstack and static site generators for our clients because of their speed and security, but in the past have often relied on additional browser-based JavaScript and internet-exposed backend services to customize user experiences based on a cookied logged-in state. With Cloudflare's HTMLRewriter, that's now changed. HTMLRewriter is a fundamentally new powerful capability for static sites. It lets us parse the request and customize each user's experience without exposing any backend services, while continuing to use a JAMstack architecture. And it's fast. Because HTMLRewriter streams responses directly to users, our code can make changes on-the-fly without incurring a giant TTFB speed penalty. HTMLRewriter is going to allow us to make architectural decisions that benefit our clients and their users -- while avoiding a lot of the tradeoffs we'd usually have to consider."</i></p><p></p><p>— <b>Matt Weinberg</b>, - President of Development and Technology, Happy Cog</p>
    <div>
      <h2>HTMLRewriter in Action</h2>
      <a href="#htmlrewriter-in-action">
        
      </a>
    </div>
    <p>Since most web developers are familiar with jQuery, we chose to keep the HTMLRewriter very similar, using selectors and handlers to modify content.</p><p>Below, we have a simple example of how to use the HTMLRewriter to rewrite the URLs in your application from <code>myolddomain.com</code> to <code>mynewdomain.com</code>:</p>
            <pre><code>async function handleRequest(req) {
  const res = await fetch(req)
  return rewriter.transform(res)
}
 
const rewriter = new HTMLRewriter()
  .on('a', new AttributeRewriter('href'))
  .on('img', new AttributeRewriter('src'))
 
class AttributeRewriter {
  constructor(attributeName) {
    this.attributeName = attributeName
  }
 
  element(element) {
    const attribute = element.getAttribute(this.attributeName)
    if (attribute) {
      element.setAttribute(
        this.attributeName,
        attribute.replace('myolddomain.com', 'mynewdomain.com')
      )
    }
  }
}
 
addEventListener('fetch', event =&gt; {
  event.respondWith(handleRequest(event.request))
})</code></pre>
            <p>The HTMLRewriter, which is instantiated once per Worker, is used here to select the <code>a</code> and <code>img</code> elements.</p><p>An element handler responds to any incoming element, when attached using the <code>.on</code> function of the <code>HTMLRewriter</code> instance.</p><p>Here, our AttributeRewriter will receive every element parsed by the HTMLRewriter instance. We will then use it to rewrite each attribute, <code>href</code> for the <code>a</code> element for example, to update the URL in the HTML.</p>
    <div>
      <h2>Getting started</h2>
      <a href="#getting-started">
        
      </a>
    </div>
    <p>You can get started with the HTMLRewriter by <a href="https://dash.cloudflare.com/sign-up/workers">signing up</a> for Workers today. For a full guide on how to use the HTMLRewriter API, we suggest checking out our <a href="https://developers.cloudflare.com/workers/reference/apis/html-rewriter/">documentation</a>.</p>
    <div>
      <h2>How does the HTMLRewriter work?</h2>
      <a href="#how-does-the-htmlrewriter-work">
        
      </a>
    </div>
    <p>How does the HTMLRewriter work under the hood? We’re excited to tell you about it, and have spared no details. Check out the <a href="/html-parsing-1">first part</a> of our two-blog post series to learn all about the not-so-brief history of rewriter HTML at Cloudflare, and stay tuned for part two tomorrow!</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Workers Sites]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[JAMstack]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">3sXy4h1845qNOYeTtszQNy</guid>
            <dc:creator>Rita Kozlov</dc:creator>
        </item>
    </channel>
</rss>