<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matthias Zaunseder</title>
    <description>The latest articles on DEV Community by Matthias Zaunseder (@zauni).</description>
    <link>https://dev.to/zauni</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F350854%2F01adbf64-bdfe-47c2-a8e8-199580141eeb.jpeg</url>
      <title>DEV Community: Matthias Zaunseder</title>
      <link>https://dev.to/zauni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zauni"/>
    <language>en</language>
    <item>
      <title>Create a zx Node.js script as binary with pkg</title>
      <dc:creator>Matthias Zaunseder</dc:creator>
      <pubDate>Thu, 17 Mar 2022 16:04:19 +0000</pubDate>
      <link>https://dev.to/zauni/create-a-zx-nodejs-script-as-binary-with-pkg-5abf</link>
      <guid>https://dev.to/zauni/create-a-zx-nodejs-script-as-binary-with-pkg-5abf</guid>
      <description>&lt;p&gt;So there is this really cool library called &lt;a href="https://github.com/google/zx"&gt;zx&lt;/a&gt; which you can use to create scripts that are replacements for bash scripts.&lt;br&gt;
But one downside of it is, that now you have to have the Node.js runtime installed on the machine where this script should run. That's sad :(&lt;/p&gt;

&lt;p&gt;But what if you could create a binary which includes your script AND the Node.js runtime?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/vercel/pkg"&gt;pkg&lt;/a&gt; to the rescue!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But first things first, let's create a simple zx script. Please make sure that you have Node.js 16+ installed on your machine and then open a shell and type the following commands to create a new directory and initialise a Node.js project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /my/projects
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-cli
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-cli
&lt;span class="nv"&gt;$ &lt;/span&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should have a &lt;code&gt;package.json&lt;/code&gt; file and in this file you have to add "type": "module" for zx to work correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  "name": "my-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
&lt;span class="gi"&gt;+ "type": "module"
&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we can add zx as a dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;zx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are ready to write our nice little script! Create a folder &lt;code&gt;src&lt;/code&gt; and add a file &lt;code&gt;index.js&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;`date`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test it now in the shell with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node src/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should output the current date and time on your machine. But as we saw we have to use the &lt;code&gt;node&lt;/code&gt; runtime to execute our script (or the &lt;code&gt;zx&lt;/code&gt; runtime as they show in their examples). Because this is sometimes not ideal, for example if the machine doesn't have Node.js or zx installed then our script can not run there.&lt;/p&gt;

&lt;p&gt;The solution to this problem is to pack the runtime and our script in an executable binary and then you can start your script even if the machine has no runtime installed.&lt;/p&gt;

&lt;p&gt;For the packaging we will use the &lt;a href="https://github.com/vercel/pkg"&gt;pkg&lt;/a&gt; library. But unfortunately pkg &lt;a href="https://github.com/vercel/pkg/issues/1291"&gt;is not supporting ES modules&lt;/a&gt; which we configured by adding the &lt;code&gt;"type": "module"&lt;/code&gt; to the &lt;code&gt;package.json&lt;/code&gt;. So before we can use pkg we need to compile our script to a version which is not using ES modules. To do the compilation we will use &lt;a href="https://github.com/evanw/esbuild"&gt;esbuild&lt;/a&gt;. esbuild can also bundle our script into one file, so no dependencies on a &lt;code&gt;node_modules&lt;/code&gt; folder are left in the compiled file. So let's install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; esbuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's add a npm script in &lt;code&gt;package.json&lt;/code&gt; to do the compilation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  "name": "my-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
&lt;span class="gd"&gt;-    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
&lt;/span&gt;&lt;span class="gi"&gt;+    "compile": "esbuild src/index.js --platform=node --target=node16 --bundle --outfile=dist/outfile.cjs"
&lt;/span&gt;  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "module",
  "dependencies": {
    "zx": "^6.0.1"
  },
  "devDependencies": {
    "esbuild": "^0.14.27"
  }
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This npm script will execute esbuild, use &lt;code&gt;src/index.js&lt;/code&gt; as an entrypoint and configure esbuild to output a Node.js v16+ compatible file to &lt;code&gt;dist/outfile.cjs&lt;/code&gt;. The &lt;code&gt;.cjs&lt;/code&gt; file ending is important because otherwise pkg tries to load our bundle with ES modules even if we have compiled them away.&lt;/p&gt;

&lt;p&gt;So now you can try the compiling script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm run compile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see something like this in the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; my-cli@1.0.0 compile
&amp;gt; esbuild src/index.js --platform=node --target=node16 --bundle --outfile=dist/outfile.cjs

  dist/outfile.cjs  439.1kb

⚡ Done in 246ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up we install the pkg library and also add a npm script to execute it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; pkg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;: (don't forget the comma after the compile script)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
  "name": "my-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "compile": "esbuild src/index.js --platform=node --target=node16 --bundle --outfile=dist/outfile.cjs",
&lt;span class="gi"&gt;+   "package": "pkg dist/outfile.cjs --targets node16 --output dist/my-cli --debug"
&lt;/span&gt;  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "module",
  "dependencies": {
    "zx": "^6.0.1"
  },
  "devDependencies": {
    "esbuild": "^0.14.27",
    "pkg": "^5.5.2"
  }
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;package&lt;/code&gt; script is executing pkg and uses dist/outfile.cjs as entrypoint. Also it configures that we want to have Node.js 16 as a target runtime and it should output a file &lt;code&gt;dist/my-cli&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now if you execute the &lt;code&gt;package&lt;/code&gt; script you should hopefully see a binary in your &lt;code&gt;dist&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm run package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This outputs a lot of debugging information which you can ignore for now. But if you have problems you can see there couple of helpful infos to diagnose the issue.&lt;/p&gt;

&lt;p&gt;Please keep in mind, that this will output a binary which is only compatible with the same operating system and processor architecture as your developer machine. So if you execute the &lt;code&gt;npm run package&lt;/code&gt; command on a Windows machine with x64 processor, the binary will not work on a Linux or macOS machine. To work there, you would either need to change the package command to include more targets (please see &lt;a href="https://github.com/vercel/pkg#targets"&gt;the documentation for that&lt;/a&gt;) or execute the package command on the same OS/processor architecture.&lt;/p&gt;

&lt;p&gt;Now in your file explorer you can already see a file &lt;code&gt;dist/my-cli&lt;/code&gt; or &lt;code&gt;dist/my-cli.exe&lt;/code&gt; depending on the OS you are working with. And this file is executable in the shell for example with this call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./dist/my-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And if everything worked you should see the current date and time 🥳&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This binary file can now be used without any runtime (as long as you execute it on the same OS/processor architecture) Great!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have fun writing great scripts which are runtime agnostic!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Markus Spiske&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/binary?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Craft CMS Live Preview with Next.js 9.3 Static Site Generation and GraphQL</title>
      <dc:creator>Matthias Zaunseder</dc:creator>
      <pubDate>Sun, 15 Mar 2020 18:42:24 +0000</pubDate>
      <link>https://dev.to/zauni/craft-cms-live-preview-with-next-js-9-3-and-graphql-308g</link>
      <guid>https://dev.to/zauni/craft-cms-live-preview-with-next-js-9-3-and-graphql-308g</guid>
      <description>&lt;p&gt;&lt;a href="https://nextjs.org/blog/next-9-3"&gt;Next.js 9.3&lt;/a&gt; was released 9th of March and has a new and exciting feature for all headless CMS users out there: &lt;strong&gt;Static Site Generation&lt;/strong&gt; coupled with &lt;strong&gt;Preview Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/blog/next-9-3#next-gen-static-site-generation-ssg-support"&gt;Static Site Generation&lt;/a&gt; (SSG for short) allows us to generate a static site with the contents of our headless CMS during the build. The magic function which enables this is &lt;code&gt;getStaticProps&lt;/code&gt;. There we can fetch data from any data source and Next.js will use it to generate a static site.&lt;/p&gt;

&lt;p&gt;So this is nice, but now you have static HTML/JS/CSS, but your users of the CMS might want to see a preview of their newly created content. Then you want to dynamically render the page again so that the CMS editor can see his changes.&lt;/p&gt;

&lt;p&gt;So I tried to combine a headless Craft CMS with a frontend written in Next.js with static site generation and working live preview. The data fetching will happen over the new GraphQL API of Craft.&lt;/p&gt;

&lt;p&gt;First of all, you need a working Craft CMS 3.4 installation with activated  GraphQL API. See the &lt;a href="https://docs.craftcms.com/v3/installation.html"&gt;Installation guide&lt;/a&gt; and the GraphQL &lt;a href="https://docs.craftcms.com/v3/graphql.html#getting-started"&gt;Getting Started guide&lt;/a&gt; for instructions.&lt;br&gt;
Then you also need a running Next.js website. See the &lt;a href="https://nextjs.org/docs/getting-started"&gt;Getting Started guide&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Configuration in Next.js
&lt;/h1&gt;

&lt;p&gt;I have implemented everything in TypeScript, so if you use JavaScript, you have to adjust the examples a bit.&lt;/p&gt;

&lt;p&gt;This a simple fetch wrapper to be able to make GraphQL Requests to Craft:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;utils/fetch.ts&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// install with `npm install node-fetch`&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Fetch from Craft GraphQL API
 * @param query GraphQL Query
 * @param previewToken Optional preview token to get draft data
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;previewToken&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;craftUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8888/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;previewToken&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;previewToken&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;craftUrl&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?token=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;previewToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;craftUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the page file, where you want to have SSG with a preview, you have to implement the &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation"&gt;getStaticProps&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;This fetches the data for the Homepage. In my case this is a single section called "Homepage", which has a field named "text".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;pages/index.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetStaticProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`
    {
      entry(title: "Homepage") {
        ... on homepage_homepage_Entry {
          text
        }
      }
    }
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previewData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;previewToken&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;context.previewData.previewToken&lt;/code&gt; data is coming from an API route which is shown below. We only supply the previewToken to the fetch function when the &lt;code&gt;context.preview&lt;/code&gt; field is &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;pages/api/preview.ts&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../utils/fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// (1)&lt;/span&gt;
  &lt;span class="c1"&gt;// Check for the right query params&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-craft-live-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryUid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not allowed to access this route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// (2)&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the url from Craft for the specific entry&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`
      {
        entry(uid: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryUid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;") {
          url
        }
      }
    `&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`URL of the entry "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryUid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" could not be fetched`&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// (3)&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the token as preview data&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setPreviewData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;previewToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// (4)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Redirect to the path from the fetched url&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;307&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parsedUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This function does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The function expects minimum 2 query params in the URL, "x-craft-live-preview" which gets set by Craft automatically in preview mode and "entryUid" so that we have the uid of the currently previewed entry. If they are not present, we will stop the function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We try to fetch the URL of the entry from Craft so that we can redirect to the right page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the query params have a token param, we will set it as preview data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We use the URL of the Entry and redirect to the path (Next.js doesn't like the domain part of the URL)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Configuration in Craft
&lt;/h1&gt;

&lt;p&gt;You have to configure your section (in my case the Homepage section) with a preview URL which points to the previously built preview API endpoint in Next.js (Next.js frontend is running under localhost:3000): &lt;code&gt;http://localhost:3000/api/preview?entryUid={sourceUid}&lt;/code&gt;&lt;br&gt;
It is important to use &lt;code&gt;{sourceUid}&lt;/code&gt; and not &lt;code&gt;{uid}&lt;/code&gt; because the uid could be different in draft entries, but they are not queryable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Et voilà: A static generated homepage, which can show a live preview in Craft whenever you edit the content.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Todos
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;localhost:8888 for the Craft CMS and localhost:3000 for Next.js are hardcoded. This should be configured with .env files.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>craftcms</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
