
<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, 08 Apr 2026 05:21:10 GMT</lastBuildDate>
        <item>
            <title><![CDATA["Just use Vite”… with the Workers runtime]]></title>
            <link>https://blog.cloudflare.com/introducing-the-cloudflare-vite-plugin/</link>
            <pubDate>Tue, 08 Apr 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ The Cloudflare Vite plugin integrates Vite, one of the most popular build tools for web development, with Workers runtime. Today, we announce the 1.0 release and official support for React Router v7. ]]></description>
            <content:encoded><![CDATA[ <p>Today, we are announcing the 1.0 release of the Cloudflare Vite plugin, as well as official support for React Router v7!</p><p>Over the past few years, <a href="https://vite.dev/"><u>Vite</u></a>’s meteoric rise has seen it become one of the most popular build tools for web development, with a large ecosystem and vibrant community. The <a href="https://developers.cloudflare.com/workers/vite-plugin/"><u>Cloudflare Vite plugin</u></a> brings the Workers runtime right into its beating heart! Previously, the Vite dev server would always run your server code in Node.js, even if you were deploying to Cloudflare Workers. By using the new <a href="https://vite.dev/guide/api-environment"><u>Environment API</u></a>, released experimentally in <a href="https://vite.dev/blog/announcing-vite6"><u>Vite 6</u></a>, your Worker code can now run inside the native Cloudflare Workers runtime (<a href="https://github.com/cloudflare/workerd"><u>workerd</u></a>). This means that the dev server matches the production behavior as closely as possible, and provides confidence as you develop and deploy your applications.
</p><p>Vite 6 includes the most significant changes to Vite’s architecture since its inception and unlocks many new possibilities for the ecosystem. Fundamental to this is the Environment API, which enables the Vite dev server to interact with any number of custom runtime environments. This means that it is now possible to run server code in alternative JavaScript runtimes, such as our own workerd.</p><p>We are grateful to have collaborated closely with the <a href="https://vite.dev/team"><u>Vite team</u></a> on its design and implementation. When you see first-hand the thoughtful and generous way in which they go about their work, it’s no wonder that Vite and its ecosystem are in such great shape!</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Nu8hnh2qcICkWBlXlEoFO/9e71cd44ad126d0c08960a94140dd540/unnamed__5_.png" />
          </figure><p><sup><i>Vite 6 with a Cloudflare Worker environment</i></sup><sup><b> </b></sup></p><p>Here you can see how it all fits together. The user views a page in the browser (1), which triggers a request to the Vite Dev Server (2). Vite processes the request, resolving, loading, and transforming source files into modules that are added to the client and Worker environments. The client modules are downloaded to the browser to be run as client-side JavaScript, and the Worker modules are sent to the Cloudflare Workers runtime to handle server-side requests. The request is handled by the Worker (3 and 4) and the Vite Dev Server returns the response to the browser (5), which displays the result to the user (6).</p>
    <div>
      <h2>Single-page applications</h2>
      <a href="#single-page-applications">
        
      </a>
    </div>
    <p>Vite has become the go-to choice for developing single-page applications (<a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA"><u>SPAs</u></a>), whether your preferred frontend framework is <a href="https://react.dev/"><u>React</u></a>, <a href="https://vuejs.org/"><u>Vue</u></a>, <a href="https://svelte.dev/"><u>Svelte</u></a>, or one of many others.</p>
    <div>
      <h3>Create a new app</h3>
      <a href="#create-a-new-app">
        
      </a>
    </div>
    <p>Let’s try out the new Cloudflare Vite plugin by creating a new React SPA using the <code>create-cloudflare </code>CLI.</p>
            <pre><code>npm create cloudflare@latest my-react-app -- --framework=react --platform=workers</code></pre>
            <p>This command runs <code>create-vite</code> and then makes the necessary changes to incorporate the Cloudflare Vite plugin.</p><p>Using the button below, you can also create a React SPA project on Cloudflare Workers, connected to a git repository of your choice, configured with <a href="https://developers.cloudflare.com/workers/ci-cd/builds/"><u>Cloudflare Workers Builds</u></a> to automatically deploy, and set up to use the new Vite plugin for local development.</p><a href="https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/staging/vite-react-template"><img src="https://deploy.workers.cloudflare.com/button" /></a>
<p></p>
    <div>
      <h3>Update an existing app</h3>
      <a href="#update-an-existing-app">
        
      </a>
    </div>
    <p>If you would instead like to update an existing Vite SPA project in the same way, you can follow these two steps:</p><p>Add the <code>@cloudflare/vite-plugin</code> dependency to the list of plugins:</p>
            <pre><code>import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { cloudflare } from "@cloudflare/vite-plugin";

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), cloudflare()],
});</code></pre>
            <p>Add a <code>wrangler.jsonc</code> configuration file alongside your Vite config:</p>
            <pre><code>{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-react-app",
  "compatibility_date": "2025-04-01",
  "assets": {
    "not_found_handling": "single-page-application",
  },
}</code></pre>
            <p>For a purely front-end application, the Cloudflare plugin integrates the Vite dev server with <a href="https://developers.cloudflare.com/workers/static-assets/"><u>Workers Assets</u></a> to ensure that settings such as <code>html_handling</code> and <code>not_found_handling</code> behave the same way as they do in production. This is just the beginning, however. The real magic happens when you add a Worker backend that is seamlessly integrated into your development and deployment workflow.</p>
    <div>
      <h3>Develop the app</h3>
      <a href="#develop-the-app">
        
      </a>
    </div>
    <p>To see this in action, start the Vite development server, which will run your Worker in the Cloudflare Workers runtime:</p>
            <pre><code>npm run dev</code></pre>
            <p>In your browser, click the first displayed button a few times to increment the counter. This is a classic SPA running JavaScript in your browser. Next, click the second button to fetch the response from the API. Notice that it displays <code>Name from API is: Cloudflare</code>. This is making an API request to a Cloudflare Worker running inside Vite.</p><p>Have a look at <code>api/index.ts</code>. This file contains a Worker that is invoked for any request not matching a static asset. It returns a JSON response if the <code>pathname</code> starts with <code>/api/</code>.</p><p>Edit <code>api/index.ts</code> by changing the <code>name</code> it returns to <code>’Cloudflare Workers’</code> and save your changes. If you click the second button in the browser again, it will now display the new <code>name</code> while preserving the previously set counter value. Vite tracked your changes and updated the Worker environment without affecting the client environment. With Vite and the Cloudflare plugin, you can iterate on the client and server parts of your app together, without losing UI state between edits.</p><p>The Cloudflare Vite integration doesn’t end with the dev server. <code>vite build</code> outputs the client and server parts of your application with a single command. <code>vite preview</code> allows you to preview your build output in the Workers runtime prior to deployment. Finally, <code>wrangler deploy</code> recognises that you have generated a Vite build and deploys your application directly without any additional bundling.</p>
    <div>
      <h2>React Router v7</h2>
      <a href="#react-router-v7">
        
      </a>
    </div>
    <p>While Vite began its life primarily as a build tool for single-page applications, it has since become the foundation for the current generation of full-stack frameworks. <a href="https://astro.build/"><u>Astro</u></a>, <a href="https://qwik.dev/"><u>Qwik</u></a>, <a href="https://reactrouter.com/"><u>React Router</u></a>, <a href="https://svelte.dev/"><u>SvelteKit</u></a> and others have all adopted Vite, drawing on its development server, build pipeline, and phenomenal developer experience. In addition to working with the Vite team on the Environment API, we have also partnered closely with the Remix team on their adoption of Vite Environments. Today, we are announcing first-class support for <a href="https://reactrouter.com/"><u>React Router v7</u></a> (the successor to Remix) in the Cloudflare Vite plugin.</p><p>You can use the <code>create-cloudflare</code> CLI to create a new React Router application configured with the Cloudflare Vite plugin.</p>
            <pre><code>npm create cloudflare@latest my-react-router-app -- --framework=react-router</code></pre>
            <p>Run <code>npm run dev</code> to start the dev server. You can also try building (<code>npm run build</code>), previewing (<code>npm run preview</code>), and deploying (<code>npm run deploy)</code> your application.</p><p>Have a look at the code below, taken from <code>workers/app.ts</code>. This is the file referenced in the <code>main</code> field in <code>wrangler.jsonc:</code></p>
            <pre><code>const requestHandler = createRequestHandler(
  () =&gt; import("virtual:react-router/server-build"),
  import.meta.env.MODE
);

export default {
  async fetch(request, env, ctx) {
    return requestHandler(request, {
      cloudflare: { env, ctx },
    });
  },
} satisfies ExportedHandler&lt;CloudflareEnvironment&gt;;</code></pre>
            <p>This single file defines your Worker at both dev and build time and puts you in full control. No more build-time adapters! Notice how the <code>env</code> and <code>ctx</code> are passed down directly in the request handler. These are then accessible in your loaders and actions, which are running inside the Workers runtime along with the rest of your server code. You can add other exports to this file to suit your needs and then reference them in your Worker config. Want to add a <a href="https://developers.cloudflare.com/durable-objects/"><u>Durable Object</u></a> or a <a href="https://developers.cloudflare.com/workflows/"><u>Workflow</u></a>? Go for it!</p><p>This will be the first in a series of full-stack frameworks to be supported and we look forward to continuing discussion and collaboration with a range of teams over the coming months. If you are a framework contributor looking to improve integration with Cloudflare and/or the Vite Environment API, then please feel free to explore the <a href="https://github.com/cloudflare/workers-sdk/tree/main/packages/vite-plugin-cloudflare"><u>code</u></a> and reach out on <a href="https://github.com/cloudflare/workers-sdk/issues/new/choose"><u>GitHub</u></a> or <a href="https://discord.com/channels/595317990191398933/1356634720628248780"><u>Discord</u></a>.</p>
    <div>
      <h2>Workers</h2>
      <a href="#workers">
        
      </a>
    </div>
    <p>While this post has focused thus far on using Vite to build web applications, the Cloudflare plugin enables you to use Vite to build anything you can build with Workers. The full Cloudflare Developer Platform is supported, including <a href="https://developers.cloudflare.com/kv/"><u>KV</u></a>, <a href="https://developers.cloudflare.com/d1/"><u>D1</u></a>, <a href="https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/"><u>Service Bindings</u></a>, <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/"><u>RPC</u></a>, <a href="https://developers.cloudflare.com/durable-objects/"><u>Durable Objects</u></a>, <a href="https://developers.cloudflare.com/workflows/"><u>Workflows</u></a>, <a href="https://developers.cloudflare.com/workers-ai/"><u>Workers AI</u></a>, etc. In fact, in most cases, taking an existing Worker and developing it with Vite is as simple as following these two steps:</p><p>Install the dependencies:</p>
            <pre><code>npm install –save-dev vite @cloudflare/vite-plugin</code></pre>
            <p>
And add a Vite config:</p>
            <pre><code>// vite.config.ts

import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({
  plugins: [cloudflare()],
});</code></pre>
            <p>That’s it! By default, the plugin will look for a <code>wrangler.json</code>, <code>wrangler.jsonc</code>, or <code>wrangler.toml</code> config file in the root of your Vite project. By using Vite, you can draw on its rich ecosystem of plugins and integrations and easily customize your build output.</p>
    <div>
      <h2>Wrapping up</h2>
      <a href="#wrapping-up">
        
      </a>
    </div>
    <p>In 2024, we <a href="https://blog.cloudflare.com/blazing-fast-development-with-full-stack-frameworks-and-cloudflare"><u>announced</u></a> <code>getPlatformProxy()</code> as a way to access Cloudflare bindings from development servers running in Node. At the end of that post, we <a href="https://blog.cloudflare.com/blazing-fast-development-with-full-stack-frameworks-and-cloudflare/#future-improvements-to-development-workflows-with-vite"><u>imagined a future</u></a> where it would instead be possible to develop directly in the Workers runtime. This would eliminate the many subtle ways that development and production behavior could differ. Today, that future is a reality, and we can’t wait for you to try it out!</p><p>Start a new project with our React Router, React, or Vue templates using the <code>create-cloudflare</code> CLI, use the “Deploy to Cloudflare” button below, or try adding <code>@cloudflare/vite-plugin</code> to your existing Vite applications. We’re excited to see what you build!</p><a href="https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/staging/vite-react-template"><img src="https://deploy.workers.cloudflare.com/button" /></a>
<p></p><p>Read more in our <a href="https://developers.cloudflare.com/workers/vite-plugin/"><u>Cloudflare Vite Plugin documentation</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <guid isPermaLink="false">4NaEhSL9wVMXjcPnibDIs1</guid>
            <dc:creator>James Opstad</dc:creator>
            <dc:creator>Dario Piotrowicz</dc:creator>
            <dc:creator>Peter Bacon Darwin</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
        </item>
        <item>
            <title><![CDATA[More NPM packages on Cloudflare Workers: Combining polyfills and native code to support Node.js APIs]]></title>
            <link>https://blog.cloudflare.com/more-npm-packages-on-cloudflare-workers-combining-polyfills-and-native-code/</link>
            <pubDate>Mon, 09 Sep 2024 21:00:00 GMT</pubDate>
            <description><![CDATA[ Workers now supports more NPM packages and Node.js APIs using an overhauled hybrid compatibility layer. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today, we are excited to announce a preview of <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>improved Node.js compatibility</u></a> for Workers and Pages. Broader compatibility lets you use more NPM packages and take advantage of the JavaScript ecosystem when writing your Workers.</p><p>Our newest version of Node.js compatibility combines the best features of our previous efforts. <a href="https://workers.cloudflare.com/"><u>Cloudflare Workers</u></a> have supported Node.js in some form for quite a while. We first announced polyfill support in <a href="https://blog.cloudflare.com/node-js-support-cloudflare-workers"><u>2021</u></a>, and later <a href="https://blog.cloudflare.com/workers-node-js-asynclocalstorage"><u>built-in support for parts of the Node.js API</u></a> that has <a href="https://blog.cloudflare.com/workers-node-js-apis-stream-path"><u>expanded</u></a> over time.</p><p>The latest changes make it even better:</p><ul><li><p>You can use far more <a href="https://en.wikipedia.org/wiki/Npm"><u>NPM</u></a> packages on Workers.</p></li><li><p>You can use packages that do not use the <code>node</code>: prefix to import Node.js APIs</p></li><li><p>You can use <a href="https://workers-nodejs-compat-matrix.pages.dev/"><u>more Node.js APIs on Workers</u></a>, including most methods on <a href="https://nodejs.org/docs/latest/api/async_hooks.html"><code><u>async_hooks</u></code></a>, <a href="https://nodejs.org/api/buffer.html"><code><u>buffer</u></code></a>, <a href="https://nodejs.org/api/dns.html"><code><u>dns</u></code></a>, <a href="https://nodejs.org/docs/latest/api/os.html"><code><u>os</u></code></a>, and <a href="https://nodejs.org/docs/latest/api/events.html"><code><u>events</u></code></a>. Many more, such as <a href="https://nodejs.org/api/fs.html"><code><u>fs</u></code></a> or <a href="https://nodejs.org/docs/latest/api/process.html"><code><u>process</u></code></a> are importable with mocked methods.</p></li></ul><p>To give it a try, add the following flag to <code>wrangler.toml</code>, and deploy your Worker with <a href="https://developers.cloudflare.com/workers/wrangler/"><u>Wrangler</u></a>:</p><p><code>compatibility_flags = ["nodejs_compat_v2"]</code></p><p>Packages that could not be imported with <code>nodejs_compat</code>, even as a dependency of another package, will now load. This includes popular packages such as <a href="https://www.npmjs.com/package/body-parser">body-parser</a>, <a href="https://www.npmjs.com/package/jsonwebtoken">jsonwebtoken</a>, {}<a href="https://www.npmjs.com/package/got">got</a>, <a href="https://www.npmjs.com/package/passport">passport</a>, <a href="https://www.npmjs.com/package/md5">md5</a>, <a href="https://www.npmjs.com/package/knex">knex</a>, <a href="https://www.npmjs.com/package/mailparser">mailparser</a>, <a href="https://www.npmjs.com/package/csv-stringify">csv-stringify</a>, <a href="https://www.npmjs.com/package/cookie-signature">cookie-signature</a>, <a href="https://www.npmjs.com/package/stream-slice">stream-slice</a>, and many more.</p><p>This behavior will soon become the default for all Workers with the <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>existing nodejs_compat compatibility flag</u></a> enabled, and a <a href="https://developers.cloudflare.com/workers/configuration/compatibility-dates/"><u>compatibility date</u></a> of 2024-09-23 or later. As you experiment with improved Node.js compatibility, share your feedback by <a href="https://github.com/cloudflare/workers-sdk/issues/new?assignees=&amp;labels=bug&amp;projects=&amp;template=bug-template.yaml&amp;title=%F0%9F%90%9B+BUG%3A"><u>opening an issue on GitHub</u></a>.</p>
    <div>
      <h3>Workerd is not Node.js</h3>
      <a href="#workerd-is-not-node-js">
        
      </a>
    </div>
    <p>To understand the latest changes, let’s start with a brief overview of how the Workers runtime differs from <a href="https://nodejs.org/"><u>Node.js</u></a>.</p><p>Node.js was built primarily for services run directly on a host OS and pioneered server-side JavaScript. Because of this, it includes functionality necessary to interact with the host machine, such as <a href="https://nodejs.org/api/process.html"><u>process</u></a> or <a href="https://nodejs.org/api/fs.html"><u>fs</u></a>, and a variety of utility modules, such as <a href="https://nodejs.org/api/crypto.html"><u>crypto</u></a>.</p><p>Cloudflare Workers run on an open source JavaScript/Wasm runtime called <a href="https://github.com/cloudflare/workerd"><u>workerd</u></a>. While both Node.js and workerd are built on <a href="https://v8.dev/"><u>V8</u></a>, workerd is <a href="https://blog.cloudflare.com/cloud-computing-without-containers"><u>designed to run untrusted code in shared processes</u></a>, exposes <a href="https://developers.cloudflare.com/workers/runtime-apis/bindings/"><u>bindings</u></a> for interoperability with other Cloudflare services, including <a href="https://blog.cloudflare.com/javascript-native-rpc"><u>JavaScript-native RPC</u></a>, and uses <a href="https://blog.cloudflare.com/introducing-the-wintercg"><u>web-standard APIs</u></a> whenever possible.</p><p>Cloudflare <a href="https://blog.cloudflare.com/introducing-the-wintercg/"><u>helped establish</u></a> <a href="https://wintercg.org/"><u>WinterCG</u></a>, the Web-interoperable Runtimes Community Group to improve interoperability of JavaScript runtimes, both with each other and with the web platform. You can build many applications using only web-standard APIs, but what about when you want to import dependencies from NPM that rely on Node.js APIs?</p><p>For example, if you attempt to import <a href="https://www.npmjs.com/package/pg"><u>pg</u></a>, a PostgreSQL driver, without Node.js compatibility turned on…</p>
            <pre><code>import pg from 'pg'</code></pre>
            <p>You will see the following error when you run <a href="https://developers.cloudflare.com/workers/wrangler/commands/#dev"><u>wrangler dev</u></a> to build your Worker:</p>
            <pre><code>✘ [ERROR] Could not resolve "events"
    ../node_modules/.pnpm/pg-cloudflare@1.1.1/node_modules/pg-cloudflare/dist/index.js:1:29:
      1 │ import { EventEmitter } from 'events';
        ╵                              ~~~~~~~~
  The package "events" wasn't found on the file system but is built into node.</code></pre>
            <p>This happens because the pg package imports the <a href="https://nodejs.org/api/events.html"><u>events module</u></a> from Node.js, which is not provided by workerd by default.</p><p>How can we enable this?</p>
    <div>
      <h3>Our first approach – build-time polyfills</h3>
      <a href="#our-first-approach-build-time-polyfills">
        
      </a>
    </div>
    <p>Polyfills are code that add functionality to a runtime that does not natively support it. They are often added to provide modern JavaScript functionality to older browsers, but can be used for server-side runtimes as well.</p><p>In 2022, we <a href="https://github.com/cloudflare/workers-sdk/pull/869"><u>added functionality to Wrangler</u></a> that injected polyfill implementations of some Node.js APIs into your Worker if you set <code>node_compat = true</code> in your wrangler.toml. For instance, the following code would work with this flag, but not without:</p>
            <pre><code>import EventEmitter from 'events';
import { inherits } from 'util';</code></pre>
            <p>These polyfills are essentially just additional JavaScript code added to your Worker by <a href="https://developers.cloudflare.com/workers/wrangler/"><u>Wrangler</u></a> when deploying the Worker. This behavior is enabled by <a href="https://www.npmjs.com/package/@esbuild-plugins/node-globals-polyfill"><code><u>@esbuild-plugins/node-globals-polyfill</u></code></a> which in itself uses <a href="https://github.com/ionic-team/rollup-plugin-node-polyfills/"><code><u>rollup-plugin-node-polyfills</u></code></a>.</p><p>This allows you to import and use some NPM packages, such as pg. However, many modules cannot be polyfilled with fast enough code or cannot be polyfilled at all.</p><p>For instance, <a href="https://nodejs.org/api/buffer.html"><u>Buffer</u></a> is a common Node.js API used to handle binary data. Polyfills exist for it, but JavaScript is often not optimized for the operations it performs under the hood, such as <code>copy</code>, <code>concat</code>, substring searches, or transcoding. While it is possible to implement in pure JavaScript, it could be far faster if the underlying runtime could use primitives from different languages. Similar limitations exist for other popular APIs such as <a href="https://nodejs.org/api/crypto.html"><u>Crypto</u></a>, <a href="https://nodejs.org/api/async_context.html"><u>AsyncLocalStorage</u></a>, and <a href="https://nodejs.org/api/stream.html"><u>Stream</u></a>.</p>
    <div>
      <h3>Our second approach – native support for some Node.js APIs in the Workers runtime</h3>
      <a href="#our-second-approach-native-support-for-some-node-js-apis-in-the-workers-runtime">
        
      </a>
    </div>
    <p>In 2023, we <a href="https://blog.cloudflare.com/workers-node-js-asynclocalstorage"><u>started adding</u></a> a subset of Node.js APIs directly to the Workers runtime. You can enable these APIs by adding the <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>nodejs_compat compatibility flag</u></a> to your Worker, but you cannot use polyfills with <code>node_compat = true</code> at the same time.</p><p>Also, when importing Node.js APIs, you must use the <code>node</code>: prefix:</p>
            <pre><code>import { Buffer } from 'node:buffer';</code></pre>
            <p>Since these Node.js APIs are built directly into the Workers runtime, they can be <a href="https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/buffer.c%2B%2B"><u>written in C++</u></a>, which allows them to be faster than JavaScript polyfills. APIs like <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/asynclocalstorage/"><u>AsyncLocalStorage</u></a>, which cannot be polyfilled without safety or performance issues, can be provided natively.</p><p>Requiring the <code>node: </code>prefix made imports more explicit and aligns with modern Node.js conventions. Unfortunately, existing NPM packages may import modules without <code>node:</code>. For instance, revisiting the example above, if you import the popular package <code>pg</code> in a Worker with the <code>nodejs_compat</code> flag, you still see the following error:</p>
            <pre><code>✘ [ERROR] Could not resolve "events"
    ../node_modules/.pnpm/pg-cloudflare@1.1.1/node_modules/pg-cloudflare/dist/index.js:1:29:
      1 │ import { EventEmitter } from 'events';
        ╵                              ~~~~~~~~
  The package "events" wasn't found on the file system but is built into node.</code></pre>
            <p>Many NPM packages still didn’t work in Workers, even if you enabled the <code>nodejs_compat</code> compatibility flag. You had to choose between a smaller set of performant APIs, exposed in a way that many NPM packages couldn’t access, or a larger set of incomplete and less performant APIs. And APIs like <code>process</code> that are exposed as globals in Node.js could still only be accessed by importing them as modules.</p>
    <div>
      <h3>The new approach: a hybrid model</h3>
      <a href="#the-new-approach-a-hybrid-model">
        
      </a>
    </div>
    <p>What if we could have the best of both worlds, and it just worked?</p><ul><li><p>A subset of Node.js APIs implemented directly in the Workers Runtime </p></li><li><p>Polyfills for the majority of other Node.js APIs</p></li><li><p>No <code>node</code>: prefix required</p></li><li><p>One simple way to opt-in</p></li></ul><p>Improved Node.js compatibility does just that.</p><p>Let’s take a look at two lines of code that look similar, but now act differently under the hood when <code>nodejs_compat_v2</code> is enabled:</p>
            <pre><code>import { Buffer } from 'buffer';  // natively implemented
import { isIP } from 'net'; // polyfilled</code></pre>
            <p>The first line imports <code>Buffer</code> from a <a href="https://github.com/cloudflare/workerd/blob/main/src/node/internal/internal_buffer.ts"><u>JavaScript module</u></a> in workerd that is backed by <a href="https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/buffer.c%2B%2B"><code><u>C++ code</u></code></a>. Various other Node.js modules are similarly implemented in a combination of Typescript and C++, including <a href="https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/async-hooks.h"><code><u>AsyncLocalStorage</u></code></a> and <a href="https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/crypto.h"><code><u>Crypto</u></code></a>. This allows for highly performant code that matches Node.js behavior.</p><p>Note that the <code>node:</code> prefix is not needed when importing <code>buffer</code>, but the code would also work with <code>node:buffer</code>.</p><p>The second line imports <code>net</code> which Wrangler automatically polyfills using a library called <a href="https://github.com/unjs/unenv"><u>unenv</u></a>. Polyfills and built-in runtime APIs now work together.</p><p>Previously, when you set <code>node_compat = true</code>, Wrangler added polyfills for every Node.js API that it was able to, even if neither your Worker nor its dependencies used that API. When you enable the <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>nodejs_compat_v2 compatibility flag</u></a>, Wrangler only adds polyfills for Node.js APIs that your Worker or its dependencies actually use. This results in small Worker sizes, even with polyfills.</p><p>For some Node.js APIs, there is not yet native support in the Workers runtime nor a polyfill implementation. In these cases, unenv “mocks” the interface. This means it adds the module and its methods to your Worker, but calling methods of the module will either do nothing or will throw an error with a message like:</p><p><code>[unenv] &lt;method name&gt; is not implemented yet!</code></p><p>This is more important than it might seem. Because if a Node.js API is “mocked”, NPM packages that depend on it can still be imported. Consider the following code:</p>
            <pre><code>// Package name: my-module

import fs from "fs";

export function foo(path) {
  const data = fs.readFileSync(path, 'utf8');
  return data;
}

export function bar() {
  return "baz";
}
</code></pre>
            
            <pre><code>import { bar } from "my-module"

bar(); // returns "baz"
foo(); // throws readFileSync is not implemented yet!
</code></pre>
            <p>Previously, even with the <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>existing nodejs_compat compatibility flag</u></a> enabled, attempting to import my-module would fail at build time, because the <code>fs</code> module could not be resolved. Now, the <code>fs</code> module can be resolved, methods that do not rely on an unimplemented Node.js API work, and methods that do throw a more specific error – a runtime error that a specific Node.js API method is not yet supported, rather than a build-time error that the module could not be resolved.</p><p>This is what enables some packages to transition from “doesn’t even load on Workers” to, “loads, but with some unsupported methods”.</p>
    <div>
      <h3>Still missing an API from Node.js? Module aliasing to the rescue</h3>
      <a href="#still-missing-an-api-from-node-js-module-aliasing-to-the-rescue">
        
      </a>
    </div>
    <p>Let’s say you need an NPM package to work on Workers that relies on a Node.js API that isn’t yet implemented in the Workers runtime or as a polyfill in unenv. You can use <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#module-aliasing"><u>module aliasing</u></a> to implement just enough of that API to make things work.</p><p>For example, let’s say the NPM package you need to work calls <a href="https://nodejs.org/api/fs.html#fsreadfilepath-options-callback"><u>fs.readFile</u></a>. You can alias the fs module by adding the following to your Worker’s wrangler.toml:</p>
            <pre><code>[alias]
"fs" = "./fs-polyfill"</code></pre>
            <p>Then, in the fs-polyfill.js file, you can define your own implementation of any methods of the fs module:</p>
            <pre><code>export function readFile() {
  console.log("readFile was called");
  // ...
}
</code></pre>
            <p>Now, the following code, which previously threw the error message “[unenv] readFile is not implemented yet!”, runs without errors:</p>
            <pre><code>import { readFile } from 'fs';

export default {
  async fetch(request, env, ctx) {
    readFile();
    return new Response('Hello World!');
  },
};
</code></pre>
            <p>You can also use module aliasing to provide an implementation of an NPM package that does not work on Workers, even if you only rely on that NPM package indirectly, as a dependency of one of your Worker's dependencies.</p><p>For example, some NPM packages, such as <a href="https://www.npmjs.com/package/cross-fetch"><u>cross-fetch</u></a>, depend on <a href="https://www.npmjs.com/package/node-fetch"><u>node-fetch</u></a>, a package that provided a polyfill of the <a href="https://developers.cloudflare.com/workers/runtime-apis/fetch/"><u>fetch() API</u></a> before it was built into Node.js. The node-fetch package isn't needed in Workers, because the fetch() API is provided by the Workers runtime. And node-fetch doesn't work on Workers, because it relies on currently unsupported Node.js APIs from the <a href="https://nodejs.org/api/http.html"><u>http</u></a> and <a href="https://nodejs.org/api/https.html"><u>https</u></a> modules.</p><p>You can alias all imports of node-fetch to instead point directly to the fetch() API that is built into the Workers runtime using the popular <a href="https://github.com/SukkaW/nolyfill"><u>nolyfill</u></a> package:</p>
            <pre><code>[alias]
"node-fetch" = "./fetch-nolyfill"</code></pre>
            <p>All your replacement module needs to do in this case is to re-export the fetch API that is built into the Workers runtime:</p>
            <pre><code>export default fetch;</code></pre>
            
    <div>
      <h3>Contributing back to unenv</h3>
      <a href="#contributing-back-to-unenv">
        
      </a>
    </div>
    <p>Cloudflare is actively contributing to unenv. We think unenv is solving the problem of cross-runtime compatibility the right way — it adds only the necessary polyfills to your application, based on what APIs you use and what runtime you target. The project supports a variety of runtimes beyond workerd and is already used by other popular projects including <a href="https://nuxt.com/"><u>Nuxt</u></a> and <a href="https://nitro.unjs.io/"><u>Nitro</u></a>. We want to thank <a href="https://github.com/pi0"><u>Pooya Parsa</u></a> and the unenv maintainers and encourage others in the ecosystem to adopt or contribute.</p>
    <div>
      <h3>The path forward</h3>
      <a href="#the-path-forward">
        
      </a>
    </div>
    <p>Currently, you can enable improved Node.js compatibility by setting the <code>nodejs_compat_v2</code> flag in <code>wrangler.toml</code>. We plan to make the new behavior the default when using the <code>nodejs_compat</code> flag on September 23rd. This will require updating your <a href="https://developers.cloudflare.com/workers/configuration/compatibility-dates/"><code><u>compatibility_date</u></code></a>.</p><p>We are excited about the changes coming to Node.js compatibility, and encourage you to try it today. <a href="https://developers.cloudflare.com/workers/runtime-apis/nodejs/"><u>See the documentation</u></a> on how to opt-in for your Workers, and please send feedback and report bugs <a href="https://github.com/cloudflare/workers-sdk/issues/new?assignees=&amp;labels=bug&amp;projects=&amp;template=bug-template.yaml&amp;title=%F0%9F%90%9B+BUG%3A"><u>by opening an issue</u></a>. Doing so will help us identify any gaps in support and ensure that as much of the Node.js ecosystem as possible runs on Workers.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Node.js]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[JavaScript]]></category>
            <guid isPermaLink="false">3zICVbgdxrLByG4g2Dsddy</guid>
            <dc:creator>James M Snell</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
            <dc:creator>James Culveyhouse</dc:creator>
            <dc:creator>Mike Nomitch</dc:creator>
        </item>
        <item>
            <title><![CDATA[Blazing fast development with full-stack frameworks and Cloudflare]]></title>
            <link>https://blog.cloudflare.com/blazing-fast-development-with-full-stack-frameworks-and-cloudflare/</link>
            <pubDate>Fri, 05 Apr 2024 13:00:44 GMT</pubDate>
            <description><![CDATA[ You can now use your framework’s development server while accessing D1 databases, R2 object stores, AI models, and more. Iterate locally in milliseconds to build sophisticated web apps that run on Cloudflare ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Hello web developers! <a href="/making-cloudflare-for-web">Last year we released</a> a slew of improvements that made deploying web applications on Cloudflare much easier, and in response we’ve seen a large growth of Astro, Next.js, Nuxt, Qwik, Remix, SolidStart, SvelteKit, and other web apps hosted on Cloudflare. Today we are announcing major improvements to our integration with these web frameworks that makes it easier to develop sophisticated applications that use our <a href="https://www.cloudflare.com/developer-platform/products/d1/">D1 SQL database</a>, <a href="https://developers.cloudflare.com/r2/">R2</a> object store, <a href="https://developers.cloudflare.com/ai/">AI</a> models, and other powerful features of <a href="https://www.cloudflare.com/developer-platform/">Cloudflare’s developer platform.</a></p><p>In the past, if you wanted to develop a web framework-powered application with D1 and run it locally, you’d have to build a production build of your application, and then run it locally using `wrangler pages dev`. While this worked, each of your code iterations would take seconds, or tens of seconds for big applications. Iterating using production builds is simply too slow, pulls you out of the <a href="https://en.wikipedia.org/wiki/Flow_(psychology)">flow</a>, and doesn’t allow you to take advantage of all the DX optimizations that framework authors have put a lot of hard work into. This is changing today!</p><p>Our goal is to integrate with web frameworks in the most natural way possible, without developers having to learn and adopt significant workflow changes or custom APIs when deploying their app to Cloudflare. Whether you are a Next.js developer, a Nuxt developer, or prefer another framework, you can now keep on using the blazing fast local development workflow familiar to you, and ship your application on Cloudflare.</p><p>All full-stack web frameworks come with a local development server (dev server) that is custom tailored to the framework and often provides an excellent development experience, with only one exception — they don't natively support some important features of Cloudflare’s development platform, especially our <a href="https://www.cloudflare.com/developer-platform/products/#storage">storage solutions</a>.</p><p>So up until recently, you had to make a tough choice. You could use the framework-specific dev server to develop your application, but forgo access to many of Cloudflare’s features. Alternatively, you could take full advantage of Cloudflare’s platform including various resources like D1 or R2<a href="https://developers.cloudflare.com/workers/configuration/bindings/">, but you would have to give up using the framework specific developer tooling. In that case, your iteration cycle would slow down, and it would take seconds rather than milliseconds for you to see results of your code changes in the browser.</a> But not anymore! Let’s take a look.</p>
    <div>
      <h3>Let’s build an application</h3>
      <a href="#lets-build-an-application">
        
      </a>
    </div>
    <p>Let’s create a new application using <a href="https://developers.cloudflare.com/pages/get-started/c3/">C3</a> — our create-cloudflare CLI. We could use any npm client of our choice (pnpm anyone?!?), but to keep things simple in this post, we’ll stick with the default npm client. To get started, just run:</p><p><code>$ npm create cloudflare@latest</code></p><p>Provide a name for your app, or stick with the randomly generated one. Then select the “Website or web app” category, and pick a full-stack framework of your choice. We support many: <a href="https://astro.build/">Astro</a>, <a href="https://nextjs.org/">Next.js</a>, <a href="https://nuxt.com/">Nuxt</a>, <a href="https://qwik.dev/">Qwik</a>, <a href="https://remix.run/">Remix</a>, <a href="https://start.solidjs.com/getting-started/what-is-solidstart">SolidStart</a>, and <a href="https://kit.svelte.dev/">SvelteKit</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/pa9natISsY3icyIUpu9Ul/cd6aa0baebe85d1b0a85eaba684d66e6/Screenshot-2024-03-28-at-7.25.10-AM.png" />
            
            </figure><p>Since C3 delegates the application scaffolding to the latest version of the framework-specific CLI, you will scaffold the application exactly as the framework authors intended without missing out on any of the framework features or options. C3 then adds to your application everything necessary for integrating and deploying to Cloudflare so that you don’t have to configure it yourself.</p><p>With our application scaffolded, let’s get it to display a list of products stored in a database with just a few steps. First, we add the configuration for our database to our <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases">wrangler.toml</a> config file:</p>
            <pre><code>[[d1_databases]]
binding = "DB"
database_name = "blog-products-db"
database_id = "XXXXXXXXXXXXXXXX"</code></pre>
            <p>Yes, that’s right! You can now configure your <a href="https://developers.cloudflare.com/workers/configuration/bindings/">bound resources</a> via the <a href="https://developers.cloudflare.com/pages/functions/wrangler-configuration/">wrangler.toml file</a>, even for full-stack apps deployed to Pages. We’ll share much more about configuration enhancements to Pages in a <a href="/browser-rendering-api-ga-rolling-out-cloudflare-snippets-swr-and-bringing-workers-for-platforms-to-our-paygo-plans/">dedicated announcement</a>.</p><p>Now let’s create a simple schema.sql file representing our database schema:</p>
            <pre><code>CREATE TABLE products(product_id INTEGER PRIMARY KEY, name TEXT, price INTEGER);
INSERT INTO products (product_id, name, price) VALUES (1, 'Apple', 250), (2, 'Banana', 100), (3, 'Cherry', 375);</code></pre>
            <p>And initialize our database:</p><p><code>$ npx wrangler d1 execute blog-products-db --local --file schema.sql</code></p><p>Notice that we used the <code>–local</code> flag of <a href="https://developers.cloudflare.com/workers/wrangler/commands/#execute"><code>wrangler d1 execute</code></a> to apply the changes to our local D1 database. This is the database that our dev server will connect to.</p><p>Next, if you use TypeScript, let TypeScript know about your database by running:</p><p><code>$ npm run build-cf-types</code></p><p>This command is preconfigured for all full-stack applications created via C3 and executes <a href="https://developers.cloudflare.com/workers/wrangler/commands/#types"><code>wrangler types</code></a> to update the interface of Cloudflare’s environment containing all configured bindings.</p><p>We can now start the dev server provided by your framework via a handy shortcut:</p><p><code>$ npm run dev</code></p><p>This shortcut will start your framework’s dev server, whether it’s powered by <a href="https://nextjs.org/docs/app/api-reference/next-cli#development">next dev</a>, <a href="https://nitro.unjs.io/">nitro</a>, or <a href="https://vitejs.dev/">vite</a>.</p><p>Now to access our database and list the products, we can now use a framework specific approach. For example, in a Next.js application that uses the App router, we could update <code>app/api/hello/route.ts</code> with the following:</p>
            <pre><code>const db = getRequestContext().env.DB;
 const productsResults = await db.prepare('SELECT * FROM products').all();
 return Response.json(productsResults.results);</code></pre>
            <p>Or in a Nuxt application, we can create a <code>server/api/hello.ts</code> file and populate it with:</p>
            <pre><code>export default defineEventHandler(async ({ context }) =&gt; {
   const db = context.cloudflare.env.DB;
   const productsResults = await db.prepare('SELECT * FROM products').all();
   return productsResults.results;
 });</code></pre>
            <p>Assuming that the framework dev server is running on port 3000, you can test the new API route in either framework by navigating to <a href="http://localhost:3000/api/hello">http://localhost:3000/api/hello</a>. For simplicity, we picked API routes in these examples, but the same applies to any UI-generating routes as well.</p><p>Each web framework has its own way to define routes and pass contextual information about the request throughout the application, so how you access your databases, object stores, and other resources will depend on your framework. You can read our updated full-stack framework guides to learn more:</p><ul><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-an-astro-site/">Astro guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">Next.js guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nuxt-site/">Nuxt guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-qwik-site/">Qwik guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-remix-site/">Remix guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-solid-site/">SolidStart guide</a></p></li><li><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site/">SvelteKit guide</a></p></li></ul><p>Now that you know how to access Cloudflare’s resources in the framework of your choice, everything else you know about your framework remains the same. You can now develop your application locally, using the development server optimized for your framework, which often includes support for hot module replacement (HMR), custom dev tools, enhanced debugging support and more, all while still benefiting from Cloudflare-specific APIs and features. Win-win!</p>
    <div>
      <h3>What has actually changed to enable these development workflows?</h3>
      <a href="#what-has-actually-changed-to-enable-these-development-workflows">
        
      </a>
    </div>
    <p>To decrease the development latency and preserve the custom framework-specific experiences, we needed to enable web frameworks and their dev servers to integrate with wrangler and miniflare in a seamless, almost invisible way.</p><p><a href="https://miniflare.dev/">Miniflare</a> is a key component in this puzzle. It is our local simulator for Cloudflare-specific resources, which is powered by <a href="https://github.com/cloudflare/workerd">workerd</a>, our JavaScript (JS) runtime. By relying on workerd, we ensure that Cloudflare’s JavaScript APIs run locally in a way that faithfully simulates our production environment. The trouble is that framework dev servers already rely on Node.js to run the application, so bringing another JS runtime into the mix breaks many assumptions in how these dev servers have been architected.</p><p>Our team however came up with an interesting approach to bridging the gap between these two JS runtimes. We call it the <a href="https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy">getPlatformProxy()</a> API, which is now part of wrangler and is super-powered by <a href="https://github.com/cloudflare/miniflare/pull/639">miniflare’s magic proxy</a>. This API exposes a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">JS proxy object</a> that behaves just like the usual <a href="https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#parameters">Workers env object</a> containing all bound resources. The proxy object enables code from Node.js to transparently invoke JavaScript code running in workerd, as well access Cloudflare-specific runtime APIs.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MPXvdyK3eYsY3YKnOC8co/480cdd00d7a921ecb65eb738caf17ff2/pasted-image-0--6-.png" />
            
            </figure><p>With this bridge between the Node.js and workerd runtimes, your application can now access Cloudflare simulators for D1, R2, KV and other storage solutions directly while running in a dev server powered by Node.js. Or you could even write an Node.js script to do the same:</p>
            <pre><code> import {getPlatformProxy} from 'wrangler';


 const {env} = getPlatformProxy();
 console.dir(env);
 const db = env.DB;


 // Now let’s execute a DB query that runs in a local D1 db
 // powered by miniflare/workerd and access the result from Node.js
 const productsResults = await db.prepare('SELECT * FROM products').all();
 console.log(productsResults.results);</code></pre>
            <p>With the <code>getPlatformProxy()</code> API available, the remaining work was all about updating all framework adapters, plugins, and in some cases frameworks themselves to make use of this API. We are grateful for the support we received from framework teams on this journey, especially <a href="https://github.com/alexanderniebuhr">Alex</a> from Astro, <a href="https://github.com/pi0">pi0</a> from Nuxt, <a href="https://github.com/pcattori">Pedro</a> from Remix, <a href="https://github.com/ryansolid">Ryan</a> from Solid, <a href="https://github.com/benmccann">Ben</a> and <a href="https://github.com/Rich-Harris">Rich</a> from Svelte, and our collaborator on the <a href="https://github.com/cloudflare/next-on-pages">next-on-pages</a> project, <a href="https://github.com/james-elicx">James Anderson</a>.</p>
    <div>
      <h3>Future improvements to development workflows with Vite</h3>
      <a href="#future-improvements-to-development-workflows-with-vite">
        
      </a>
    </div>
    <p>While the <a href="https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy"><code>getPlatformProxy()</code></a> API is a good solution for many scenarios, we can do better. If we could run the entire application in our JS runtime rather than Node.js, we could even more faithfully simulate the production environment and reduce developer friction and production surprises.</p><p>In the ideal world, we’d like you to develop against the same runtime that you deploy to in production, and this can only be achieved by integrating workerd directly into the dev servers of all frameworks, which is not a small feat considering the number of frameworks out there and the differences between them.</p><p>We however got a bit lucky. As we kicked off this effort, we quickly realized that <a href="https://vitejs.dev/">Vite</a>, a popular dev server used by many full-stack frameworks, was gaining increasingly greater adoption. In fact, Remix switched over to <a href="https://remix.run/blog/remix-vite-stable">Vite just recently</a> and confirmed the popularity of Vite as the common foundation for web development today.</p><p>If Vite had first-class support for running a full-stack application in an alternative JavaScript runtime, we could enable anyone using Vite to develop their applications locally with complete access to the Cloudflare developer platform. No more framework specific custom integrations and workarounds — all the features of a full-stack framework, Vite, and Cloudflare accessible to all developers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3hj4Tb9Ex2NnwrnqZ5z6M2/e049e4300b188381259f60bc69ad054c/pasted-image-0--7-.png" />
            
            </figure><p>Sounds too good to be true? Maybe. We are very stoked to be working with the Vite team on the <a href="https://github.com/vitejs/vite/pull/16089">Vite environments</a> proposal, which could enable just that. This proposal is still evolving, so stay tuned for updates.</p>
    <div>
      <h3>What will you build today?</h3>
      <a href="#what-will-you-build-today">
        
      </a>
    </div>
    <p>We aim to make Cloudflare the best development platform for web developers. Making it quick and easy to develop your application with frameworks and tools you are already familiar with is a big part of our story. Start your journey with us by running a single command:</p><p><code>$ npm create cloudflare@latest</code></p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Full Stack]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Miniflare]]></category>
            <guid isPermaLink="false">14PqvEOUknz9TI2FQGbZT3</guid>
            <dc:creator>Igor Minar</dc:creator>
            <dc:creator>Dario Piotrowicz</dc:creator>
            <dc:creator>James Culveyhouse</dc:creator>
            <dc:creator>Peter Bacon Darwin</dc:creator>
        </item>
        <item>
            <title><![CDATA[Announcing Pages support for monorepos, wrangler.toml, database integrations and more!]]></title>
            <link>https://blog.cloudflare.com/pages-workers-integrations-monorepos-nextjs-wrangler/</link>
            <pubDate>Thu, 04 Apr 2024 13:00:16 GMT</pubDate>
            <description><![CDATA[ Today, we’re launching four improvements to Pages that bring functionality previously restricted to Workers, with the goal of unifying the development experience between the two.  Support for monorepos, wrangler.toml, new additions to Next.js support and database integrations ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Pages <a href="/cloudflare-pages-ga">launched</a> in 2021 with the goal of empowering developers to go seamlessly from idea to production. With <a href="https://developers.cloudflare.com/pages/get-started/git-integration/#configure-your-deployment">built-in CI/CD</a>, <a href="https://developers.cloudflare.com/pages/configuration/preview-deployments/">Preview Deployments</a>, <a href="https://developers.cloudflare.com/pages/configuration/git-integration/">integration with GitHub and GitLab</a>, and support for all the most popular <a href="https://developers.cloudflare.com/pages/framework-guides/">JavaScript frameworks</a>, Pages lets you build and deploy both static and full-stack apps globally to our network in seconds.</p><p>Pages has superpowers like these that Workers does not have, and vice versa. Today you have to choose upfront whether to build a Worker or a Pages project, even though the two products largely overlap. That’s why during 2023’s <a href="/pages-and-workers-are-converging-into-one-experience">Developer Week</a>, we started bringing both products together to give developers the benefit of the best of both worlds. And it’s why we announced that like Workers, Pages projects can now directly access <a href="https://developers.cloudflare.com/workers/configuration/bindings/">bindings</a> to Cloudflare services — using <a href="https://github.com/cloudflare/workerd">workerd</a> under-the-hood — even when using the local development server provided by a full-stack framework like <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-an-astro-site/">Astro,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">Next.js,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nuxt-site/">Nuxt,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-qwik-site/">Qwik,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-remix-site/">Remix,</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-solid-site/">SolidStart, or</a> <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site/">SvelteKit</a>. Today, we’re thrilled to be launching some new improvements to Pages that bring functionality previously restricted to Workers. Welcome to the stage: monorepos, wrangler.toml, new additions to Next.js support, and database integrations!</p>
    <div>
      <h3>Pages now supports monorepos</h3>
      <a href="#pages-now-supports-monorepos">
        
      </a>
    </div>
    <p>Many development teams use monorepos – repositories that contain multiple apps, with each residing in its own subdirectory. This approach is extremely helpful when these apps share code.</p><p>Previously, the Pages CI/CD set-up limited users to one repo per project. To use a monorepo with Pages, you had to <a href="https://developers.cloudflare.com/pages/get-started/direct-upload/">directly upload it</a> on your own, using the Wrangler CLI. If you did this, you couldn’t use Pages’ integration with GitHub or Gitlab, or have Pages CI/CD handle builds and deployments. With Pages support for monorepos, development teams can trigger builds to their various projects with each push.</p><p><b>Manage builds and move fast</b>You can now include and exclude specific paths to watch for in each of your projects to avoid unnecessary builds from commits to your repo.</p><p>Let’s say a monorepo contains 4 subdirectories – a marketing app, an ecommerce app, a design library, and a package. The marketing app depends on the design library, while the ecommerce app depends on the design library and the package.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/435MhqmGH7CJ4dXIvMEbN2/2ec159aecf92ea18f5b686b75024484d/image3-7.png" />
            
            </figure><p>Updates to the design library should rebuild and redeploy both applications, but an update to the marketing app shouldn’t rebuild and deploy the ecommerce app. However, by default, any push you make to my-monorepo triggers a build for both projects regardless of which apps were changed. Using the include/exclude build controls, you can specify paths to build and ignore for your project to help you track dependencies and build more efficiently.</p><p><b>Bring your own tools</b>Already using tools like <a href="https://turbo.build/">Turborepo</a>, <a href="https://nx.dev/">NX</a>, and <a href="https://lerna.js.org/">Lerna</a>? No problem! You can also bring your favorite <a href="https://developers.cloudflare.com/pages/configuration/monorepos/#monorepo-management-tools">monorepo management tooling</a> to Pages to help manage your dependencies quickly and efficiently.</p><p>Whatever your tooling and however you’re set up, check out our <a href="https://developers.cloudflare.com/pages/configuration/monorepos/">documentation</a> to get started with your monorepo right out of the box.</p>
    <div>
      <h3>Configure Pages projects with wrangler.toml</h3>
      <a href="#configure-pages-projects-with-wrangler-toml">
        
      </a>
    </div>
    <p>Today, we’re excited to announce that you can now configure Pages projects using wrangler.toml — the same configuration file format that is already used for configuring Workers.</p><p>Previously, Pages projects had to be configured exclusively in the dashboard. This forced you to context switch from your development environment any time you made a configuration change, like adding an environment variable or <a href="https://developers.cloudflare.com/workers/configuration/bindings/">binding</a>. It also separated configuration from code, making it harder to know things like what bindings are being used in your project. If you were developing as a team, all the users on your team had to have access to your account to make changes – even if they had access to make changes to the source code via your repo.</p><p>With wrangler.toml, you can:</p><ul><li><p><b>Store your configuration file in source control.</b> Keep your configuration in your repo alongside the rest of your code.</p></li><li><p><b>Edit your configuration via your code editor.</b> Remove the need to switch back and forth between interfaces.</p></li><li><p><b>Write configuration that is shared across environments.</b> Define bindings and environment variables for local, preview, and production in one file.</p></li><li><p><b>Ensure better access control.</b> By using a configuration file in your repo, you can control who has access to make changes without giving access to your Cloudflare dashboard.</p></li></ul><p><b>Migrate existing projects</b>If you have an existing Pages project, we’ve added a new Wrangler CLI command that downloads your existing configuration and provides you with a valid <code>wrangler.toml</code> file.</p>
            <pre><code>$ npx wrangler@latest pages download config &lt;PROJECT_NAME&gt;</code></pre>
            <p>Run this command, add the wrangler.toml file that it generates to your project’s root directory, and then when you deploy, your project will be configured based on this configuration file.</p><p>If you are already using wrangler.toml to define your local development configuration, you can continue doing so. By default, your existing wrangler.toml file will continue to only apply to local development. When you run <code>wrangler pages deploy</code>, Wrangler will show you the additional fields that you must add in order for your configuration to apply to production and preview environments. Add these fields to your wrangler.toml, and then when you deploy your changes, the configuration you’ve defined in wrangler.toml will be used by your Pages project.</p><p>Refer to the <a href="https://developers.cloudflare.com/pages/functions/wrangler-configuration/">documentation</a> for more information on exactly what’s supported and how to leverage wrangler.toml in your development workflows.</p>
    <div>
      <h3>Integrate Pages projects with your favorite database</h3>
      <a href="#integrate-pages-projects-with-your-favorite-database">
        
      </a>
    </div>
    <p>You can already connect to <a href="https://developers.cloudflare.com/d1/">D1</a>, Cloudflare’s <a href="https://www.cloudflare.com/developer-platform/products/d1/">serverless SQL database</a>, directly from Pages projects. And you can connect directly to your existing PostgreSQL database using <a href="https://developers.cloudflare.com/hyperdrive/">Hyperdrive</a>. Today, we’re making it even easier for you to connect 3rd party databases to Pages with just a couple of clicks. Pages now integrates directly with <a href="https://developers.cloudflare.com/workers/databases/native-integrations/neon/">Neon</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/planetscale/">PlanetScale</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/supabase/">Supabase</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/turso/">Turso</a>, <a href="https://developers.cloudflare.com/workers/databases/native-integrations/upstash/">Upstash</a>, and <a href="https://developers.cloudflare.com/workers/databases/native-integrations/xata/">Xata</a>!</p><p>Simply navigate to your Pages project’s settings, select your database provider, and we’ll add <a href="https://developers.cloudflare.com/pages/functions/bindings/#environment-variableshttps://developers.cloudflare.com/pages/functions/bindings/#environment-variables">environment variables</a> with credentials needed to connect as well a <a href="https://developers.cloudflare.com/pages/functions/bindings/#secrets">secret</a> with the API key from the provider for you automatically.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2seOXZ1bXjWnBbHTV7zs4U/6e180084ddfcbcc3a661afdacb8b1dc9/image1-4.png" />
            
            </figure><p>Not ready to ship to production yet? You can deploy your changes to Pages’ preview environment alongside your staging database and test your deployment with its unique preview URL.</p><p><b>What’s coming up for integrations?</b>We’re just getting started with database integrations, with many more providers to come. In the future, we’re also looking to expand our integrations platform to include seamless set up when building other components of your app – think authentication and observability!</p><p>Want to bring your favorite tools to Cloudflare but don’t see the integration option? Want to build out your own integration?</p><p>Not only are we looking for <a href="https://docs.google.com/forms/d/e/1FAIpQLScUzm1bpWzR0SlJLGI80HchcAz9emPWG2lIXO107KNZTcfo-w/viewform">user input on new integrations</a> to add, but we’re also opening up the integrations platform to builders who want to submit their own products! We’ll be releasing step-by-step documentation and tooling to easily build and publish your own integration. If you’re interested in submitting your own integration, please fill out our <a href="https://docs.google.com/forms/d/e/1FAIpQLScUzm1bpWzR0SlJLGI80HchcAz9emPWG2lIXO107KNZTcfo-w/viewform">integration intake form</a> and we’ll be in touch!</p>
    <div>
      <h3>Improved Next.js Support for Pages</h3>
      <a href="#improved-next-js-support-for-pages">
        
      </a>
    </div>
    <p>With <a href="https://github.com/cloudflare/next-on-pages/releases">30 minor and patch releases</a> since the 1.0 launch of <a href="https://github.com/cloudflare/next-on-pages">next-on-pages</a> during Dev Week 2023, our <a href="https://nextjs.org/">Next.js</a> integration has been continuously maturing and keeping up with the evolution of Next.js. In addition to performance improvements, and compatibility and bug fixes, we released three significant improvements.</p><p>First, the <a href="https://eslint.org/">ESLint</a> plugin <a href="https://www.npmjs.com/package/eslint-plugin-next-on-pages">eslint-plugin-next-on-pages</a> is a great way to catch and fix compatibility issues as you are writing your code before you build and deploy applications. The plugin contains <a href="https://github.com/cloudflare/next-on-pages/tree/main/packages/eslint-plugin-next-on-pages/docs/rules">several rules</a> for the most common coding mistakes we see developers make, with more being added as we identify problematic scenarios.</p><p>Another noteworthy change is the addition of <a href="https://github.com/cloudflare/next-on-pages/blob/3846730c4a0d12/packages/next-on-pages/README.md#cloudflare-platform-integration">getRequestContext()</a> APIs, which provides you with access to Cloudflare-specific resources and metadata about the request currently being processed by your application, allowing for example you to take client’s location or browser preferences into account when generating a response.</p><p>Last but not least, we have completely <a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">overhauled the local development workflow for Next.js</a> as well as other full-stack frameworks. Thanks to the new <a href="https://github.com/cloudflare/next-on-pages/tree/main/internal-packages/next-dev">setupDevPlatform()</a> API, you can now use the default development server <code>next dev</code>, with support for instant edit &amp; refresh experience, while also using D1, <a href="https://www.cloudflare.com/developer-platform/r2/">R2</a>, KV and other resources provided by the Cloudflare development platform. Want to take it for a quick spin? Use <a href="https://developers.cloudflare.com/pages/get-started/c3/">C3</a> to scaffold a new Next.js application with just one command.</p><p>To learn more about our Next.js integration, check out our <a href="https://developers.cloudflare.com/pages/framework-guides/nextjs/deploy-a-nextjs-site/">Next.js framework guide</a>.</p>
    <div>
      <h3>What’s next for the convergence of Workers and Pages?</h3>
      <a href="#whats-next-for-the-convergence-of-workers-and-pages">
        
      </a>
    </div>
    <p>While today’s launch represents just a few of the many upcoming additions to converge Pages and Workers, we also wanted to share a few milestones that are on the horizon, planned later in 2024</p><p><b>Pages features coming soon to Workers</b></p><ul><li><p><b>Workers CI/CD.</b> Later this year, we plan to bring the <a href="https://www.cloudflare.com/learning/serverless/glossary/what-is-ci-cd/">CI/CD system</a> from Cloudflare Pages to Cloudflare Workers. Connect your repositories to Cloudflare and trigger builds for your Workers with every commit.</p></li><li><p><b>Serve static assets from Workers.</b> You will be able to deploy and serve static assets as part of Workers – just like you can with Pages today – and build Workers using full-stack frameworks! This will also extend to Workers for Platforms, allowing you to build platforms that let your customers deploy complete, full-stack applications that serve both dynamic and static assets.</p></li><li><p><b>Workers</b> <a href="https://developers.cloudflare.com/pages/configuration/preview-deployments"><b>preview URLs</b></a><b>.</b> Preview versions of your Workers with every change and share a unique URL with your team for testing.</p></li></ul><p><b>Workers features coming soon to Pages</b></p><ul><li><p><b>Add</b> <a href="https://developers.cloudflare.com/workers/observability/logging/tail-workers/"><b>Tail Workers</b></a> <b>to Pages projects.</b> Get observability into your Pages Functions by capturing <code>console.log()</code> messages, unhandled exceptions, and request metadata, and then forward the information to external destinations.</p></li><li><p><a href="https://developers.cloudflare.com/workers/observability/logging/logpush/"><b>Workers Trace Events Logpush</b></a><b>.</b> Push your Pages Functions logs to supported destinations like <a href="https://developers.cloudflare.com/r2/">R2</a>, Datadog, or any HTTP destination for long term storage, auditing, and compliance.</p></li><li><p><a href="https://developers.cloudflare.com/workers/configuration/versions-and-deployments/gradual-deployments/"><b>Gradual Deployments</b></a><b>.</b> Gradually deploy new versions of your Pages Function to reduce risk when making changes to critical applications.</p></li></ul><p>You might also notice that the Pages and Workers interfaces in the Cloudflare Dash will begin to look more similar through the rest of this year. These changes aren’t just superficial, or us porting over functionality from one product to another. Under-the-hood, we are unifying the way that Workers and Pages projects are composed and then deployed to our network, ensuring that as we add new products and features, they can work with both Pages and Workers on day one.</p><p>In the meantime, bring your monorepo, a wrangler.toml, and your favorite databases to Pages and let’s rock! Be sure to show off what you’ve built in the <a href="https://discord.cloudflare.com/">Cloudflare Developer Discord</a> or by giving us a shout at <a href="https://twitter.com/CloudflareDev">@CloudflareDev</a>.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <guid isPermaLink="false">4P2K139AXugqOLE4sR5wIu</guid>
            <dc:creator>Nevi Shah</dc:creator>
            <dc:creator>Adam Murray</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
        </item>
        <item>
            <title><![CDATA[Making Cloudflare the best place for your web applications]]></title>
            <link>https://blog.cloudflare.com/making-cloudflare-for-web/</link>
            <pubDate>Wed, 17 May 2023 13:05:00 GMT</pubDate>
            <description><![CDATA[ Angular, Astro, Next, Nuxt, Qwik, Remix, Solid, Svelte, Vue on Cloudflare? Deployed globally, even “beyond the edge”, with a single command? And all for $0 or a fraction of the usual cost? Try: npm create cloudflare ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/48P7Dxc74iSHHOSu9OT0Dd/6838b800ce6874801e5d9c0f110ea77d/image1-38.png" />
            
            </figure><p>Hey web developers! We are about to shake things up a bit here at Cloudflare and wanted to give you a heads-up, so that you know what we are doing and where we are going. You might know Cloudflare as one of the best places to come to when you need to protect, speed up, or scale your web application, but increasingly Cloudflare is also becoming the best place to <i>deploy and run</i> your application!</p><p><b>Why deploy your application to Cloudflare?</b> Two simple reasons. First, it removes lots of hassle of managing many separate systems and allows you to develop, deploy, monitor, and tune your application all in one place. Second, by deploying to Cloudflare directly, there is so much more we can do to optimize your application and get it to the hands, ears, or eyes of your users more quickly and smoothly.</p><p><b>So what’s changing?</b> Quite a bit, actually. I’m not going to bore you with rehashing all the details as my most-awesome colleagues have written separate blog posts with all the details, but here is a high level rundown.</p>
    <div>
      <h3>Cloudflare Workers + Pages = awesome development platform</h3>
      <a href="#cloudflare-workers-pages-awesome-development-platform">
        
      </a>
    </div>
    <p>Cloudflare Pages and Workers are merging into a single unified development and <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">application hosting platform</a> that offers:</p><ul><li><p>Super low latency globally: your static assets and compute are less than <a href="https://www.cloudflare.com/network/">50ms away from 95% of the world’s Internet-connected population</a>.</p></li><li><p>Free egress including free static asset hosting.</p></li><li><p>Standards-based JavaScript and WASM runtime that already serves over 10 million requests per second at peak globally.</p></li><li><p>Access to powerful features like R2 (<a href="https://www.cloudflare.com/learning/cloud/what-is-object-storage/">object storage</a> with an <a href="https://www.cloudflare.com/developer-platform/solutions/s3-compatible-object-storage/">S3-compatible</a> API), low-latency globally replicated <a href="https://www.cloudflare.com/products/workers-kv/">KV storage</a>, <a href="https://developers.cloudflare.com/queues/">Queues</a>, <a href="https://developers.cloudflare.com/d1/">D1 database</a>, and many more.</p></li><li><p>Support for GitOps and <a href="https://www.cloudflare.com/learning/serverless/glossary/what-is-ci-cd/">CI/CD workflows</a> and preview environments to boost development velocity.</p></li><li><p>… and so much more.</p></li></ul><p>While mathematically proven to be wrong, we stubbornly believe that 1+1=3, and in this case this translates to Cloudflare Pages + Workers = way more than the sum of the parts. In fact, it’s an awesome foundation for one of a kind development platform that we are thrilled to be building for you.</p><p>We started this product convergence journey a few quarters ago, and early on agreed upon not leaving any of the existing applications behind. Instead, we’ll be bringing them over to this new world. Today we are ready to start sharing the incremental results, with so much more to come over the upcoming quarters. Want to know more? My colleague Nevi posted lots of spicy details in <a href="/pages-and-workers-are-converging-into-one-experience">her blog post</a>.</p>
    <div>
      <h3>Smart Placement for Workers takes us beyond the edge!</h3>
      <a href="#smart-placement-for-workers-takes-us-beyond-the-edge">
        
      </a>
    </div>
    <p>Smart placement is, to put it simply, revolutionary for Cloudflare. It enables a new compute paradigm on our platform, unmatched by any other application hosting providers today. Do you have a typical full-stack application built with one of the many popular web frameworks? This feature is for you! And it works with both Workers and Pages!</p><p>While previously we always executed all applications at the “edge” of our global network — meaning, as close to the user as possible. With smart placement, we intelligently determine the best location within our network where the compute (your application) should run. We do this by observing your application’s behavior and what other network resources or endpoints the application interacts with. We then transparently spawn your application at an optimal location, usually close to where your data is stored, and route the incoming requests via our network to this location.</p><p>Smart placement enables applications to run near to the data these applications need to get stuff done. This is especially powerful for applications that interact with databases, <a href="https://www.cloudflare.com/learning/cloud/what-is-object-storage/">object stores</a>, or other backend endpoints, especially if these are centralized and not globally distributed.</p><p>Your user or clients requests still enter our lightning fast network in one of our 285+ datacenters in the world, close to their current location, but instead of spawning the application right there, we route the request to the most optimal datacenter, the one that is near the data or backend system the application talks to.</p><p>This doesn’t mean that compute at the edge is not cool anymore! It is! There are still many use-cases where running your application at the edge makes sense, and smart placement will determine this scenario and keep the application at the edge if that’s the right place for it to be. A/B testing, localization, asset serving, and others are use-cases that should almost always happen at the edge.</p><p>Sounds interesting? Check out this <a href="https://smart-placement-demo.pages.dev/">visual demo</a> and read up on <a href="/announcing-workers-smart-placement/">Smart Placement in a blog post from my colleague Tanushree</a> to get started.</p>
    <div>
      <h3>Develop locally or in the browser!</h3>
      <a href="#develop-locally-or-in-the-browser">
        
      </a>
    </div>
    <p>We continue to deliver on our goal to build the best development environment integrated directly into our lightning fast and globally distributed application platform. We’re launching <a href="https://developers.cloudflare.com/workers/get-started/guide/#1-start-a-new-project-with-wrangler-the-workers-cli">Wrangler</a> v3, with complete support for local-by-default development workflow. Powered by the open-source Cloudflare Workers JavaScript runtime — <a href="https://github.com/cloudflare/workerd#readme">workerd</a>, this change reduces development server startup time by 10x and script reload times by 60x — boosting your productivity and keeping you in the flow longer.</p><p>In the dashboard, we're introducing an upgraded and far more powerful online editor powered by <a href="https://code.visualstudio.com/">VSCode</a> – you can now finally edit multiple JavaScript modules in your browser, get an accurate edge preview of your code, friendly error pages, and type checking!</p><p>Finally, in both our dashboard editor and Wrangler, we've updated our workerd-customized <a href="https://developer.chrome.com/docs/devtools/">Chrome DevTools</a> to the latest version, providing even greater debugging and profiling capabilities, wherever you choose to work.</p><p>This is just the first wave of improvements to our development tooling space, you’ll see us iterating in this space over the next few quarters, but in the meantime, check out in-depth posts from Adam, Brendan, and Samuel with <a href="/wrangler3">all the Wrangler v3 details</a> and <a href="/improved-quick-edit">VSCode and dash editor improvements</a>.</p>
    <div>
      <h3>Increased memory, CPU, and application size limits and simplified pricing!</h3>
      <a href="#increased-memory-cpu-and-application-size-limits-and-simplified-pricing">
        
      </a>
    </div>
    <p>In the age of AI, WASM, and powerful full-stack applications, we’ve noticed that developers are hitting our current resource limits with increased frequency. We want to be a place where these applications thrive and developers are empowered to build bigger and more sophisticated applications. Therefore, within the next week we’ll be increasing application size limits (JavaScript/WASM bundle size) to 10MB (after gzip) and startup latency limit (script compile time) is being increased from 200ms to 400ms.</p><p>To further empower developers, we’re thinking about how to unify and simplify our billing model to make our pricing more straightforward, and increase limits such as memory limits by introducing tiers. Stay tuned for more information on these!</p><p>With these changes developers can build cooler apps and operate them for less! Cool, right?!?</p>
    <div>
      <h3>Pages CI now with a modern build image!</h3>
      <a href="#pages-ci-now-with-a-modern-build-image">
        
      </a>
    </div>
    <p>The wait is finally over! Pages now use a modern build image to power the CI and integrated build system. With this improvement you can finally use recent versions of Node.js, pnpm, and many other tools used by developers today.</p><p>While delivering this improvement, we made it much easier for us to keep things up to date in the future, but also unlocked new features like build caching!</p><p>The updates are available to all new projects by default, while existing projects can opt in to newer defaults. Sounds like your cup of coffee? Read on in <a href="/moderizing-cloudflare-pages-builds-toolbox">this blog post by Greg</a>.</p>
    <div>
      <h3>Enough already, let’s get started! …with your framework of choice and C3!</h3>
      <a href="#enough-already-lets-get-started-with-your-framework-of-choice-and-c3">
        
      </a>
    </div>
    <p>In addition to being a CDN, and place to deploy your Worker applications, Cloudflare is now also becoming the best place to run your full-stack web applications. This includes all full-stack web frameworks like Angular, Astro, Next, Nuxt, Qwik, Remix, Solid, Svelte, Vue, and others.</p><p>Our overall mission is to help build a better Internet, and my team’s contribution to this mission is to enable developers, but really just about anyone, to go from an idea to a deployed application in no time.</p><p>To enable developers to turn their ideas into deployed applications quickly and without any hassle we’ve built two things.</p><p>First, we partnered with many web framework authors to build new or improve existing adapters for all the popular JavaScript web frameworks. These adapters ensure that your application runs on our platform in the most efficient way, while having access to all the capabilities and features of our platform.</p><p>These adapters include the highly <a href="https://github.com/cloudflare/next-on-pages/">requested Next.js adapter</a>, that we’ve just overhauled to be production ready and are launching 1.0.0 today! In partnership with the respective teams, we’ve built brand-new adapters for <a href="https://github.com/cloudflare/workers-sdk/tree/main/packages/create-cloudflare/src/frameworks/angular">Angular</a>, and <a href="https://github.com/dario-piotrowicz/qwik/tree/main/starters/adaptors/cloudflare-pages">Qwik</a>, while improving Astro, Nuxt, Solid, and a few others.</p><p>Second, we developed a brand new sassy CLI we call C3 — short for create-cloudflare CLI, a sibling to our existing Wrangler CLI. If you are a developer who lives your life in terminal or local editors like VSCode, then this CLI is your single entry-point to the Cloudflare universe.</p><p>Run the C3 command, and we’ll get you started. You pick your framework of choice, we hand the control over to the CLI of the chosen framework as we don’t want to stand in between you and the hard-working framework authors that craft the experience for their framework. A minute or so later once all npm dependencies are installed, you get a URL from us with your application deployed. That’s it. From an idea to a URL that you can share with friends almost instantly! Boom.</p><div></div>
<p></p>
    <div>
      <h3>The best place for your web applications</h3>
      <a href="#the-best-place-for-your-web-applications">
        
      </a>
    </div>
    <p>So to recap, our first class support for full-stack web frameworks, combined with the low latency and cost-effectiveness of our platform, as well as smart placement that allows the backend of the full-stack web application to run in the optimal location automagically, and all the remaining significant improvements in our developer tooling, makes Cloudflare THE best place to build and host web applications. This is our contribution to our mission to build a better Internet and push the Web forward.</p><p>We aspire to be the place people turn to when they want to get business done, or when they just want to be creative, explore ideas and have fun. It’s a long journey, and we’ve got a lot of interesting challenges ahead of us. <a href="https://forms.gle/X7P6BWs529eJRs6LA">Your input will be critical</a> in guiding us. We are all thrilled to have the opportunity to be part of it and give it our best shot. You can join this journey too, and get started today:</p>
            <pre><code>npm create cloudflare my-first-app</code></pre>
            
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">2StHmpNu5XVZ3I0fn5ji54</guid>
            <dc:creator>Igor Minar</dc:creator>
        </item>
        <item>
            <title><![CDATA[Server-side render full stack applications with Pages Functions]]></title>
            <link>https://blog.cloudflare.com/pages-full-stack-frameworks/</link>
            <pubDate>Thu, 17 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Page Functions are now out of beta, bringing the ability to add dynamic server-side rendering to your applications. Pages makes it easy to deploy applications built using all the major frameworks. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6oB484c3bFLWkeU1gCwmKY/4b1fc5b9e22114528486a7d8962787dc/image1-54.png" />
            
            </figure><p>Pages Functions are now out of beta and <a href="/pages-function-goes-ga">generally available</a>, bringing dynamic computation within 50ms of 95% of users globally. Built on top of Cloudflare Workers, Pages projects are easy to deploy and instantly benefit from this low latency, with over 275 data centers across the globe.</p><p>With Page Functions comes the ability to add dynamic server-side rendering to your applications. Pages makes it easy to deploy applications built using all the major meta-frameworks such as Astro, Next.js, Qwik, Remix, Solid, and Svelte. There is no better time to start deploying your server-side rendered full-stack applications to Cloudflare Pages.</p>
    <div>
      <h2>Go server-side with Pages Functions</h2>
      <a href="#go-server-side-with-pages-functions">
        
      </a>
    </div>
    <p>When Pages <a href="/cloudflare-pages/">launched in December 2020</a>, it was focused on being a <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">high-performance host for static assets</a>. Pages was a perfect choice for anyone building websites which could be generated ahead of time with static site generation. <a href="https://jamstack.org/">Jamstack</a> was all the rage, and Cloudflare's network was an excellent choice for its ability to serve static files to visitors from around the globe.</p><p>Once deployed the files would be effortlessly hosted and served at incredible speeds across the world to your users. These statically generated applications can run client-side code in the browser to customize the appearance and behavior of the page, but this approach often struggles with slow <a href="https://web.dev/tti/">time-to-interactive (TTI)</a>, which results in a poor user experience, and SEO rankings.</p><p>Once loaded, client-side rendered applications are great at building highly interactive applications, but in order for such applications to load and become interactive, they usually need to make several network requests to fetch all the code and data it needs to create the UI. If your client devices have a slow or unreliable network connection, each request will become a hurdle that decreases the quality of the user experience.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5LNHd7T6v6mQBPseRROouU/9853fb92ac96b602e0e8a7d3c1629132/image4-21.png" />
            
            </figure><p>Slow connected device making lots of requests</p><p>If you want users to start interacting with your web applications faster, you must make data requests when rendering the HTML. While static generation can avoid these runtime requests by making them at build time, it is not able to provide dynamic customized content. To give users both a customized and fast experience you can server-side render the HTML.</p><p>By using server-side rendering, you can optimize access to resources making use of Cloudflare’s high-bandwidth connectivity and the ability to cache data nearby, minimizing the time spent on the device waiting for data.</p><p>Furthermore, by running the server-side rendering in a Pages Function you get the benefit that both the client (browser) and server (Cloudflare Worker) are both executing similar JavaScript runtimes. This means that you can write isomorphic code that works on both the frontend and backend, avoiding duplication of business and data access logic. Many of the modern full-stack frameworks even provide for code to begin execution on the server and then continue running on the client.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7herLN9ZtWmpEyn0XDupJr/2ca92c7f9b03fd1aec22fb3cff42b3c6/image2-38.png" />
            
            </figure><p>Fast connected Worker making lots of requests</p>
    <div>
      <h2>Use a full-stack framework</h2>
      <a href="#use-a-full-stack-framework">
        
      </a>
    </div>
    <p>Writing your own library to do server-side rendering is no simple task. But luckily many frontend frameworks support server-side rendering, and Cloudflare Pages offers the perfect deployment platform for them. Each framework has its own take on server-side rendering, but most can be integrated effortlessly with Pages Functions. In fact, many frameworks come with starter kits and libraries that make deploying to Pages trivial.</p><p>We have previously blogged about deploying <a href="/cloudflare-pages-goes-full-stack/#what-else-can-you-do">SvelteKit</a>, <a href="/remix-on-cloudflare-pages/">Remix</a> and <a href="/next-on-pages/">Next.js</a> to Cloudflare Pages, but there are many more <a href="https://developers.cloudflare.com/pages/framework-guides/">integrations already available</a>. Let’s take a look at a few of the other popular ones:</p>
    <div>
      <h3>QwikCity</h3>
      <a href="#qwikcity">
        
      </a>
    </div>
    <p>The full-stack framework that uses the Qwik frontend framework is called QwikCity. You can read the full quick-start documentation for running Qwik on Pages <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-qwik-site/">here</a>.</p><p>Create a new project by running the following command in your terminal:</p>
            <pre><code>npm create qwik@latest</code></pre>
            <p>You will be prompted to select a name - choose qwik-app - and a starter project - choose “Basic App (QwikCity)”. Now add the Cloudflare Pages adaptor by running the following in your terminal:</p>
            <pre><code>cd qwik-app
npm run qwik add cloudflare-pages</code></pre>
            <p>By installing the <code>cloudflare-pages</code> adapter, your project will have a Cloudflare Pages <code>functions/[[path]].ts</code> file. The <code>[[path]]</code> filename indicates that this file will handle requests to all incoming URLs, rendering the response in Pages Functions. Now, build and test the application using the <code>wrangler pages dev</code> tool:</p>
            <pre><code>npm run build
npx wrangler pages dev ./dist</code></pre>
            <p>The client and server-side code will be compiled and then Wrangler will start up a dev session. Press <code>b</code> to open a browser and see the server-side rendered site.</p>
    <div>
      <h3>Astro</h3>
      <a href="#astro">
        
      </a>
    </div>
    <p>Astro is a full-stack framework that can run a range of different frontend frameworks. It added support for server-side rendering <a href="https://astro.build/blog/experimental-server-side-rendering/">earlier this year</a>. You can read the full quick-start documentation for running Astro on Pages <a href="https://docs.astro.build/en/guides/deploy/cloudflare/#how-to-deploy-an-ssr-site">here</a>.</p><p>Create a new project by running the following command in your terminal:</p>
            <pre><code>npm create astro@latest</code></pre>
            <p>You will be prompted to select a path to the project, a starter template, and additional setup configuration - accept the defaults. Now add the Cloudflare Pages adaptor by running the following in your terminal:</p>
            <pre><code>cd &lt;path/to/project&gt;
npx astro add cloudflare</code></pre>
            <p>You will be prompted whether you wish to install - select continue when asked. This will update the astro.build/config file with the plugin. Update the configuration to set the cloudflare plugin to <code>directory</code> mode:</p>
            <pre><code>export default defineConfig({
  adapter: cloudflare({ mode: "directory" }),
});</code></pre>
            <p>By installing this adaptor in <code>directory</code> mode, Astro will compile the server-side part of the application into a Pages Function at <code>functions/[[path]].js</code>. Now build and test the application using the <code>wrangler pages dev</code> tool:</p>
            <pre><code>npm run build
npx wrangler pages dev ./dist</code></pre>
            <p>The client and server-side code will be compiled and then Wrangler will start up a dev session. Press <code>b</code> to open a browser and see the server-side rendered site. <a href="https://docs.astro.build/en/guides/integrations-guide/cloudflare/">Check out Astro’s docs</a> to read more about configuring your Astro project when deploying it to Cloudflare Pages.</p>
    <div>
      <h3>SolidStart</h3>
      <a href="#solidstart">
        
      </a>
    </div>
    <p>The full-stack framework that uses the SolidJS frontend framework is called SolidStart. Support for running SolidStart on Cloudflare Pages is provided by the <a href="https://github.com/solidjs/solid-start/tree/main/packages/start-cloudflare-pages">start-cloudflare-pages</a> Vite adapter.</p><p>Create a new SolidStart project by running the following command in your terminal:</p>
            <pre><code>mkdir my-app
cd my-app
npm init solid</code></pre>
            <p>You will be prompted to choose a template - choose “todomvc”. You are then prompted whether to add Server Side Rendering and TypeScript - choose “yes” for both. Now install the <code>solid-start-cloudflare-pages</code> adaptor.</p>
            <pre><code>npm install --save-dev solid-start-cloudflare-pages</code></pre>
            <p>Update the vite.config.ts file to use this adaptor.</p>
            <pre><code>import solid from "solid-start/vite";
import { defineConfig } from "vite";
import cloudflare from "solid-start-cloudflare-pages";

export default defineConfig({
  plugins: [solid({ adapter: cloudflare({}) })],
});</code></pre>
            <p>By including this adapter, Solid will compile the server-side part of the application into a Pages Function at <code>functions/[[path]].js</code> and the client-side part into <code>dist/public</code>. Now build and test the application using the <code>wrangler pages dev</code> tool:</p>
            <pre><code>npm run build
npx wrangler pages dev ./dist/public</code></pre>
            <p>The client and server-side code will be compiled and then Wrangler will start up a dev session. Press <code>b</code> to open a browser and see the server-side rendered site.</p>
    <div>
      <h3>Nuxt.js</h3>
      <a href="#nuxt-js">
        
      </a>
    </div>
    <p>The full-stack framework that uses the Vue.js frontend framework is called Nuxt.js. Nuxt.js supports deploying to Cloudflare Pages natively via a Nitro preset.</p><p>Create a new Nuxt project using <code>nuxi</code> (a Nuxt.js specific version of Nitro), giving it the title <code>nuxt-app</code> in your terminal:</p>
            <pre><code>npx nuxi init nuxt-app
cd nuxt-app
npm install</code></pre>
            <p>By specifying an environment variable Nuxt.js can generate output for Cloudflare Pages Functions. Build and test the application using nuxi and wrangler:</p>
            <pre><code>NITRO_PRESET=cloudflare-pages npx nuxi build
npx wrangler pages dev .output/public</code></pre>
            <p>The client and server-side code will be compiled and then Wrangler will start up a dev session. Press <code>b</code> to open a browser and see the server-side rendered site.</p>
    <div>
      <h2>Get rendering!</h2>
      <a href="#get-rendering">
        
      </a>
    </div>
    <p>Now that Pages Functions are generally available, and the major full-stack frameworks provide straightforward integrations with Pages, there is no better time to add server-side rendering to your application and deploy to Cloudflare Pages.</p><p>Check out the Cloudflare Pages documentation for more help in <a href="https://pages.cloudflare.com/">getting started</a> or chat with us <a href="https://discord.gg/cloudflaredev">on our friendly Discord server</a> about what Pages Functions can do for your project.</p><p>If you are a framework author and would also like to integrate with Pages Functions then get in touch. We would love to help make that happen!</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <guid isPermaLink="false">7sbi49fzybJHkcFdjNStpV</guid>
            <dc:creator>Peter Bacon Darwin</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
        </item>
        <item>
            <title><![CDATA[Incremental adoption of micro-frontends with Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/fragment-piercing/</link>
            <pubDate>Thu, 17 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ With Cloudflare Workers, our fragment-based micro-frontend architecture, and fragment piercing technique, engineering teams can incrementally improve large frontends in a fraction of the time, yielding significant user and developer experience gains. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Q4iw5pvW4frJry6aDHbW1/72ed68595be7d127566b976c0a4114a6/image5-11.png" />
            
            </figure>
    <div>
      <h2>Bring micro-frontend benefits to legacy Web applications</h2>
      <a href="#bring-micro-frontend-benefits-to-legacy-web-applications">
        
      </a>
    </div>
    <p>Recently, we wrote about <a href="/better-micro-frontends/">a new fragment architecture</a> for building Web applications that is fast, cost-effective, and scales to the largest projects, while enabling a fast iteration cycle. The approach uses multiple collaborating Cloudflare Workers to render and stream micro-frontends into an application that is interactive faster than traditional client-side approaches, leading to better user experience and SEO scores.</p><p>This approach is great if you are starting a new project or have the capacity to rewrite your current application from scratch. But in reality most projects are too large to be rebuilt from scratch and can adopt architectural changes only in an incremental way.</p><p>In this post we propose a way to replace only selected parts of a legacy client-side rendered application with server-side rendered fragments. The result is an application where the most important views are interactive sooner, can be developed independently, and receive all the benefits of the micro-frontend approach, while avoiding large rewrites of the legacy codebase. This approach is framework-agnostic; in this post we demonstrate fragments built with React, Qwik, and SolidJS.</p>
    <div>
      <h2>The pain of large frontend applications</h2>
      <a href="#the-pain-of-large-frontend-applications">
        
      </a>
    </div>
    <p>Many large frontend applications developed today fail to deliver good user experience. This is often caused by architectures that require large amounts of JavaScript to be downloaded, parsed and executed before users can interact with the application. Despite efforts to defer non-critical JavaScript code via lazy loading, and the use of server-side rendering, these large applications still take too long to become interactive and respond to the user's inputs.</p><p>Furthermore, large monolithic applications can be complex to build and deploy. Multiple teams may be collaborating on a single codebase and the effort to coordinate testing and deployment of the project makes it hard to develop, deploy and iterate on individual features.</p><p>As outlined in our <a href="/better-micro-frontends/">previous post</a>, micro-frontends powered by <a href="https://workers.cloudflare.com/">Cloudflare Workers</a> can solve these problems but converting an application monolith to a micro-frontend architecture can be difficult and expensive. It can take months, or even years, of engineering time before any benefits are perceived by users or developers.</p><p>What we need is an approach where a project can incrementally adopt micro-frontends into the most impactful parts of the application incrementally, without needing to rewrite the whole application in one go.</p>
    <div>
      <h2>Fragments to the rescue</h2>
      <a href="#fragments-to-the-rescue">
        
      </a>
    </div>
    <p>The goal of a fragment based architecture is to significantly <a href="https://www.cloudflare.com/solutions/ecommerce/optimization/">decrease loading and interaction latency</a> for large web applications (as measured via <a href="https://web.dev/vitals/">Core Web Vitals</a>) by breaking the application into micro-frontends that can be quickly rendered (and cached) in Cloudflare Workers. The challenge is how to integrate a micro-frontend fragment into a legacy client-side rendered application with minimal cost to the original project.</p><p>The technique we propose allows us to convert the most valuable parts of a legacy application’s UI, in isolation from the rest of the application.</p><p>It turns out that, in many applications, the most valuable parts of the UI are often nested within an application “shell” that provides header, footer, and navigational elements. Examples of these include a login form, product details panel in an <a href="https://www.cloudflare.com/ecommerce/">e-commerce application</a>, the inbox in an email client, etc.</p><p>Let’s take a login form as an example. If it takes our application several seconds to display the login form, the users will dread logging in, and we might lose them. We can however convert the login form into a server-side rendered fragment, which is displayed and interactive immediately, while the rest of the legacy application boots up in the background. Since the fragment is interactive early, the user can even submit their credentials before the legacy application has started and rendered the rest of the page.</p><div></div>
<p><small>Animation showing the login form being available before the main application</small></p><p>This approach enables engineering teams to deliver valuable improvements to users in just a fraction of the time and engineering cost compared to traditional approaches, which either sacrifice user experience improvements, or require a lengthy and high-risk rewrite of the entire application. It allows teams with monolithic single-page applications to adopt a micro-frontend architecture incrementally, target the improvements to the most valuable parts of the application, and therefore front-load the return on investment.</p><p>An interesting challenge in extracting parts of the UI into server-side rendered fragments is that, once displayed in the browser, we want the legacy application and the fragments to feel like a single application. The fragments should be neatly embedded within the legacy application shell, keeping the application accessible by correctly forming the DOM hierarchy, but we also want the server-side rendered fragments to be displayed and become interactive as quickly as possible — even before the legacy client-side rendered application shell comes into existence. How can we embed UI fragments into an application shell that doesn’t exist yet? We resolved this problem via a technique we devised, which we call “fragment piercing”.</p>
    <div>
      <h2>Fragment piercing</h2>
      <a href="#fragment-piercing">
        
      </a>
    </div>
    <p>Fragment piercing combines HTML/DOM produced by server-side rendered micro-frontend fragments with HTML/DOM produced by a legacy client-side rendered application.</p><p>The micro-frontend fragments are rendered directly into the top level of the HTML response, and are designed to become immediately interactive. In the background, the legacy application is client-side rendered as a sibling of these fragments. When it is ready, the fragments are “pierced” into the legacy application – the DOM of each fragment is moved to its appropriate place within the DOM of the legacy application – without causing any visual side effects, or loss of client-side state, such as focus, form data, or text selection. Once “pierced”, a fragment can begin to communicate with the legacy application, effectively becoming an integrated part of it.</p><p>Here, you can see a “login” fragment and the empty legacy application “root” element at the top level of the DOM, before piercing.</p>
            <pre><code>&lt;body&gt;
  &lt;div id="root"&gt;&lt;/div&gt;
  &lt;piercing-fragment-host fragment-id="login"&gt;
    &lt;login q:container...&gt;...&lt;/login&gt;
  &lt;/piercing-fragment-host&gt;
&lt;/body&gt;</code></pre>
            <p>And here you can see that the fragment has been pierced into the “login-page” div in the rendered legacy application.</p>
            <pre><code>&lt;body&gt;
  &lt;div id="root"&gt;
    &lt;header&gt;...&lt;/header&gt;
    &lt;main&gt;
      &lt;div class="login-page"&gt;
        &lt;piercing-fragment-outlet fragment-id="login"&gt;
          &lt;piercing-fragment-host fragment-id="login"&gt;
            &lt;login  q:container...&gt;...&lt;/login&gt;
          &lt;/piercing-fragment-host&gt;
        &lt;/piercing-fragment-outlet&gt;
      &lt;/div&gt;
    &lt;/main&gt;
    &lt;footer&gt;...&lt;/footer&gt;
  &lt;/div&gt;
&lt;/body&gt;</code></pre>
            <p>To keep the fragment from moving and causing a visible layout shift during this transition, we apply CSS styles that position the fragment in the same way before and after piercing.</p><p>At any time an application can be displaying any number of pierced fragments, or none at all. This technique is not limited only to the initial load of the legacy application. Fragments can also be added to and removed from an application, at any time. This allows fragments to be rendered in response to user interactions and client-side routing.</p><p>With fragment piercing, you can start to incrementally adopt micro-frontends, one fragment at a time. You decide on the granularity of fragments, and which parts of the application to turn into fragments. The fragments don’t all have to use the same Web framework, which can be useful when switching stacks, or during a post-acquisition integration of multiple applications.</p>
    <div>
      <h2>The “Productivity Suite” demo</h2>
      <a href="#the-productivity-suite-demo">
        
      </a>
    </div>
    <p>As a demonstration of fragment piercing and incremental adoption we have developed a <a href="https://github.com/cloudflare/workers-web-experiments/tree/main/productivity-suite">“productivity suite” demo</a> application that allows users to manage to-do lists, read hacker news, etc. We implemented the shell of this application as a client-side rendered React application — a common tech choice in corporate applications. This is our “legacy application”. There are three routes in the application that have been updated to use micro-frontend fragments:</p><ul><li><p><code>/login</code> - a simple dummy login form with client-side validation, displayed when users are not authenticated (implemented in <a href="https://qwik.builder.io/">Qwik</a>).</p></li><li><p><code>/todos</code> - manages one or more todo lists, implemented as two collaborating fragments:</p><ul><li><p>Todo list selector - a component for selecting/creating/deleting Todo lists (implemented in <a href="https://qwik.builder.io/">Qwik</a>).</p></li><li><p>Todo list editor - a clone of the <a href="https://todomvc.com/">TodoMVC</a> app (implemented in <a href="https://reactjs.org/docs/react-dom-server.html">React</a>).</p></li></ul></li><li><p><code>/news</code> - a clone of the <a href="https://github.com/solidjs/solid-hackernews">HackerNews</a> demo (implemented in <a href="https://www.solidjs.com/">SolidJS</a>).</p></li></ul><p>This demo showcases that different independent technologies can be used for both the legacy application and for each of the fragments.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/38jTYqRteZyGozPUoqXd8D/60b003aa2b53395b4adcb0cf31dcd2fc/image2-41.png" />
            
            </figure><p>A visualization of the fragments that are pierced into the legacy application</p><p>The application is deployed at <a href="https://productivity-suite.web-experiments.workers.dev/">https://productivity-suite.web-experiments.workers.dev/</a>.</p><p>To try it out, you first need to log in – simply use any username you like (no password needed). The user’s data is saved in a cookie, so you can log out and back in using the same username. After you’ve logged in, navigate through the various pages using the navigation bar at the top of the application. In particular, take a look at the “<a href="https://productivity-suite.web-experiments.workers.dev/todos">Todo Lists</a>” and “<a href="https://productivity-suite.web-experiments.workers.dev/news">News</a>” pages to see the piercing in action.</p><p>At any point, try reloading the page to see that fragments are rendered instantly while the legacy application loads slowly in the background. Try interacting with the fragments even before the legacy application has appeared!</p><p>At the very top of the page there are controls to let you see the impact of fragment piercing in action.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/11Y8DDksAEPz1AMQT8jjSG/8c69e3cc1d99b8a67a01410b146f2c02/image1-56.png" />
            
            </figure><ul><li><p>Use the “Legacy app bootstrap delay” slider to set the simulated delay before the legacy application starts.</p></li><li><p>Toggle “Piercing Enabled” to see what the user experience would be if the app did not use fragments.</p></li><li><p>Toggle “Show Seams” to see where each fragment is on the current page.</p></li></ul>
    <div>
      <h2>How it works</h2>
      <a href="#how-it-works">
        
      </a>
    </div>
    <p>The application is composed of a number of building blocks.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/47B8E1C6o3kWhsEzUWYL7J/ca1e6348128985d560bd28f0dc32615f/Frame-653.png" />
            
            </figure><p>An overview of the collaborating Workers and legacy application host</p><p>The <b>Legacy application host</b> in our demo serves the files that define the client-side React application (HTML, JavaScript and stylesheets). Applications built with other tech stacks would work just as well. The <b>Fragment Workers</b> host the micro-frontend fragments, as described in our previous <a href="/better-micro-frontends/">fragment architecture</a> post. And the <b>Gateway Worker</b> handles requests from the browser, selecting, fetching and combining response streams from the legacy application and micro-frontend fragments.</p><p>Once these pieces are all deployed, they work together to handle each request from the browser. Let’s look at what happens when you go to the `/login` route.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2atnhkVHu0tNa1MKGWnOPs/b80838e713fd7b64a177a82b06377a16/image4-22.png" />
            
            </figure><p>The flow of requests when viewing the login page</p><p>The user navigates to the application and the browser makes a request to the Gateway Worker to get the initial HTML. The Gateway Worker identifies that the browser is requesting the login page. It then makes two parallel sub-requests – one to fetch the index.html of the legacy application, and another to request the server-side rendered login fragment. It then combines these two responses into a single response stream containing the HTML that is delivered to the browser.</p><p>The browser displays the HTML response containing the empty root element for the legacy application, and the server-side rendered login fragment, which is immediately interactive for the user.</p><p>The browser then requests the legacy application’s JavaScript. This request is proxied by the Gateway Worker to the Legacy application host. Similarly, any other assets for the legacy application or fragments get routed through the Gateway Worker to the legacy application host or appropriate Fragment Worker.</p><p>Once the legacy application’s JavaScript has been downloaded and executed, rendering the shell of the application in the process, the fragment piercing kicks in, moving the fragment into the appropriate place in the legacy application, while preserving all of its UI state.</p><p>While focussed on the login fragment to explain fragment piercing, the same ideas apply to the other fragments implemented in the <code>/todos</code> and <code>/news</code> routes.</p>
    <div>
      <h2>The piercing library</h2>
      <a href="#the-piercing-library">
        
      </a>
    </div>
    <p>Despite being implemented using different Web frameworks, all the fragments are integrated into the legacy application in the same way using helpers from a “<a href="https://github.com/cloudflare/workers-web-experiments/tree/main/productivity-suite/piercing-library">Piercing Library</a>”. This library is a collection of server-side and client-side utilities that we developed, for the demo, to handle integrating the legacy application with micro-frontend fragments. The main features of the library are the <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/piercing-gateway.ts#L82"><code>PiercingGateway</code></a> class, <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/piercing-fragment-host/piercing-fragment-host.ts#L5">fragment host</a> and <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/piercing-fragment-outlet.ts#L31">fragment outlet</a> custom elements, and the <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/message-bus/message-bus.ts#L18"><code>MessageBus</code></a> class.</p>
    <div>
      <h3>PiercingGateway</h3>
      <a href="#piercinggateway">
        
      </a>
    </div>
    <p>The <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/piercing-gateway.ts#L82"><code>PiercingGateway</code></a> class can be used to instantiate a Gateway Worker that handles all requests for our application’s HTML, JavaScript and other assets. The `PiercingGateway` routes requests through to the appropriate Fragment Workers or to the host of the Legacy Application. It also combines the HTML response streams from these fragments with the response from the legacy application into a single HTML stream that is returned to the browser.</p><p>Implementing a Gateway Worker is straightforward using the Piercing Library. Create a new <code>gateway</code> instance of <code>PiercingGateway</code>, passing it the URL to the legacy application host and a function to determine whether piercing is enabled for the given request. Export the <code>gateway</code> as the default export from the Worker script so that the Workers runtime can wire up its <code>fetch()</code> handler.</p>
            <pre><code>const gateway = new PiercingGateway&lt;Env&gt;({
  // Configure the origin URL for the legacy application.
  getLegacyAppBaseUrl: (env) =&gt; env.APP_BASE_URL,
  shouldPiercingBeEnabled: (request) =&gt; ...,
});
...

export default gateway;</code></pre>
            <p>Fragments can be registered by calling the <code>registerFragment()</code> method so that the <code>gateway</code> can automatically route requests for a fragment’s HTML and assets to its Fragment Worker. For example, registering the login fragment would look like:</p>
            <pre><code>gateway.registerFragment({
  fragmentId: "login",
  prePiercingStyles: "...",
  shouldBeIncluded: async (request) =&gt; !(await isUserAuthenticated(request)),
});</code></pre>
            
    <div>
      <h3>Fragment host and outlet</h3>
      <a href="#fragment-host-and-outlet">
        
      </a>
    </div>
    <p>Routing requests and combining HTML responses in the Gateway Worker is only half of what makes piercing possible. The other half needs to happen in the browser where the fragments need to be pierced into the legacy application using the technique we described earlier.</p><p>The fragment piercing in the browser is facilitated by a pair of <a href="https://html.spec.whatwg.org/multipage/custom-elements.html">custom elements</a>, the fragment host (<a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/piercing-fragment-host/piercing-fragment-host.ts#L5"><code>&lt;piercing-fragment-host&gt;</code></a>) and the fragment outlet (<a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/piercing-fragment-outlet.ts#L31"><code>&lt;piercing-fragment-outlet&gt;</code></a>).</p><p>The Gateway Worker wraps the HTML for each fragment in a fragment host. In the browser, the fragment host manages the life-time of the fragment and is used when moving the fragment’s DOM into position in the legacy application.</p>
            <pre><code>&lt;piercing-fragment-host fragment-id="login"&gt;
  &lt;login q:container...&gt;...&lt;/login&gt;
&lt;/piercing-fragment-host&gt;</code></pre>
            <p>In the legacy application, the developer marks where a fragment should appear when it is pierced by adding a fragment outlet. Our demo application’s Login route looks as follows:</p>
            <pre><code>export function Login() {
  …
  return (
    &lt;div className="login-page" ref={ref}&gt;
      &lt;piercing-fragment-outlet fragment-id="login" /&gt;
    &lt;/div&gt;
  );
}</code></pre>
            <p>When a fragment outlet is added to the DOM, it searches the current document for its associated fragment host. If found, the fragment host and its contents are moved inside the outlet. If the fragment host is not found, the outlet will make a request to the gateway worker to fetch the fragment HTML, which is then streamed directly into the fragment outlet, using the <a href="https://github.com/marko-js/writable-dom">writable-dom library</a> (a small but powerful library developed by the <a href="https://markojs.com/">MarkoJS</a> team).</p><p>This fallback mechanism enables client-side navigation to routes that contain new fragments. This way fragments can be rendered in the browser via both initial (hard) navigation and client-side (soft) navigation.</p>
    <div>
      <h3>Message bus</h3>
      <a href="#message-bus">
        
      </a>
    </div>
    <p>Unless the fragments in our application are completely presentational or self-contained, they also need to communicate with the legacy application and other fragments. The <code>[MessageBus](https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/piercing-library/src/message-bus/message-bus.ts#L18)</code> is a simple asynchronous, isomorphic, and framework-agnostic communication bus that the legacy application and each of the fragments can access.</p><p>In our demo application the login fragment needs to inform the legacy application when the user has authenticated. This <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/app/fragments/login/src/components/LoginForm.tsx#L51-L57">message dispatch</a> is implemented in the Qwik <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/app/fragments/login/src/components/LoginForm.tsx#L38"><code>LoginForm</code></a> component as follows:</p>
            <pre><code>const dispatchLoginEvent = $(() =&gt; {
  getBus(ref.value).dispatch("login", {
    username: state.username,
    password: state.password,
  });
  state.loading = true;
});</code></pre>
            <p>The legacy application can then <a href="https://github.com/cloudflare/workers-web-experiments/blob/df50b60cfff7bc299cf70ecfe8f7826ec9313b84/productivity-suite/app/legacy-app/src/auth.tsx#L24-L34">listen for these messages</a> like this:</p>
            <pre><code>useEffect(() =&gt; {
  return getBus().listen&lt;LoginMessage&gt;("login", async (user) =&gt; {
    setUser(user);
    await addUserDataIfMissing(user.username);
    await saveCurrentUser(user.username);
    getBus().dispatch("authentication", user);
    navigate("/", { replace: true, });
  });
}, []);</code></pre>
            <p>We settled on this message bus implementation because we needed a solution that was framework-agnostic, and worked well on both the server as well as client.</p>
    <div>
      <h2>Give it a go!</h2>
      <a href="#give-it-a-go">
        
      </a>
    </div>
    <p>With fragments, fragment piercing, and Cloudflare Workers, you can improve performance as well as the development cycle of legacy client-side rendered applications. These changes can be adopted incrementally, and you can even do so while implementing fragments with a Web framework for your choice.</p><p>The “Productivity Suite” application demonstrating these capabilities can be found at <a href="https://productivity-suite.web-experiments.workers.dev/">https://productivity-suite.web-experiments.workers.dev/</a>.</p><p>All the code we have shown is open-source and published to Github: <a href="https://github.com/cloudflare/workers-web-experiments/tree/main/productivity-suite">https://github.com/cloudflare/workers-web-experiments/tree/main/productivity-suite</a>.</p><p>Feel free to clone the repository. It is easy to run locally and even deploy your own version (for free) to Cloudflare. We tried to make the code as reusable as possible. Most of the core logic is in the <a href="https://github.com/cloudflare/workers-web-experiments/tree/main/productivity-suite/piercing-library">piercing library</a> that you could try in your own projects. We’d be thrilled to receive feedback, suggestions, or hear about applications you’d like to use it for. Join our <a href="https://github.com/cloudflare/workers-web-experiments/discussions/64">GitHub discussion</a> or also reach us on our <a href="https://discord.com/channels/595317990191398933/1041751020340002907">discord channel</a>.</p><p>We believe that combining Cloudflare Workers with the latest ideas from frameworks will drive the next big steps forward in improved experiences for both users and developers in Web applications. Expect to see more demos, blog posts and collaborations as we continue to push the boundaries of what the Web can offer. And if you’d also like to be directly part of this journey, we are also happy to share that <a href="https://boards.greenhouse.io/cloudflare/jobs/4619341">we are hiring</a>!</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Edge]]></category>
            <category><![CDATA[Micro-frontends]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">4vnFkyih2W2DD0QcaALcdf</guid>
            <dc:creator>Peter Bacon Darwin</dc:creator>
            <dc:creator>Dario Piotrowicz</dc:creator>
            <dc:creator>James Culveyhouse</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Workers and micro-frontends: made for one another]]></title>
            <link>https://blog.cloudflare.com/better-micro-frontends/</link>
            <pubDate>Thu, 20 Oct 2022 13:00:00 GMT</pubDate>
            <description><![CDATA[ In this blog-post we demonstrate how hosting and combining multiple server-side rendered micro-frontends on Cloudflare Workers offer a highly scalable, high performance solution to these problems ]]></description>
            <content:encoded><![CDATA[ <p>To help developers build better web applications we researched and devised a fragments architecture to build <a href="https://martinfowler.com/articles/micro-frontends.html">micro-frontends</a> using <a href="https://workers.cloudflare.com/">Cloudflare Workers</a> that is lightning fast, cost-effective to develop and operate, and scales to the needs of the largest enterprise teams without compromising release velocity or user experience.</p><p>Here we share a technical overview and a proof of concept of this architecture.</p>
    <div>
      <h2>Why micro-frontends?</h2>
      <a href="#why-micro-frontends">
        
      </a>
    </div>
    <p>One of the challenges of modern frontend web development is that applications are getting bigger and more complex. This is especially true for enterprise web applications supporting <a href="https://www.cloudflare.com/ecommerce/">e-commerce</a>, banking, insurance, travel, and other industries, where a unified user interface provides access to a large amount of functionality. In such projects it is common for many teams to collaborate to build a single web application. These monolithic web applications, usually built with JavaScript technologies like React, Angular, or Vue, span thousands, or even millions of lines of code.</p><p>When a monolithic JavaScript architecture is used with applications of this scale, the result is a slow and fragile user experience with low <a href="https://web.dev/measure/">Lighthouse scores</a>. Furthermore, collaborating development teams often struggle to <a href="https://www.youtube.com/watch?v=pU1gXA0rfwc">maintain and evolve</a> their parts of the application, as their <a href="https://igor.dev/posts/fate-sharing-and-micro-frontends/">fates are tied</a> with fates of all the other teams, so the mistakes and tech debt of one team often impacts all.</p><p>Drawing on ideas from <a href="https://en.wikipedia.org/wiki/Microservices">microservices</a>, the frontend community has started to advocate for <a href="https://micro-frontends.org/">micro-frontends</a> to enable teams to develop and deploy their features independently of other teams. Each micro-frontend is a self-contained mini-application, that can be developed and released independently, and is responsible for rendering a “fragment” of the page. The application then combines these fragments together so that from the user's perspective it feels like a single application.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78VTFfttaimJC7Son9VcYZ/652e6f47dd6354864fd99102307659ba/image3.jpg" />
            
            </figure><p>An application consisting of multiple micro-frontends</p><p>Fragments could represent vertical application features, like “account management” or “checkout”, or horizontal features, like “header” or “navigation bar”.</p>
    <div>
      <h3>Client-side micro-frontends</h3>
      <a href="#client-side-micro-frontends">
        
      </a>
    </div>
    <p>A common approach to micro-frontends is to rely upon client-side code to lazy load and stitch fragments together (e.g. via <a href="https://webpack.js.org/concepts/module-federation/">Module Federation</a>). Client-side micro-frontend applications suffer from a number of problems.</p><p>Common code must either be duplicated or published as a shared library. Shared libraries are problematic themselves. It is not possible to <a href="https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking">tree-shake</a> unused library code at build time resulting in more code than necessary being downloaded to the browser and coordinating between teams when shared libraries need to be updated can be complex and awkward.</p><p>Also, the top-level container application must bootstrap before the micro-frontends can even be requested, and they also need to boot before they become interactive. If they are nested, then you may end up getting a <a href="https://javascript.plainenglish.io/react-official-answer-the-right-way-of-requesting-data-in-react18-other-frameworks-also-apply-50d907c1f6c4">waterfall of requests</a> to get micro-frontends leading to further runtime delays.</p><p>These problems can result in a sluggish application startup experience for the user.</p><p>Server-side rendering could be used with client-side micro-frontends to improve how quickly a browser displays the application but implementing this can significantly increase the complexity of development, deployment and operation. Furthermore, most server-side rendering approaches still suffer from a <a href="https://dev.to/this-is-learning/why-efficient-hydration-in-javascript-frameworks-is-so-challenging-1ca3">hydration delay</a> before the user can fully interact with the application.</p><p>Addressing these challenges was the main motivation for exploring an alternative solution, which relies on the distributed, low latency properties provided by Cloudflare Workers.</p>
    <div>
      <h2>Micro-frontends on Cloudflare Workers</h2>
      <a href="#micro-frontends-on-cloudflare-workers">
        
      </a>
    </div>
    <p><a href="https://workers.cloudflare.com/">Cloudflare Workers</a> is a compute platform that offers a highly scalable, low latency JavaScript execution environment that is available in <a href="https://www.cloudflare.com/network/">over 275 locations</a> around the globe. In our exploration we used Cloudflare Workers to host and render micro-frontends from anywhere on our global network.</p>
    <div>
      <h3>Fragments architecture</h3>
      <a href="#fragments-architecture">
        
      </a>
    </div>
    <p>In this architecture the application consists of a tree of “fragments” each deployed to Cloudflare Workers that collaborate to server-side render the overall response. The browser makes a request to a “root fragment”, which will communicate with “child fragments” to generate the final response. Since Cloudflare Workers can communicate with each other <a href="https://developers.cloudflare.com/workers/platform/bindings/about-service-bindings/">with almost no overhead</a>, applications can be server-side rendered quickly by child fragments, all working in parallel to render their own HTML, streaming their results to the parent fragment, which combines them into the final response stream delivered to the browser.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/43AlwyalVCD1CfOm31lNiX/f740b01c554b0f574267cf8c4dfe245c/blog-1447.png" />
            
            </figure><p>A high-level overview of a fragments architecture</p>
    <div>
      <h2>Visit the “Cloud Gallery”</h2>
      <a href="#visit-the-cloud-gallery">
        
      </a>
    </div>
    <p>We have built an example of a “Cloud Gallery” application to show how this can work in practice. It is deployed to Cloudflare Workers at  <a href="https://cloud-gallery.web-experiments.workers.dev/">https://cloud-gallery.web-experiments.workers.dev/</a></p><p>The demo application is a simple filtered gallery of cloud images built using our fragments architecture. Try selecting a tag in the type-ahead to filter the images listed in the gallery. Then change the delay on the stream of cloud images to see how the type-ahead filtering can be interactive before the page finishes loading.</p>
    <div>
      <h3>Multiple Cloudflare Workers</h3>
      <a href="#multiple-cloudflare-workers">
        
      </a>
    </div>
    <p>The application is composed of a tree of six collaborating but independently deployable Cloudflare Workers, each rendering their own fragment of the screen and providing their own client-side logic, and assets such as CSS stylesheets and images.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2xfKbBmdC16pAkNbdCjOz7/0a3e7eebadd5272421fe10dbbb594d76/image6-4.png" />
            
            </figure><p>Architectural overview of the Cloud Gallery app</p><p>The “main” fragment acts as the root of the application. The “header” fragment has a slider to configure an artificial delay to the display of gallery images. The “body” fragment contains the “filter” fragment and “gallery” fragments. Finally, the “footer” fragment just shows some static content.</p><p>The full source code of the demo app is available on <a href="https://github.com/cloudflare/workers-web-experiments/tree/main/cloud-gallery">GitHub</a>.</p>
    <div>
      <h2>Benefits and features</h2>
      <a href="#benefits-and-features">
        
      </a>
    </div>
    <p>This architecture of multiple collaborating server-side rendered fragments, deployed to Cloudflare Workers has some interesting features.</p>
    <div>
      <h3>Encapsulation</h3>
      <a href="#encapsulation">
        
      </a>
    </div>
    <p>Fragments are entirely encapsulated, so they can control what they own and what they make available to other fragments.</p>
    <div>
      <h4><i>Fragments can be developed and deployed independently</i></h4>
      <a href="#fragments-can-be-developed-and-deployed-independently">
        
      </a>
    </div>
    <p>Updating one of the fragments is as simple as redeploying that fragment. The next request to the main application will use the new fragment. Also, fragments can host their own assets (client-side JavaScript, images, etc.), which are streamed through their parent fragment to the browser.</p>
    <div>
      <h4><i>Server-only code is not sent to the browser</i></h4>
      <a href="#server-only-code-is-not-sent-to-the-browser">
        
      </a>
    </div>
    <p>As well as reducing the cost of downloading unnecessary code to the browser, security sensitive code that is only needed for server-side rendering the fragment is never exposed to other fragments and is not downloaded to the browser. Also, features can be safely hidden behind feature flags in a fragment, allowing more flexibility with rolling out new behavior safely.</p>
    <div>
      <h3>Composability</h3>
      <a href="#composability">
        
      </a>
    </div>
    <p>Fragments are fully composable - any fragment can contain other fragments. The resulting tree structure gives you more flexibility in how you architect and deploy your application. This helps larger projects to scale their development and deployment. Also, fine-grain control over how fragments are composed, could allow fragments that are expensive to server-side render to be cached individually.</p>
    <div>
      <h3>Fantastic Lighthouse scores</h3>
      <a href="#fantastic-lighthouse-scores">
        
      </a>
    </div>
    <p>Streaming server-rendered HTML results in great user experiences and <a href="https://developer.chrome.com/docs/lighthouse/overview/">Lighthouse</a> scores, which in practice means happier users and higher chance of conversions for your business.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4GNNIIhE13dbX7EwfTUoQ8/47168493eec000d1df7eb71db56bf271/image7-2.png" />
            
            </figure><p>Lighthouse scores for the Cloud Gallery app</p><p>Each fragment can parallelize requests to its child fragments and pipe the resulting HTML streams into its own single streamed server-side rendered response. Not only can this reduce the time to render the whole page but streaming each fragment through to the browser reduces the time to the first byte of each fragment.</p>
    <div>
      <h3>Eager interactivity</h3>
      <a href="#eager-interactivity">
        
      </a>
    </div>
    <p>One of the powers of a fragments architecture is that fragments can become interactive even while the rest of the application (including other fragments) is still being streamed down to the browser.</p><p>In our demo, the “filter” fragment is immediately interactive as soon as it is rendered, even if the image HTML for the “gallery” fragment is still loading.</p><p>To make it easier to see this, we added a slider to the top of the “header” that can simulate a network or database delay that slows down the HTML stream which renders the “gallery” images. Even when the “gallery” fragment is still loading, the type-ahead input, in the “filter” fragment, is already fully interactive.</p><p>Just think of all the frustration that this eager interactivity could avoid for web application users with unreliable Internet connection.</p>
    <div>
      <h2>Under the hood</h2>
      <a href="#under-the-hood">
        
      </a>
    </div>
    <p>As discussed already this architecture relies upon deploying this application as many cooperating Cloudflare Workers. Let’s look into some details of how this works in practice.</p><p>We experimented with various technologies, and while this approach can be used with many frontend libraries and frameworks, we found the <a href="https://qwik.builder.io/">Qwik framework</a> to be a particularly good fit, because of its HTML-first focus and low JavaScript overhead, which avoids any hydration problems.</p>
    <div>
      <h3>Implementing a fragment</h3>
      <a href="#implementing-a-fragment">
        
      </a>
    </div>
    <p>Each fragment is a server-side rendered Qwik application deployed to its own Cloudflare Worker. This means that you can even browse to these fragments directly. For example, the “header” fragment is deployed to <a href="https://cloud-gallery-header.web-experiments.workers.dev/">https://cloud-gallery-header.web-experiments.workers.dev/</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/24SSUszIf2fbUphL5lsfr9/756d04fc6bc455f3845b45bf1ff592c0/image8-2.png" />
            
            </figure><p>A screenshot of the self-hosted “header” fragment</p><p>The header fragment is defined as a <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/header/src/root.tsx"><code>Header</code></a> component using Qwik. This component is rendered in a Cloudflare Worker via a <code>fetch()</code> handler:</p>
            <pre><code>export default {
  fetch(request: Request, env: Record&lt;string, unknown&gt;): Promise&lt;Response&gt; {
    return renderResponse(request, env, &lt;Header /&gt;, manifest, "header");
  },
};</code></pre>
            <small><a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/header/src/entry.ssr.tsx"><b>cloud-gallery/header/src/entry.ssr.tsx</b></a></small><br /><p>The <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/renderResponse.ts"><code><u>renderResponse</u></code></a><code>()</code> function is a helper we wrote that server-side renders the fragment and streams it into the body of a <code>Response</code> that we return from the <code>fetch()</code> handler.</p><p>The header fragment serves its own JavaScript and image assets from its Cloudflare Worker. We configure <a href="https://developers.cloudflare.com/workers/wrangler"><u>Wrangler</u></a> to upload these assets to Cloudflare and serve them from our network.</p>
    <div>
      <h2>Implementing fragment composition</h2>
      <a href="#implementing-fragment-composition">
        
      </a>
    </div>
    <p>Fragments that contain child fragments have additional responsibilities:</p><ul><li><p>Request and inject child fragments when rendering their own HTML.</p></li><li><p>Proxy requests for child fragment assets through to the appropriate fragment.</p></li></ul>
    <div>
      <h3>Injecting child fragments</h3>
      <a href="#injecting-child-fragments">
        
      </a>
    </div>
    <p>The position of a child fragment inside its parent can be specified by a <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/fragmentHelpers.tsx"><code>FragmentPlaceholder</code></a> helper component that we have developed. For example, the “body” fragment has the “filter” and “gallery” fragments.</p>
            <pre><code>&lt;div class="content"&gt;
  &lt;FragmentPlaceholder name="filter" /&gt;
  &lt;FragmentPlaceholder name="gallery" /&gt;
&lt;/div&gt;</code></pre>
            <small><a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/body/src/root.tsx"><b>cloud-gallery/body/src/root.tsx</b></a></small><br /><p>The <code>FragmentPlaceholder</code> component is responsible for making a request for the fragment and piping the fragment stream into the output stream.</p>
    <div>
      <h3>Proxying asset requests</h3>
      <a href="#proxying-asset-requests">
        
      </a>
    </div>
    <p>As mentioned earlier, fragments can host their own assets, especially client-side JavaScript files. When a request for an asset arrives at the parent fragment, it needs to know which child fragment should receive the request.</p><p>In our demo we use a convention that such asset paths will be prefixed with <code>/_fragment/&lt;fragment-name&gt;</code>. For example, the header logo image path is <code>/_fragment/header/cf-logo.png</code>. We developed a <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/fragmentHelpers.tsx#L28"><code><u>tryGetFragmentAsset</u></code></a><code>()</code> helper which can be added to the parent fragment’s <code>fetch()</code> handler to deal with this:</p>
            <pre><code>export default {
  async fetch(
    request: Request,
    env: Record&lt;string, unknown&gt;
  ): Promise&lt;Response&gt; {
    // Proxy requests for assets hosted by a fragment.
    const asset = await tryGetFragmentAsset(env, request);
    if (asset !== null) {
      return asset;
    }
    // Otherwise server-side render the template injecting child fragments.
    return renderResponse(request, env, &lt;Root /&gt;, manifest, "div");
  },
};</code></pre>
            <small><a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/body/src/entry.ssr.tsx"><strong>cloud-gallery/body/src/entry.ssr.tsx</strong></a></small><br />
    <div>
      <h3>Fragment asset paths</h3>
      <a href="#fragment-asset-paths">
        
      </a>
    </div>
    <p>If a fragment hosts its own assets, then we need to ensure that any HTML it renders uses the special <code>_fragment/&lt;fragment-name&gt;</code> path prefix mentioned above when referring to these assets. We have implemented a strategy for this in the helpers we developed.</p><p>The <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/fragmentHelpers.tsx"><code><u>FragmentPlaceholder</u></code></a> component adds a `base` searchParam to the fragment request to tell it what this prefix should be. The <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/renderResponse.ts"><code><u>renderResponse</u></code></a><code>()</code> helper extracts this prefix and provides it to the Qwik server-side renderer. This ensures that any request for client-side JavaScript has the correct prefix. Fragments can apply a hook that we developed called <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/base.ts#L22"><code><u>useFragmentRoot</u></code></a><code>()</code>. This allows components to gather the prefix from a <a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/base.ts#L12"><code><u>FragmentContext</u></code></a> <a href="https://qwik.builder.io/docs/components/context/"><u>context</u></a>.</p><p>For example, since the “header” fragment hosts the Cloudflare and Github logos as assets, it must call the <code>useFragmentRoot()</code> hook:</p>
            <pre><code>export const Header = component$(() =&gt; {
  useStylesScoped$(HeaderCSS);
  useFragmentRoot();

  return (...);
});</code></pre>
            <small><a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/header/src/root.tsx"><strong>cloud-gallery/header/src/root.tsx</strong></a></small><p>The <code>FragmentContext</code> value can then be accessed in components that need to apply the prefix. For example, the <code>Image</code> component:</p>
            <pre><code>export const Image = component$((props: Record&lt;string, string | number&gt;) =&gt; {
  const { base } = useContext(FragmentContext);
  return &lt;img {...props} src={base + props.src} /&gt;;
});</code></pre>
            <small><a href="https://github.com/cloudflare/workers-web-experiments/blob/main/cloud-gallery/helpers/src/image/image.tsx"><strong>cloud-gallery/helpers/src/image/image.tsx</strong></a></small>
    <div>
      <h3>Service-binding fragments</h3>
      <a href="#service-binding-fragments">
        
      </a>
    </div>
    <p>Cloudflare Workers provide a mechanism called <a href="https://developers.cloudflare.com/workers/platform/bindings/about-service-bindings/">service bindings</a> to make requests between Cloudflare Workers efficiently that avoids network requests. In the demo we use this mechanism to make the requests from parent fragments to their child fragments with almost no performance overhead, while still allowing the fragments to be independently deployed.</p>
    <div>
      <h2>Comparison to current solutions</h2>
      <a href="#comparison-to-current-solutions">
        
      </a>
    </div>
    <p>This fragments architecture has three properties that distinguish it from other current solutions.</p><p>Unlike monoliths, or client-side micro-frontends, fragments are developed and deployed as independent server-side rendered applications that are composed together on the server-side. This significantly improves rendering speed, and lowers interaction latency in the browser.</p><p>Unlike server-side rendered micro-frontends with Node.js or cloud functions, Cloudflare Workers is a globally distributed compute platform with a region-less deployment model. It has incredibly low latency, and a near-zero communication overhead between fragments.</p><p>Unlike solutions based on <a href="https://webpack.js.org/concepts/module-federation/">module federation</a>, a fragment's client-side JavaScript is very specific to the fragment it is supporting. This means that it is small enough that we don’t need to have shared library code, eliminating the version skew issues and coordination problems when updating shared libraries.</p>
    <div>
      <h2>Future possibilities</h2>
      <a href="#future-possibilities">
        
      </a>
    </div>
    <p>This demo is just a proof of concept, so there are still areas to investigate. Here are some of the features we’d like to explore in the future.</p>
    <div>
      <h3>Caching</h3>
      <a href="#caching">
        
      </a>
    </div>
    <p>Each micro-frontend fragment can be cached independently of the others based on how static its content is. When requesting the full page, the fragments only need to run server-side rendering for micro-frontends that have changed.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3PxpkF17fG0fMqBX0nhT6n/1789385a464d8908f7646a1570c6314d/image2.jpg" />
            
            </figure><p>An application where the output of some fragments are cached</p><p>With per-fragment caching you can return the HTML response to the browser faster, and avoid incurring compute costs in re-rendering content unnecessarily.</p>
    <div>
      <h3>Fragment routing and client-side navigation</h3>
      <a href="#fragment-routing-and-client-side-navigation">
        
      </a>
    </div>
    <p>Our demo application used micro-frontend fragments to compose a single page. We could however use this approach to implement page routing as well. When server-side rendering, the main fragment could insert the appropriate “page” fragment based on the visited URL. When navigating, client-side, within the app, the main fragment would remain the same while the displayed “page” fragment would change.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/31uGNgOqJccEZXHRfrK7Fw/a69dd9152b184802d07c437347560251/image5-1.jpg" />
            
            </figure><p>An application where each route is delegated to a different fragment</p><p>This approach combines the best of server-side and client-side routing with the power of fragments.</p>
    <div>
      <h3>Using other frontend frameworks</h3>
      <a href="#using-other-frontend-frameworks">
        
      </a>
    </div>
    <p>Although the Cloud Gallery application uses Qwik to implement all fragments, it is possible to use other frameworks as well. If really necessary, it’s even possible to mix and match frameworks.</p><p>To achieve good results, the framework of choice should be capable of server-side rendering, and should have a small client-side JavaScript footprint. HTML streaming capabilities, while not required, can significantly improve performance of large applications.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1AkgbhioqHBaKtvZxVTIsp/6a818eeb06c4ad842886e81f9d0f477a/image1-15.png" />
            
            </figure><p>An application using different frontend frameworks</p>
    <div>
      <h3>Incremental migration strategies</h3>
      <a href="#incremental-migration-strategies">
        
      </a>
    </div>
    <p>Adopting a new architecture, compute platform, and deployment model is a lot to take in all at once, and for existing large applications is prohibitively risky and expensive. To make this  fragment-based architecture available to legacy projects, an incremental adoption strategy is a key.</p><p>Developers could test the waters by migrating just a single piece of the user-interface within their legacy application to a fragment, integrating with minimal changes to the legacy application. Over time, more of the application could then be moved over, one fragment at a time.</p>
    <div>
      <h3>Convention over configuration</h3>
      <a href="#convention-over-configuration">
        
      </a>
    </div>
    <p>As you can see in the Cloud Gallery demo application, setting up a fragment-based micro-frontend requires quite a bit of configuration. A lot of this configuration is very mechanical and could be abstracted away via conventions and better tooling. Following productivity-focused precedence found in Ruby on Rails, and filesystem based routing meta-frameworks, we could make a lot of this configuration disappear.</p>
    <div>
      <h2>Try it yourself!</h2>
      <a href="#try-it-yourself">
        
      </a>
    </div>
    <p>There is still so much to dig into! Web applications have come a long way in recent years and their growth is hard to overstate. Traditional implementations of micro-frontends have had only mixed success in helping developers scale development and deployment of large applications. Cloudflare Workers, however, unlock new possibilities which can help us tackle many of the existing challenges and help us build better web applications.</p><p>Thanks to the <a href="https://workers.cloudflare.com/#plans">generous free plan</a> offered by Cloudflare Workers, you can <a href="https://github.com/cloudflare/workers-web-experiments/tree/main/cloud-gallery">check out the Gallery Demo code</a> and deploy it yourself.</p><p>If all of these sounds interesting to you, and you would like to work with us on improving the developer experience for Cloudflare Workers, we are also happy to share that <a href="https://boards.greenhouse.io/cloudflare/jobs/4619341">we are hiring</a>!</p> ]]></content:encoded>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Micro-frontends]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Serverless]]></category>
            <guid isPermaLink="false">irbcct7Wl9QqgfZhsBGew</guid>
            <dc:creator>Peter Bacon Darwin</dc:creator>
            <dc:creator>James Culveyhouse</dc:creator>
            <dc:creator>Igor Minar</dc:creator>
        </item>
    </channel>
</rss>