Dylan  Iqbal

Dylan Iqbal

1626491665

Running a Next.js Site on Cloudflare Pages

Step by step tutorial on how to deploy your website on Cloudflare Pages

The Original Article can be found on https://opstrace.com

JAMstack Overflow

These days there are so many providers for JAMstack hosting, it’s hard to choose. Netlify, GitHub Pages, Vercel, Heroku, … the New Dynamic has a list of over 30 different hosting/deployment tools, with new ones being added regularly. However, the new kid in town caught our attention: Cloudflare Pages. They have only been around for a few months now, but since we already use Cloudflare for DNS and CDN, consolidating tools could be a nice win.

Cloudflare Pages radically simplifies the process of developing and deploying sites by taking care of all the tedious parts of web development. Now, developers can focus on the fun and creative parts instead. – https://blog.cloudflare.com/cloudflare-pages-ga/

Next.js on Cloudflare

Given they’re just starting up, the features are still a bit limited. One of the biggest drawbacks as of this moment is the lack of a server to generate dynamic content. Currently, Cloudflare uses the Next.js static HTML export to prerender all pages to plain html. Given we don’t use any server-side rendering capabilities at the moment, this was good enough to move forward now, but we are also excited to see the further development of Cloudflare Pages.

Getting started

Let’s create a project:

cloudflare create a project first screen

Assuming you have a Next.js website and both next build and next export run through without any errors (you’ll probably see an error when using next/image, we’ll get to that in a moment), make sure everything is committed and pushed to a repository. In addition, make sure you create alias scripts in package.json for build and export:

"build": "next build",
"export": "next export",

This is necessary to run post-build scripts to generate additional content such as a sitemap.xmlrobots.txt, RSS/Atom feeds etc.

Log in to your Cloudflare Dashboard and head to “Pages” on the right. “Create a project” and connect to your repository.

When you’re in the build configuration section, they offer “Next.js (Static Export)” as a framework preset, but since this preset uses next commands by default, pre/post build hooks from our package.json are ignored. Instead, do not select a preset and configure the build options manually. The Cloudflare “build command” should be:

npm run build && npm run export
## or
## yarn build && yarn export

Similarly, the static files will be exported to a directory called out, so set the “build output directory” field to this. Your input should look like this:

cloudflare build settings screen

Once saved, Pages will automatically initiate the first build. Once the build is successful, you can then head to the *.pages.dev URL that will be shown at the top of the page. In a Pull Request, Cloudflare comments the build status and preview url.

If you are already using Cloudflare DNS, you can connect your custom domain in the next step—Cloudflare will automatically generate the CNAME for you with a click on the “activate domain” button:

cloudflare connect custom domain

Congratulations, you’re now running your Next.js site on Cloudflare Pages! Now, the fine print.

Images

The Problem

If you switched to the new next/image component in Next.js 11, you’ll see the following warning during export:

Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
  Possible solutions:
    - Use `next start` to run a server, which includes the Image Optimization API.
    - Use any provider which supports Image Optimization (like Vercel).
    - Configure a third-party loader in `next.config.js`.
    - Use the `loader` prop for `next/image`.
  Read more: https://nextjs.org/docs/messages/export-image-api

Since we want to do image optimization and we don’t want any new tools, we’ve decided to look at another Clouflare option—a Cloudflare Worker.

Create a Worker

To create one in your Cloudflare Dashboard, go to “Workers” > “Create a Worker”. Cloudflare Docs has an entire article about Resizing Images with Cloudflare Workers, and prepared the script for you to copy into the {} Script box:

// https://developers.cloudflare.com/images/resizing-with-workers
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
  let url = new URL(request.url)
  let options = { cf: { image: {} } }
  if (url.searchParams.has('fit'))
    options.cf.image.fit = url.searchParams.get('fit')
  if (url.searchParams.has('width'))
    options.cf.image.width = url.searchParams.get('width')
  if (url.searchParams.has('height'))
    options.cf.image.height = url.searchParams.get('height')
  if (url.searchParams.has('quality'))
    options.cf.image.quality = url.searchParams.get('quality')
  const imageURL = url.searchParams.get('image')
  const imageRequest = new Request(imageURL, {
    headers: request.headers
  })
  return fetch(imageRequest, options)
}

In the top right, you can change the name of the worker. Once saved, note down the URL, we’ll need that.

cloudflare image worker preview

Configure the Loader

As the error gives us possible solutions, unfortunately we can’t “Configure a third-party loader in next.config.js.” - there is a small list of pre-existing loaders, but Cloudflare isn’t one of them and they’re no longer adding new default loaders. So we’re using the loader prop for ‘next/image’:

// replace [yourprojectname] and [yourdomain.com] with your actual project name and (custom) domain
const cloudflareImageLoader = ({ src, width, quality }) => {
  if (!quality) {
    quality = 75
  }
  return `https://images.[yourprojectname].workers.dev?width=${width}&quality=${quality}&image=https://[yourdomain.com]${src}`
}

And the <Image>:

const MyImage = (props) => {
  return (
    <Image
      loader={cloudflareImageLoader}
      src="me.png"
      alt="Picture of the author"
      width={500}
      height={500}
    />
  )
}

This would be too cumbersome to add this loader to every single <Image> tag you have in your project. So we created a custom Image component (/components/Image.jsx):

import Image from 'next/image'

// replace [yourprojectname] and [yourdomain.com] with your actual project name and (custom) domain
const cloudflareImageLoader = ({ src, width, quality }) => {
  if (!quality) {
    quality = 75
  }
  return `https://images.[yourprojectname].workers.dev?width=${width}&quality=${quality}&image=https://[yourdomain.com]${src}`
}

export default function Img(props) {
  if (process.env.NODE_ENV === 'development') {
    return <Image unoptimized={true} {...props} />
  } else {
    return <Image {...props} loader={cloudflareImageLoader} />
  }
}
Node 16 Hiccup

If you’re running on Node 16, you may already have had issues with Images on Next.js, and because we don’t need image optimziation during development, we’ve removed the loader and added unoptimized={true} for the development environment.

Now you can search/replace all import Image from next/image to import Image from components/Image. To resolve the import path components/Image, you need to add a jsconfig.json to your project so that components/Image will resolve to ./src/components/Image:

{
  "compilerOptions": {
    "baseUrl": "."
  }
}

Once you’ve done all that, you’ll probably still see the same error during next export, so let’s add a fake third-party loader into next.config.js (this fake loader will not be used—it’s just a hack to avoid the build error):

images: {
  loader: 'imgix',
  path: ''
},

npm run export should now run successfully without any errors!

Previews

Cloudflare Pages also offer a GitHub integration that provides Pull Request previews, posting a comment to each Pull Request with the deployment status, which is extremely useful. (Other services provide this as well, for example, Vercel.)

However, one thing that was missing: a direct link out to the preview. In order to retrieve the preview URL, we built a GitHub Action Cloudflare Preview URL that waits for the deployment to be ready and then returns the URL. This is useful to run E2E tests, URL link checks etc. on a real website before going live.

There’s room for improvement though:

  • build times are still very long (2+ minutes to initialize the build environment).
  • more flexibility with environment and build variables to expose system/build related information in user-defined variables.
  • use of the GitHub Deployments API, which fires an event when a deployment is ready, instead of polling the Cloudflare API.

Sitemap

You can use next-sitemap to generate a sitemap for all your pages automatically after build. Follow the README and add the next-sitemap.js as well as the post-build hook. This works out of the box with static site generation and the sitemap.xml and robots.txt will be copied into the export (/out) folder during npm run export. You should add both files to .gitignore to prevent them being added to the repository.

RSS Feeds

If you publish regularly and you want to give your audience a way to subscribe to your blog, RSS/Atom is the standard format for that. Most tutorials you’ll find about RSS generation require server-side rendering from your dynamic content, though. But we can also solve this with a post build hook.

First, we need a script to generate the feed from our articles. We put this in utils/generate-rss.js. We use feed to help generate the XML and JSON files for RSS and Atom.

import fs from 'fs'
import { Feed } from 'feed'
import getPosts from 'utils/getPosts'

// site.js exports the default site variables, such as the link, default image, favicon, etc
import meta from 'content/site.js'

async function generate() {
  const feed = new Feed({
    title: meta.title,
    description: meta.description,
    image: meta.image,
    favicon: meta.favicon,
    copyright: meta.copyright,
    language: meta.language,
    link: meta.link,
    id: meta.link,
    feedLinks: {
      json: `${meta.link}feed.json`,
      rss2: `${meta.link}feed.xml`,
      atom: `${meta.link}atom.xml`
    }
  })

  // we store blog articles in content/articles/article.mdx
  // you can change the path and regex here for your project.
  const posts = ((context) => {
    return getPosts(context)
  })(require.context('content/articles', true, /\.\/.*\.mdx$/))

  posts.forEach((post) => {
    feed.addItem({
      title: post.title,
      id: `${meta.link}${post.slug}`,
      link: `${meta.link}${post.slug}`,
      date: new Date(post.date),
      description: post.description,
      image: `${meta.link}${post.featuredImage.src}`
    })
  })

  fs.writeFileSync('./public/feed.xml', feed.rss2())
  fs.writeFileSync('./public/feed.json', feed.json1())
  fs.writeFileSync('./public/atom.xml', feed.atom1())
}

generate()

This is a little tricky. As you can see we’re using require.context which isn’t available outside the Next/Webpack environment. We’re using a modified webpack config in next.config.js to compile the script and put it into the build directory:

webpack: function (config, { dev, isServer }) {
  if (!dev && isServer) {
    const originalEntry = config.entry

    config.entry = async () => {
      const entries = { ...(await originalEntry()) }
      entries['utils/generate-rss.js'] = 'utils/generate-rss.js'
      return entries
    }
  }
  return config
}

Finally, we’ll need to run the script after build (another post-build hook). In order to run this in parallel with the sitemap generation and keep everything neat and tidy, we’re using npm-run-all:

"export": "next export",
"build": "next build",
"postbuild": "run-p generate:sitemap generate:rss",
"generate:rss": "node ./.next/server/utils/generate-rss.js.js",
"generate:sitemap": "next-sitemap",

You can now add the feeds into your _document.js <Head>:

<Html lang="en">
  <Head>
    ...
    <link
      rel="alternate"
      type="application/rss+xml"
      title="Opstrace RSS2 Feed"
      href="https://opstrace.com/feed.xml"
    />
    <link
      rel="alternate"
      type="application/atom+xml"
      title="Opstrace Atom Feed"
      href="https://opstrace.com/atom.xml"
    />
    <link
      rel="alternate"
      type="application/json"
      title="Opstrace JSON Feed"
      href="https://opstrace.com/feed.json"
    />
    ...
  </Head>
  <body>
    <Main />
    <NextScript />
  </body>
</Html>

Conclusion

Getting a first build on Cloudflare is incredibly easy, fast and convenient. Give Cloudflare permission for your repo, build, deploy—done. And it’s free. If you use them for DNS, no manual DNS changes need to be made because Cloudflare does that for you. As they’re feeding your site directly into their incredibly powerful content delivery network (CDN), you can expect the best load performance available.

With Cloudflare you also get some decent Account Analytics out of the box without any tracking snippets. (Also, script blockers cannot side-step this tracking.) They’ve also recently added Web Analytics. Overall it’s a great offer for JAMstack sites and reduces the need for yet another tool to log in to and maintain.

Preparing Next.js was a little bit of work, but there were no serious blockers that prevented us from deploying with and hosting on Cloudflare Pages. We’re now experimenting with Cloudflare Workers and Google Cloud Functions to add some server-side capabilities to our site, for example to collect feedback or handle our Stripe subscriptions. There are a few known convenience features missing from the build environment, but Cloudflare will probably add those soon. And maybe they’ll even support Server-Side Rendering (SSR) capabilities for Next.js sites, too.

#next #cloudflare #react #web-development #webdev

What is GEEK

Buddha Community

Running a Next.js Site on Cloudflare Pages

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Eva  Murphy

Eva Murphy

1625674200

Google analytics Setup with Next JS, React JS using Router Events - 14

In this video, we are going to implement Google Analytics to our Next JS application. Tracking page views of an application is very important.

Google analytics will allow us to track analytics information.

Frontend: https://github.com/amitavroy/video-reviews
API: https://github.com/amitavdevzone/video-review-api
App link: https://video-reviews.vercel.app

You can find me on:
Twitter: https://twitter.com/amitavroy7​
Discord: https://discord.gg/Em4nuvQk

#next js #js #react js #react #next #google analytics

Dylan  Iqbal

Dylan Iqbal

1626491665

Running a Next.js Site on Cloudflare Pages

Step by step tutorial on how to deploy your website on Cloudflare Pages

The Original Article can be found on https://opstrace.com

JAMstack Overflow

These days there are so many providers for JAMstack hosting, it’s hard to choose. Netlify, GitHub Pages, Vercel, Heroku, … the New Dynamic has a list of over 30 different hosting/deployment tools, with new ones being added regularly. However, the new kid in town caught our attention: Cloudflare Pages. They have only been around for a few months now, but since we already use Cloudflare for DNS and CDN, consolidating tools could be a nice win.

Cloudflare Pages radically simplifies the process of developing and deploying sites by taking care of all the tedious parts of web development. Now, developers can focus on the fun and creative parts instead. – https://blog.cloudflare.com/cloudflare-pages-ga/

Next.js on Cloudflare

Given they’re just starting up, the features are still a bit limited. One of the biggest drawbacks as of this moment is the lack of a server to generate dynamic content. Currently, Cloudflare uses the Next.js static HTML export to prerender all pages to plain html. Given we don’t use any server-side rendering capabilities at the moment, this was good enough to move forward now, but we are also excited to see the further development of Cloudflare Pages.

Getting started

Let’s create a project:

cloudflare create a project first screen

Assuming you have a Next.js website and both next build and next export run through without any errors (you’ll probably see an error when using next/image, we’ll get to that in a moment), make sure everything is committed and pushed to a repository. In addition, make sure you create alias scripts in package.json for build and export:

"build": "next build",
"export": "next export",

This is necessary to run post-build scripts to generate additional content such as a sitemap.xmlrobots.txt, RSS/Atom feeds etc.

Log in to your Cloudflare Dashboard and head to “Pages” on the right. “Create a project” and connect to your repository.

When you’re in the build configuration section, they offer “Next.js (Static Export)” as a framework preset, but since this preset uses next commands by default, pre/post build hooks from our package.json are ignored. Instead, do not select a preset and configure the build options manually. The Cloudflare “build command” should be:

npm run build && npm run export
## or
## yarn build && yarn export

Similarly, the static files will be exported to a directory called out, so set the “build output directory” field to this. Your input should look like this:

cloudflare build settings screen

Once saved, Pages will automatically initiate the first build. Once the build is successful, you can then head to the *.pages.dev URL that will be shown at the top of the page. In a Pull Request, Cloudflare comments the build status and preview url.

If you are already using Cloudflare DNS, you can connect your custom domain in the next step—Cloudflare will automatically generate the CNAME for you with a click on the “activate domain” button:

cloudflare connect custom domain

Congratulations, you’re now running your Next.js site on Cloudflare Pages! Now, the fine print.

Images

The Problem

If you switched to the new next/image component in Next.js 11, you’ll see the following warning during export:

Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
  Possible solutions:
    - Use `next start` to run a server, which includes the Image Optimization API.
    - Use any provider which supports Image Optimization (like Vercel).
    - Configure a third-party loader in `next.config.js`.
    - Use the `loader` prop for `next/image`.
  Read more: https://nextjs.org/docs/messages/export-image-api

Since we want to do image optimization and we don’t want any new tools, we’ve decided to look at another Clouflare option—a Cloudflare Worker.

Create a Worker

To create one in your Cloudflare Dashboard, go to “Workers” > “Create a Worker”. Cloudflare Docs has an entire article about Resizing Images with Cloudflare Workers, and prepared the script for you to copy into the {} Script box:

// https://developers.cloudflare.com/images/resizing-with-workers
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
  let url = new URL(request.url)
  let options = { cf: { image: {} } }
  if (url.searchParams.has('fit'))
    options.cf.image.fit = url.searchParams.get('fit')
  if (url.searchParams.has('width'))
    options.cf.image.width = url.searchParams.get('width')
  if (url.searchParams.has('height'))
    options.cf.image.height = url.searchParams.get('height')
  if (url.searchParams.has('quality'))
    options.cf.image.quality = url.searchParams.get('quality')
  const imageURL = url.searchParams.get('image')
  const imageRequest = new Request(imageURL, {
    headers: request.headers
  })
  return fetch(imageRequest, options)
}

In the top right, you can change the name of the worker. Once saved, note down the URL, we’ll need that.

cloudflare image worker preview

Configure the Loader

As the error gives us possible solutions, unfortunately we can’t “Configure a third-party loader in next.config.js.” - there is a small list of pre-existing loaders, but Cloudflare isn’t one of them and they’re no longer adding new default loaders. So we’re using the loader prop for ‘next/image’:

// replace [yourprojectname] and [yourdomain.com] with your actual project name and (custom) domain
const cloudflareImageLoader = ({ src, width, quality }) => {
  if (!quality) {
    quality = 75
  }
  return `https://images.[yourprojectname].workers.dev?width=${width}&quality=${quality}&image=https://[yourdomain.com]${src}`
}

And the <Image>:

const MyImage = (props) => {
  return (
    <Image
      loader={cloudflareImageLoader}
      src="me.png"
      alt="Picture of the author"
      width={500}
      height={500}
    />
  )
}

This would be too cumbersome to add this loader to every single <Image> tag you have in your project. So we created a custom Image component (/components/Image.jsx):

import Image from 'next/image'

// replace [yourprojectname] and [yourdomain.com] with your actual project name and (custom) domain
const cloudflareImageLoader = ({ src, width, quality }) => {
  if (!quality) {
    quality = 75
  }
  return `https://images.[yourprojectname].workers.dev?width=${width}&quality=${quality}&image=https://[yourdomain.com]${src}`
}

export default function Img(props) {
  if (process.env.NODE_ENV === 'development') {
    return <Image unoptimized={true} {...props} />
  } else {
    return <Image {...props} loader={cloudflareImageLoader} />
  }
}
Node 16 Hiccup

If you’re running on Node 16, you may already have had issues with Images on Next.js, and because we don’t need image optimziation during development, we’ve removed the loader and added unoptimized={true} for the development environment.

Now you can search/replace all import Image from next/image to import Image from components/Image. To resolve the import path components/Image, you need to add a jsconfig.json to your project so that components/Image will resolve to ./src/components/Image:

{
  "compilerOptions": {
    "baseUrl": "."
  }
}

Once you’ve done all that, you’ll probably still see the same error during next export, so let’s add a fake third-party loader into next.config.js (this fake loader will not be used—it’s just a hack to avoid the build error):

images: {
  loader: 'imgix',
  path: ''
},

npm run export should now run successfully without any errors!

Previews

Cloudflare Pages also offer a GitHub integration that provides Pull Request previews, posting a comment to each Pull Request with the deployment status, which is extremely useful. (Other services provide this as well, for example, Vercel.)

However, one thing that was missing: a direct link out to the preview. In order to retrieve the preview URL, we built a GitHub Action Cloudflare Preview URL that waits for the deployment to be ready and then returns the URL. This is useful to run E2E tests, URL link checks etc. on a real website before going live.

There’s room for improvement though:

  • build times are still very long (2+ minutes to initialize the build environment).
  • more flexibility with environment and build variables to expose system/build related information in user-defined variables.
  • use of the GitHub Deployments API, which fires an event when a deployment is ready, instead of polling the Cloudflare API.

Sitemap

You can use next-sitemap to generate a sitemap for all your pages automatically after build. Follow the README and add the next-sitemap.js as well as the post-build hook. This works out of the box with static site generation and the sitemap.xml and robots.txt will be copied into the export (/out) folder during npm run export. You should add both files to .gitignore to prevent them being added to the repository.

RSS Feeds

If you publish regularly and you want to give your audience a way to subscribe to your blog, RSS/Atom is the standard format for that. Most tutorials you’ll find about RSS generation require server-side rendering from your dynamic content, though. But we can also solve this with a post build hook.

First, we need a script to generate the feed from our articles. We put this in utils/generate-rss.js. We use feed to help generate the XML and JSON files for RSS and Atom.

import fs from 'fs'
import { Feed } from 'feed'
import getPosts from 'utils/getPosts'

// site.js exports the default site variables, such as the link, default image, favicon, etc
import meta from 'content/site.js'

async function generate() {
  const feed = new Feed({
    title: meta.title,
    description: meta.description,
    image: meta.image,
    favicon: meta.favicon,
    copyright: meta.copyright,
    language: meta.language,
    link: meta.link,
    id: meta.link,
    feedLinks: {
      json: `${meta.link}feed.json`,
      rss2: `${meta.link}feed.xml`,
      atom: `${meta.link}atom.xml`
    }
  })

  // we store blog articles in content/articles/article.mdx
  // you can change the path and regex here for your project.
  const posts = ((context) => {
    return getPosts(context)
  })(require.context('content/articles', true, /\.\/.*\.mdx$/))

  posts.forEach((post) => {
    feed.addItem({
      title: post.title,
      id: `${meta.link}${post.slug}`,
      link: `${meta.link}${post.slug}`,
      date: new Date(post.date),
      description: post.description,
      image: `${meta.link}${post.featuredImage.src}`
    })
  })

  fs.writeFileSync('./public/feed.xml', feed.rss2())
  fs.writeFileSync('./public/feed.json', feed.json1())
  fs.writeFileSync('./public/atom.xml', feed.atom1())
}

generate()

This is a little tricky. As you can see we’re using require.context which isn’t available outside the Next/Webpack environment. We’re using a modified webpack config in next.config.js to compile the script and put it into the build directory:

webpack: function (config, { dev, isServer }) {
  if (!dev && isServer) {
    const originalEntry = config.entry

    config.entry = async () => {
      const entries = { ...(await originalEntry()) }
      entries['utils/generate-rss.js'] = 'utils/generate-rss.js'
      return entries
    }
  }
  return config
}

Finally, we’ll need to run the script after build (another post-build hook). In order to run this in parallel with the sitemap generation and keep everything neat and tidy, we’re using npm-run-all:

"export": "next export",
"build": "next build",
"postbuild": "run-p generate:sitemap generate:rss",
"generate:rss": "node ./.next/server/utils/generate-rss.js.js",
"generate:sitemap": "next-sitemap",

You can now add the feeds into your _document.js <Head>:

<Html lang="en">
  <Head>
    ...
    <link
      rel="alternate"
      type="application/rss+xml"
      title="Opstrace RSS2 Feed"
      href="https://opstrace.com/feed.xml"
    />
    <link
      rel="alternate"
      type="application/atom+xml"
      title="Opstrace Atom Feed"
      href="https://opstrace.com/atom.xml"
    />
    <link
      rel="alternate"
      type="application/json"
      title="Opstrace JSON Feed"
      href="https://opstrace.com/feed.json"
    />
    ...
  </Head>
  <body>
    <Main />
    <NextScript />
  </body>
</Html>

Conclusion

Getting a first build on Cloudflare is incredibly easy, fast and convenient. Give Cloudflare permission for your repo, build, deploy—done. And it’s free. If you use them for DNS, no manual DNS changes need to be made because Cloudflare does that for you. As they’re feeding your site directly into their incredibly powerful content delivery network (CDN), you can expect the best load performance available.

With Cloudflare you also get some decent Account Analytics out of the box without any tracking snippets. (Also, script blockers cannot side-step this tracking.) They’ve also recently added Web Analytics. Overall it’s a great offer for JAMstack sites and reduces the need for yet another tool to log in to and maintain.

Preparing Next.js was a little bit of work, but there were no serious blockers that prevented us from deploying with and hosting on Cloudflare Pages. We’re now experimenting with Cloudflare Workers and Google Cloud Functions to add some server-side capabilities to our site, for example to collect feedback or handle our Stripe subscriptions. There are a few known convenience features missing from the build environment, but Cloudflare will probably add those soon. And maybe they’ll even support Server-Side Rendering (SSR) capabilities for Next.js sites, too.

#next #cloudflare #react #web-development #webdev

Eva  Murphy

Eva Murphy

1625751960

Laravel API and React Next JS frontend development - 28

In this video, I wanted to touch upon the functionality of adding Chapters inside a Course. The idea was to not think much and start the development and pick up things as they come.

There are places where I get stuck and trying to find answers to it up doing what every developer does - Google and get help. I hope this will help you understand the flow and also how developers debug while doing development.

App url: https://video-reviews.vercel.app
Github code links below:
Next JS App: https://github.com/amitavroy/video-reviews
Laravel API: https://github.com/amitavdevzone/video-review-api

You can find me on:
Twitter: https://twitter.com/amitavroy7​
Discord: https://discord.gg/Em4nuvQk

#next js #api #react next js #next #frontend #development

Deploy Next.js to Cloudflare Pages - Cloudflare Static Web Apps Tutorial

Learn how to use Cloudflare Pages to host and deploy static Next.js web apps. In this tutorial, we’ll walk through:

  • 00:00 - Intro
  • 00:09 - What tools will we use?
  • 00:39 - Using Create Next App to create a new Next.js app
  • 01:14 - Creating a new GitHub repository
  • 02:34 - Connecting a GitHub repository to Cloudflare Pages
  • 03:52 - Deploying a Next.js app to Cloudflare Pages
  • 07:39 - Cloudflare Deploy Previews with GitHub Pull Requests
  • 09:24 - Outro

🗒️ Read More
https://spacejelly.dev/posts/how-to-use-cloudflare-pages-to-host-deploy-a-next-js-app/

#cloudflare #next #react #javascript