<?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: Knut Melvær</title>
    <description>The latest articles on DEV Community by Knut Melvær (@kmelve).</description>
    <link>https://dev.to/kmelve</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%2F40916%2Fb65bd736-9b6e-46af-bc6f-9bc930f42752.jpg</url>
      <title>DEV Community: Knut Melvær</title>
      <link>https://dev.to/kmelve</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kmelve"/>
    <language>en</language>
    <item>
      <title>On the limits of MDX</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Thu, 01 Apr 2021 19:09:22 +0000</pubDate>
      <link>https://dev.to/kmelve/on-the-limits-of-mdx-1c8k</link>
      <guid>https://dev.to/kmelve/on-the-limits-of-mdx-1c8k</guid>
      <description>&lt;p&gt;I feel I must preface this with some hedging because I'm about to challenge something that many people seem to love: MDX.&lt;/p&gt;

&lt;p&gt;I have nothing but respect for those who contribute to the MDX ecosystem. Also, I'm totally the type of person that would love MDX. I have been writing in Markdown since 2004, and one of my first GitHub projects was a &lt;a href="https://github.com/kmelve/WordtoMMDfootnotes"&gt;jQuery-based markdown footnotes plugin for Wordpress&lt;/a&gt; (jeez louise don't use this!). At university, I had a whole MultiMarkdown-to-LaTeX setup in &lt;a href="https://www.sublimetext.com/"&gt;Sublime Text&lt;/a&gt; with &lt;a href="https://pandoc.org/"&gt;pandoc&lt;/a&gt;, &lt;a href="http://www.bibtex.org/"&gt;BibTeX&lt;/a&gt;, and PDF preview with &lt;a href="https://skim-app.sourceforge.io/"&gt;Skim&lt;/a&gt; going for me. It was kinda great (at least for the two weeks the setup worked)&lt;/p&gt;

&lt;p&gt;I don't think MDX should be “considered harmful”, nor that everyone should stop using it. But I think there are some things worth considering before locking your, or rather, others’ content to it. And I'm writing this knowing there might be things I've missed or not considered. Feel free to respond to me with your own blog post, or on &lt;a href="https://twitter.com/kmelve"&gt;Twitter&lt;/a&gt;. I don't think this is &lt;a href="https://www.urbandictionary.com/define.php?term=Not%20a%20hill%20I%20want%20to%20die%20on"&gt;the hill I want to die on&lt;/a&gt; though. So I'll allocate no more than 3 hours to follow up on this discussion. Use them wisely.&lt;/p&gt;

&lt;p&gt;With that out of the way. Let's jump into this. 🏊&lt;/p&gt;

&lt;h2&gt;
  
  
  What is MDX?
&lt;/h2&gt;

&lt;p&gt;If you go to &lt;a href="https://mdxjs.com"&gt;mdxjs.com&lt;/a&gt; it self-defines as “an authorable format that lets you seamlessly write JSX in your Markdown documents.” For those not in the know, JSX is “an XML-like syntax extension to ECMAScript without any defined semantics.“ (at least as proposed by the &lt;a href="https://facebook.github.io/jsx/"&gt;draft specification&lt;/a&gt;). In order words, MDX, that is, the MDX precompiler, lets you combine the templating syntax usually found in React.js projects with Markdown. It looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Hello, *world*!&lt;/span&gt;

Below is an example of JSX embedded in Markdown. &lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="ge"&gt;**&lt;/span&gt;Try and change
the background color!&lt;span class="ge"&gt;**&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;padding:&lt;/span&gt; &lt;span class="err"&gt;'20&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;',&lt;/span&gt; &lt;span class="na"&gt;backgroundColor:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;tomato&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;This is JSX&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may look like HTML, because it does, but it's JSX. The intriguing part with MDX, but also the… uhm… problematic part, is that you can do stuff like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;import { Button } from './Button'

&lt;span class="gh"&gt;# Hello world&lt;/span&gt;

Hello, I'm still an mdx file, but now I have a button component!

&lt;span class="nt"&gt;&amp;lt;Button&amp;gt;&lt;/span&gt;Click&lt;span class="nt"&gt;&amp;lt;/Button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(example from the &lt;a href="https://www.docz.site/docs/writing-mdx"&gt;docz.site&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Yep, you can import JSX components and embed them with your run-of-the-mill Markdown prose. If you're documenting your JSX based component library, which is what Docz let you do, this makes all the sense in the world. MDX is also used to author slide decks in &lt;a href="https://github.com/jxnblk/mdx-deck"&gt;mdx-deck&lt;/a&gt;, which is very appealing if you're tired of clicking around in Keynote/PowerPoint/Google Sheets. Which many of us are. I'm not denying the appeal or usability of MDX for certain things for certain people.&lt;/p&gt;

&lt;p&gt;From a React developer’s standpoint that it's used to writing JSX, MDX seems to be touching on the ethos of Markdown, at least as John Gruber, its original creator, introduce it on &lt;a href="https://daringfireball.net/projects/markdown/"&gt;daringfireball.com&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Markdown has always allowed inline and block-level HTML to express things outside of the syntax. Because HTML was the end product. In that way, MDX isn't much different. Markdown's key feature though is "easy-to-read, easy-to-write". I'm not sure if MDX keeps within, or moves away from this general intent.  Gruber made a syntax that was easier to read and write for anyone not familiar with HTML. I'm not convinced that JSX solves the same problem. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is the problem MDX tries to solve?
&lt;/h2&gt;

&lt;p&gt;Markdown was designed at a time where most of the web authoring was still done in HTML. It was also designed when web content was mostly text and images. This isn't the case anymore. Web content has moved towards a much richer set of components, from embeds to interactive code blocks, to between-paragraphs call to action.&lt;/p&gt;

&lt;p&gt;MDX seems like an attempt to make these components available to the author in the same syntax used in frontend development (well, as long as your frontend development uses JSX). And that's pretty much it. I think.&lt;/p&gt;

&lt;p&gt;But this problem has been solved already. With something they call “rich text editors.”&lt;/p&gt;

&lt;p&gt;There's plenty of content platforms with plenty of rich text editors that spew out plenty of different formats, including markdown, HTML, and abstractions as &lt;a href="https://github.com/bustle/mobiledoc-kit"&gt;MobileDoc&lt;/a&gt; and &lt;a href="http://portabletext.org/"&gt;Portable Text&lt;/a&gt;. Medium gained popularity thanks to its smooth authoring experience, &lt;a href="https://notion.so"&gt;Notion&lt;/a&gt; now seems to have taken over that hype. Void of HTML and Markdown (well, markdown-like shortcuts works, but is not a requirement), but with rich embeds. Arguably, these interfaces are more friendly and more accessible than learning Markdown, or MDX.&lt;/p&gt;

&lt;p&gt;There had to be at least one reason for Slacks introduction of a rich text editor, yes, &lt;a href="https://www.vice.com/en_us/article/pa7nbn/slacks-new-rich-text-editor-shows-why-markdown-still-scares-people"&gt;it wasn't very well executed&lt;/a&gt;, and we got Markdown back (I actually got used to the RTE), but I suspect they actually attempted to solve real user experience problems: &lt;em&gt;Not everyone wants to learn Markdown&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hey, I'm writing here!
&lt;/h2&gt;

&lt;p&gt;I have written React for 20 years (that's recruiter for “since 2015”). I should know how to use my keyboard to paint beautiful JSX components with some lovely props and all that. But for some reason, when I have been made to write MDX. It. just. doesn't. work. I mess the syntax up all the time. Forget that I can't actually be writing Markdown inside of an MDX component (without wrapping it in some MDXprovider something). No syntax highlighting (this may have changed at the time you read this). No helpful error to actually point out where I forgot to close that component. Yeah, I know, but I was really supposed to be writing. Not doing debugging of frontend code. &lt;/p&gt;

&lt;p&gt;And yeah… speaking of those components. Most times I had to use MDX, it was to contribute to someone else's documentation. So that means that I had to actually look up a bunch of documentation just to make a code example or a “note”. Sure, I could just &lt;a href="http://www.locusmag.com/Features/2009/01/cory-doctorow-writing-in-age-of.html"&gt;&lt;em&gt;TK'ed&lt;/em&gt;&lt;/a&gt; those parts (and I did), but again, it feels unnecessary for doing something that could be seamlessly solved with a text editor.&lt;/p&gt;

&lt;p&gt;This my totally subjective experience, but for now MDX is introducing a level of friction that I'm not really ok with when I'm writing. Which takes me to the next section. Other people!&lt;/p&gt;

&lt;h2&gt;
  
  
  So, are we expecting people to use this?
&lt;/h2&gt;

&lt;p&gt;I generally have hesitations dividing people into! &lt;a href="https://www.knutmelvaer.no/blog/2020/04/who-are-the-non-technicals/"&gt;“techies” and “non-techies”&lt;/a&gt; (I can be persuaded if you actually identify as a &lt;a href="https://en.wikipedia.org/wiki/Luddite"&gt;Luddite&lt;/a&gt;). But I have been through enough projects as a consultant and have been through enough user tests to be very careful in forcing even Markdown on people who go to work to do content. &lt;strong&gt;Writing with a markup syntax should be opt-in, not forced upon you.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;You expect a person who probably already have too much stuff to do, to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn Markdown&lt;/li&gt;
&lt;li&gt;Then learn MDX/JSX and imports&lt;/li&gt;
&lt;li&gt;Internalize your component system (that never changes, right?)&lt;/li&gt;
&lt;li&gt;Work with plain files&lt;/li&gt;
&lt;li&gt;Use git or whatnot to actually get the stuff where it needs to go&lt;/li&gt;
&lt;li&gt;Ask you how to troubleshoot their texts _when _it gets borked&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sure, you have managed to persuade your client to do it and that's jolly good. But I know that for most people that don't share our coding interests, this will not fly. Not the bit. Also, you're asking them to put their content into a certain format that arguably marries it to presentation. That's probably OK for a slide deck, but less OK if that content is actually describing something of value inside of your organization. &lt;/p&gt;

&lt;p&gt;And it has nothing to do with people being "technical" or not. Most content people I know can spot an apostrophe from a grave accent after two jaegers after a seminar. They know how the syntax works. At least some of the time. It's about what we can reasonably expect people to have to deal with. Should they be learning to write JSX components, when frankly, that's your job?&lt;/p&gt;

&lt;p&gt;“But Knut, I have this client and they love it”. Sure, that's great for you and your client! But now you have another challenge. That client may want their content elsewhere. Or well, redesign their site the year we all do everything in WebGL. Or they just want to switch out their design system with new components. Yes, I know you have an &lt;a href="https://mdxjs.com/advanced/ast"&gt;AST&lt;/a&gt;. But you know what's better than an AST? Not to have to use an AST. &lt;/p&gt;

&lt;p&gt;Because it's not only moving between formats and languages, it's also how you actually structure your content by what it means, and not after the whims of a specific presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can't unmix cake
&lt;/h2&gt;

&lt;p&gt;I work for a &lt;a href="https://www.sanity.io"&gt;company that promotes structured content&lt;/a&gt;, so you should see this coming from a mile away:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For most uses of MDX you will end up mixing specific presentation concerns with your content. This is not great.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yeah, it kinda worked for HTML. Until something called iOS came along. And then you had an icky problem. Sure, you could parse it. But have you ever tried to &lt;a href="https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags"&gt;parse real-world HTML&lt;/a&gt;? You probably rather spend your afternoon on something different. &lt;/p&gt;

&lt;p&gt;For people working with content strategy, content is best stored as ingredients from which you can bake the things that you need when you need it. They have been preaching “structured content” for ages and fighting with CMSes that force content into WYSIWYG page builders and make editors copy-paste their texts around in small layout boxes prisons. &lt;/p&gt;

&lt;p&gt;Yes, technically you can be really semantic with MDX too. Compose your components to be great meaningful abstractions, not get tempted to use that &lt;code&gt;style&lt;/code&gt; attribute, and keep everything neatly separated in their own documents. But there's little in the design and practice of MDX that promotes this use. It is promoted as a way to build rich visual presentations. &lt;/p&gt;

&lt;p&gt;Sometimes you want to make a cake, and that's fine. But you should think really hard if you could feed a lot more people for a lot less effort if you hadn't made the cake in the first place. Ok, this metaphor is pretty tired now. The point is: You should think really hard about how you want to be able to work with your content, the inclinations of whom you want to work with your content, and finally, how sustainable and flexible your structuring of it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obligatory section where I try to sell you our thing
&lt;/h2&gt;

&lt;p&gt;I get it. I get the tangibility of flat files. I get that it feels good to take your coding skills into your prose. But it's not the best way to work with content. Text editors with familiar affordances that produce typed rich text that can be queried and serialized into whatever you need are better. Where developers can define the data structures they need, and editors get easy-to-use tools to get their work done. Like what we're building at &lt;a href="https://www.sanity.io"&gt;Sanity&lt;/a&gt; with &lt;a href="https://www.portabletext.org"&gt;Portable Text&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;But it doesn't even need to be Sanity. After we launched with Portable Text, others have recognized that storing rich text in JSON structures has its advantages. No, you will never want to actually read or author the JSON, but you shouldn't need to. That what's React and JSX is best for: &lt;br&gt;
Building the editorial experiences that don't come in the way of writing. That can be reused across frameworks, programming languages, and redesigns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing remarks
&lt;/h2&gt;

&lt;p&gt;(take a minute to appreciate &lt;a href="https://github.com/mdx-js/mdx/tree/master/packages/remark-mdx"&gt;that subtle pun&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With that out of the way&lt;/em&gt;, let me reiterate that I don't want to belabor the people behind MDX and adjacent technologies. It obviously brings some people joy. You shouldn't feel bad for using it either, but now at least you have some counterpoints to make better decisions from. Maybe someone gets inspired to prove me wrong and make a structured content pattern library for MDX. That would at least be something. Or use some of my aforementioned allocated three hours of discussion time to tell me everything that's wrong with the Portable Text specification (I welcome it actually if it can make it better).&lt;/p&gt;

&lt;p&gt;But do make sure you have considered if MDX solves the problem you really should be solving, or if it only tickles your developer fancy.&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>mdx</category>
      <category>react</category>
      <category>writing</category>
    </item>
    <item>
      <title>Smash your writer’s block with The Hulk Summary™</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Thu, 30 Jan 2020 07:06:23 +0000</pubDate>
      <link>https://dev.to/kmelve/smash-your-writer-s-block-with-the-hulk-summary-cf4</link>
      <guid>https://dev.to/kmelve/smash-your-writer-s-block-with-the-hulk-summary-cf4</guid>
      <description>&lt;ul&gt;
&lt;li&gt;WRITING IS HARD&lt;/li&gt;
&lt;li&gt;YOU THINK TOO MUCH!&lt;/li&gt;
&lt;li&gt;WE HAVE A SOLUTION&lt;/li&gt;
&lt;li&gt;THE HULK SUMMARY!&lt;/li&gt;
&lt;li&gt;CHANNEL INNER HULK VOICE!&lt;/li&gt;
&lt;li&gt;BULLET LIST!&lt;/li&gt;
&lt;li&gt;FEW WORDS&lt;/li&gt;
&lt;li&gt;SAY IT. EFFECTIVE!&lt;/li&gt;
&lt;li&gt;NOW, SMASH CAR!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Look, when you work with content, it’s not always easy to get going. Perhaps you only manage to come up with the same tired clichés, or you’re too close to the product and find yourself knee-deep on a tangent describing how the design choices were inspired by something your uncle said in a birthday party.&lt;/p&gt;

&lt;p&gt;Whatever it is that keeps you from writing that succinct post that presents the what, how, and why to your readers without wasting their time, there is a remedy. We called it “The Hulk Summary”.&lt;/p&gt;

&lt;p&gt;The method is simple. First channel your inner Hulk voice (everyone has one hidden in them somewhere), add a touch of rage and use it to describe whatever you need to get writing on. Hammer down that shift key (caps lock is a cop-out) and type max 4 words for each bullet to capture the core sentiment of what you’re arguing. The constraints will set your mind free.&lt;/p&gt;

&lt;p&gt;You might not find crude shouting methodology enough to tease out the core of what you try to say. I'm happy to announce that The Hulk Summary™ is fully compatible with renowned communication frameworks whose efficiencies are proven by probably too expensive consultancy hours, such as the &lt;a href="https://strategyu.co/scqa-a-framework-for-defining-problems-hypotheses/"&gt;SCQA-model&lt;/a&gt; from &lt;a href="http://www.barbaraminto.com/"&gt;The Minto Pyramid Principle&lt;/a&gt;. Put differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WHAT SITUATION!&lt;/li&gt;
&lt;li&gt;COMPLICATION! DIFFICULTIES!&lt;/li&gt;
&lt;li&gt;I HAVE QUESTION!&lt;/li&gt;
&lt;li&gt;ANSWERS ARE DUE.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This method will most definitively not be developed further. We have loads to things to ship over at sanity.io. But now that it is introduced to a wider audience, we would love to hear your success stories about how it saved your whole content marketing department from writer’s block and pencil fear. Or how you made an interesting friendship from using it as a quirky icebreaker at a gathering. Literally hit us up on &lt;a href="https://twitter.com/kmelve"&gt;Twitter&lt;/a&gt; and let us know, hashtag thehulkmethod.&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;No Banners were hurt in writing this blog post.&lt;/em&gt;)&lt;/p&gt;

</description>
      <category>writing</category>
      <category>productivity</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Ode to LICEcap, the simple GIF screen capture tool</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Sat, 26 Oct 2019 17:28:17 +0000</pubDate>
      <link>https://dev.to/kmelve/ode-to-licecap-the-simple-gif-screen-capture-tool-44cg</link>
      <guid>https://dev.to/kmelve/ode-to-licecap-the-simple-gif-screen-capture-tool-44cg</guid>
      <description>&lt;p&gt;The folks at Apple Computers Inc. really wanted me to upgrade to &lt;a href="https://arstechnica.com/gadgets/2019/10/macos-10-15-catalina-the-ars-technica-review/" rel="noopener noreferrer"&gt;macOS Catalina&lt;/a&gt;, so I did. After having nervously lingered in front of the unmoving progress bar of impending doom for two hours while the upgrade script made sure that all of my millions of node_modules files had the correct sandboxed permissions, I was finally let into my tool of digital self-expression again. Only to discover that the brilliant engineers of Palo Alto had decided that 32-bit apps weren’t in vogue anymore. You know, like reliable keyboards and SD-card slots.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1q29xbjc03rvdys7iu3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1q29xbjc03rvdys7iu3q.png" alt="The 32-bit version of LICEcap can't be opened on macOS Catalina"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not being able to open my beloved LICEcap, prompted me to think of how much I actually use this app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But this post isn’t about how Apple has lost its edge with its &lt;a href="https://goo.gl/maps/QsTYwoDtEozHpMgr7" rel="noopener noreferrer"&gt;new perfect circular new campus&lt;/a&gt;, but about one of my favorite little apps, the GIF screen capture tool &lt;a href="https://www.cockos.com/licecap/" rel="noopener noreferrer"&gt;LICEcap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Not a day goes by without me having to record something I do on the screen. It can be to document some bug I found, show my colleagues at &lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity.io&lt;/a&gt; something cool, a clever tweet, or useful visual context when I’m helping other people out some project. I know you should think twice before putting animated GIFs on your webpage (because they tend to be huge), but I sometimes make that sin too.d&lt;/p&gt;

&lt;p&gt;There are loads of cool screen capture to GIF tools out there. An obvious mention is &lt;a href="https://getkap.co/" rel="noopener noreferrer"&gt;Kap&lt;/a&gt; by &lt;a href="https://github.com/wulkano/kap/graphs/contributors" rel="noopener noreferrer"&gt;these wonderful people&lt;/a&gt;. It does a lot more than LICEcap, and is even written in the world-eating JavaScript programming language. In fact, I used it to screen capture how LICEcap works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cdn.sanity.io/images/ndjrels0/production/ffbaa72d85ee1494b1d7b885f3275e97ac46d1b2-1008x942.gif" rel="noopener noreferrer"&gt;Click to see how it works&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Using LICEcap to record some interesting free coding.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But the reason I’m always reaching for LICEcap when I need those moving pixels captured is that it records directly to the file. No post-processing. Apparently, that is a killer feature. Being able to quickly do the screen capture and have the GIF ready for sharing in the instant you stop the recording is really convenient. Turns out, convenience trumps feature lists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsrfq11pby0517pgekt7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsrfq11pby0517pgekt7p.png" alt="The few recording options for LICEcap."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not a lot of bells and whistles​, but enough in most cases.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ICEcap doesn’t have a bunch of options and settings. But that’s fine for most parts. If I need more, that usually means that I should do the recording with something like &lt;a href="http://www.telestream.net/screenflow/overview.htm" rel="noopener noreferrer"&gt;ScreenFlow&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;I actually thought my days with LICEcap were over, but writing this post made me discover that a 64-bit version has been out since February 2018, so shame on me.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Doing some minimal amounts of research for this post, I also discovered that LICEcap’s developer is &lt;a href="https://en.wikipedia.org/wiki/Justin_Frankel" rel="noopener noreferrer"&gt;Justin Frankel of Winamp fame&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>10x engineers and my approach to Twitter</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Mon, 15 Jul 2019 22:00:00 +0000</pubDate>
      <link>https://dev.to/kmelve/10x-engineers-and-my-approach-to-twitter-3o92</link>
      <guid>https://dev.to/kmelve/10x-engineers-and-my-approach-to-twitter-3o92</guid>
      <description>&lt;p&gt;You're probably a bit tired of the whole 10x engineer thing by now, but this post isn't really about that. It is about what I learned from it and how I’m reconsidering my approach to Twitter.&lt;/p&gt;

&lt;h2&gt;
  
  
  10x what? Context, please.
&lt;/h2&gt;

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

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



&lt;/p&gt;

&lt;p&gt;Investor Shekar Kirani recently posted a thread on Twitter about the traits to an alleged type of engineers/programmers. I think it's safe to say that they are a combination of stereotypes that many people find toxic and problematic in a work environment. The ethos of the tweet seems to be that there are these people that don't fit in with the normal expectations of the workplace (“they don’t like meetings” etc), but will be these efficient, high performing workers that will give you, the founder, an advantage in the race that is product development.&lt;/p&gt;

&lt;p&gt;I'll leave it to others to rebuke each and every argument in this thread (just dive into the replies to get an idea), but let me just point out that the best coders I know have tended to be really nice people that have happily shared their knowledge, gone to meetings, had family obligations, and all sorts of desktop backgrounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  I piled some wood on the bonfire
&lt;/h2&gt;

&lt;p&gt;So Shekar’s tweets struck a nerve and the reactions were plentiful. People were tired by the whole 10x thing before two hours had gone. The sentiment among the outspoken programmers and tech people were pretty unified against the idea that the profile the tweets painted had any basis in reality, and were a collection of traits that had no business being in tech or a workplace. There were also worry that these tweets rehearsed and perpetrated ideas that are shared among founders and investors. Some of the generalizations also made it really easy to mock and satirize the Twitter-thread.&lt;/p&gt;

&lt;p&gt;As I've written before, I'm sometimes tempted to do the hot take or go for the satirical smartass comment on Twitter. Shekar’s thread got to me, both because here was this investor promoting something I deeply disagree with, but also because it seemed so out of place to do so in an environment that's just ready to pile on people that seemingly work against making tech a healthier and more inclusive place.&lt;/p&gt;

&lt;p&gt;So I tweeted something to the effect that I think it's weird that an investor would say these things publicly, and should have known the response it would get. It simply doesn't seem like a strategic move, even though if one means it. Only I choose to put emphasis on what these tweets said about Shekar as a person, and by “quote tweeting” him. Making the recipients my audience, and engaging him directly.&lt;/p&gt;

&lt;p&gt;I got my likes and replies and moved on with the day. I was one of many hundreds, if not more, that more or less mocking wrote Shekar and his thread off. As one does on Twitter, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this the person I want to be?
&lt;/h2&gt;

&lt;p&gt;And then I got some feedback. A person, whose opinions I care about, told me that I came off arrogant and with little respect to a person I disagreed with, who I didn’t know, on the basis on some tweets. My first reaction was to become a bit annoyed. I just did what you do on Twitter, right? Here's this investor saying outrageous stuff, and I was sticking it to the man. But then I had to reconsider the critique because it came from a place of concern.&lt;/p&gt;

&lt;p&gt;I don't know Shekar. I don't know much about the context he's working on in India. But I know that the respect and humanity I found lacking in the ideas behind his tweets were a bit lacking in mine as well. I didn't tweet what I did because I hoped to change anyone's mind or educate them.&lt;/p&gt;

&lt;p&gt;I tweeted what I did because I wanted to look smart and part of “good team“. I was virtue signaling. And doing so by throwing timber on a bonfire to a person that probably didn't expect how this thread would blow up. That's not a person I want to be, and I don't think I really was helping promote the ideas and practices we so dearly want in tech.&lt;/p&gt;

&lt;p&gt;So I deleted my tweets.&lt;/p&gt;

&lt;h2&gt;
  
  
  I’m not done thinking about how I approach Twitter
&lt;/h2&gt;

&lt;p&gt;My reconsideration of how I approach Twitter can easily be read as a value judgment of others’ satirical or mocking replies to Shekar’s tweets. This is where I’m ambivalent. Because I do mean and appreciate that there is a place of satire, humor, and jestful creativity to counter destructive ideas put forth by people in power. The site &lt;a href="https://1x.engineer/" rel="noopener noreferrer"&gt;1x Engineer&lt;/a&gt; is a good example of this.&lt;/p&gt;

&lt;p&gt;There’s also another side of this, which is that of privilege. I have, as a Norwegian guy in my early 30s, very little reason to feel particularly angry or hurt based on my experiences growing up in one of the safest environments on this planet. But other people have plenty of good reasons to feel and express both.&lt;/p&gt;

&lt;p&gt;That’s why I explicitly am framing these thoughts as the reevaluation I’ve done for my own behavior, and put them here in a way to think loudly in public, and to hold my self accountable. So this is how I'll try to approach critique on the web going forward. And frankly, most of these points are not original and have been made by many others before me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'll consider that I’m responding to a real person.&lt;/li&gt;
&lt;li&gt;I’ll comment on the actions and ideas represented in the tweets.&lt;/li&gt;
&lt;li&gt;I’ll consider that the person may have English as a secondary language (as I do), and are not aware of nuances and the implications that certain word choices may have.&lt;/li&gt;
&lt;li&gt;I’ll consider what I want to achieve: Is it providing nuance or reconsideration? Is it just blowing off steam? Is it marking a stance?&lt;/li&gt;
&lt;li&gt;I will to the best of my ability, try to make it possible for the person to reconsider, or engage me in a discussion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I believe I know what you’re thinking: What about trolls and people with extreme and hurtful opinions? I don’t really think all people on Twitter is there for “enlightened discourse”, which the points above are aiming for. And obviously, many people know what they’re doing when they say hurtful stuff. As for now, I’ll probably not grant them much of my attention and counter with promoting ideas and activities that make tech a safer and more inclusive (for example, &lt;a href="https://www.knutmelvaer.no/blog/2018/09/making-tech-survivable-what-can-men-do/" rel="noopener noreferrer"&gt;Making tech surviveable: What can men do?&lt;/a&gt;).&lt;/p&gt;




&lt;p&gt;Is there something I have failed to consider here? Did this make you think about how you use Twitter? I’d love to hear about it!&lt;/p&gt;

</description>
      <category>healthydebate</category>
    </item>
    <item>
      <title>A year in developer relations</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Fri, 05 Jul 2019 07:00:00 +0000</pubDate>
      <link>https://dev.to/kmelve/a-year-in-developer-relations-2m72</link>
      <guid>https://dev.to/kmelve/a-year-in-developer-relations-2m72</guid>
      <description>&lt;p&gt;Here are my learnings based on my first year running developer relations at Sanity.io. I guess they are rather obvious, but I think they’re worth sharing as they can be helpful for someone starting with developer relations/advocacy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Cover Image: I was a fan of Syntax.fm’s Scott &amp;amp; Wes before I became a developer advocate. Here I got to meet them at JAMstack_conf San Francisco in 2018.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve been in developer relations for about a year now. Actually, I’ve only &lt;em&gt;known&lt;/em&gt; that “develop relations” and “developer advocate” have been specific things for that long. The first time I consciously encountered these titles was when I was offered the role as "Head of developer relations" with my current job at &lt;a href="https://www.sanity.io"&gt;Sanity.io&lt;/a&gt;. It seemed to encapsulate with what I could contribute with.&lt;/p&gt;

&lt;p&gt;Even though I had never worn such titles before, I had experience in teaching, mentoring, and dissemination, and I had been promoting aspiring developers before. I have a lot of training from teaching theory and methodology at University, I have run web development courses for retirees and beginners, and I have been writing about technology for a long time. I just didn’t know that that was a dedicated job in tech, and not the least, &lt;a href="https://thenewstack.io/devrel-and-the-increasing-popularity-of-the-developer-advocate/"&gt;a “scene”&lt;/a&gt;. With T-shirts, stickers, &lt;a href="https://www.amazon.com/Business-Value-Developer-Relations-Communities/dp/1484237471"&gt;books&lt;/a&gt;, and &lt;a href="https://devrelcollective.fun/"&gt;Slack groups&lt;/a&gt;. With the title, I was also joining a community and a discourse.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Find yourself a team that cares
&lt;/h2&gt;

&lt;p&gt;I joined Sanity when they mostly were the developers from the original &lt;a href="https://bengler.no"&gt;Bengler&lt;/a&gt; team. They made the platform because they wanted a real-time content backend for &lt;a href="https://www.oma.eu"&gt;OMA’s website&lt;/a&gt;. In 2017, they converted Bengler into a startup for Sanity. Since I joined, I had to figure out how to do the developer relations part, but also contribute to how we should communicate Sanity in general. I’m very fortunate to be working with some fantastic people, both in terms of talent and experience, who also give an excellent mix of constructive feedback and praise.&lt;/p&gt;

&lt;p&gt;That’s perhaps the most crucial part of what motivates me as a developer advocate: It's much more fun when you and your colleagues feel that there’s a stake, that there‘re care and attention given to almost every detail of what we do. I get the sense that we have made this cool thing that we want people to use, because we think it makes their day better, and they will make cool things with it. If you want to work as a developer advocate, be on the lookout of a team that cares. It’s easy enough to forget if the product has a cool flair, or the perks are awesome.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Learn to take feedback
&lt;/h2&gt;

&lt;p&gt;That stake, and care, comes with a challenging side too. There will be a lot of opinions, inclinations, ideas, and feedback on whatever you do. The feedback may even be conflicting or just not feasible to follow up. Your job is to mediate the feedback that you get within the company, with that you get outside, and turn it into something constructive and actionable.&lt;/p&gt;

&lt;p&gt;I try my best to communicate why we are doing what we do in the weekly all-staff meetings. I also make sure to include nice things people have said about our work to remind the team that they’re doing work that's appreciated by real people. That's the “relations” part of the job.&lt;/p&gt;

&lt;p&gt;I give much consideration to the feedback I get from my colleagues, but I don’t always follow it. That's partly having to follow my gut-feelings from all the impressions and observations I've, being "out there", and partly because the advice you're given is for inaction (“We shouldn't do x, y, z”).&lt;/p&gt;

&lt;p&gt;I remember that we had a lot of discussion and indecisiveness around creating a new developer community. All the services had drawbacks for sure. My job then was just to pick something, and get it going. So I did. A year after we’re over 1.100 developers in &lt;a href="https://slack.sanity.io"&gt;our Slack&lt;/a&gt;. Yes, the message retention sucks, yes, it would have been handy to have all our answers indexed by Google. At the same time, the feedback, enthusiasm, and all the questions have been invaluable. We don’t regret it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Talk less, listen more
&lt;/h2&gt;

&lt;p&gt;Speaking of the community Slack. I also remember being super worried about trolls and people that would object to our &lt;a href="https://github.com/sanity-io/sanity/blob/next/CODE_OF_CONDUCT.md"&gt;Code of Conduct&lt;/a&gt;. It’s super interesting to see that many of us in tech are occupied with figuring out how we can make sure that people feel welcome, included, and safe. Since I became more aware of people’s shitty experiences, and my own mostly hassle-free experience in tech, I must admit that I many times have been afraid of inadvertently saying something that may cause someone discomfort.&lt;/p&gt;

&lt;p&gt;Because I used(?) to be much more of a "here’s my five cents”-guy on Twitter and such (well 600 words in, I guess I still kinda am), but I have consciously abstained from posting and replying to stuff that may have irritated me. I use two thought technologies (which I picked up from the &lt;a href="http://5by5.tv/b2w/"&gt;Back to Work podcast&lt;/a&gt;). The first is saying out loud: "I will not let this bother me." The second is to question "Is this the hill I want to die on?". They actually work — most of the time.&lt;/p&gt;

&lt;p&gt;Instead of being such a smart ass, I have been trying to observe and listen instead. It is something I still work on being better at. I have been listening in two ways. First, I have made sure to follow a more diverse cast of people, and I have been trying to take in the stories of those who display concerns about the inclusiveness of tech. I’ve also tried to &lt;a href="https://www.knutmelvaer.no/blog/2018/09/making-tech-survivable-what-can-men-do/"&gt;contribute with some thoughts&lt;/a&gt; and took part in organizing &lt;a href="https://www.globaldiversitycfpday.com/events/91"&gt;Global Diversity Call For Papers Day&lt;/a&gt;. And it has been humbling. And frankly, it’s nice not being the one offering the hot take or glib tweet (well, there’s still some occasional ones).&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Learn how to take time off
&lt;/h2&gt;

&lt;p&gt;Honestly, I’m still rubbish at this. So I write this as much as advice for myself as for you. Thing is, there’s an infinite amount of tasks you can do as developer advocate: there’s always another talk proposal, demo, blog, or some documentation you could improve. There are always people that need help with something. So you have to draw some lines. Now, it’s hard to offer exactly what those lines should be because it also is highly dependent on where you live, whom you live with, if you have a family, how old you are, etc.&lt;/p&gt;

&lt;p&gt;I’m fortunate in having gotten professional help for recurring depressions, and have mostly figured out how to live with it (&lt;a href="https://en.wikipedia.org/wiki/Cognitive_behavioral_therapy"&gt;CBT&lt;/a&gt; worked for me). I’ve been through a burn-out experience when I did my Ph.D. studies at University and got into tech after that – where I felt much more at home. I’m also fortunate in having a spouse that rides dressage. I often tag along to the stables to get some honest off-screen time with our two horses and help her out with grooming, and the many tasks and sorts that you have to do there. I also do my best to get some exercise, jogging and such. Doing something completely different seems essential.&lt;/p&gt;

&lt;p&gt;Taking time off is partly on you, but having a workplace that understands that highly motivated people often need help with setting boundaries and be reminded that they need to take time off to not burn out at the office, is important as well. We’re regularly reminded of this at Sanity, and we’re trying to build structures (everything from how projects are planned, to setting expectations) that enable and ensure this as well.&lt;/p&gt;

&lt;p&gt;I also think it’s vital for us that has the roles of being a developer advocate to communicate this as well, and to our own discretion share those part of the daily life. It's easy enough to feed into people’s impostor syndromes and impression that you have to work all the time to belong in tech.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Take it seriously, but don’t be too serious
&lt;/h2&gt;

&lt;p&gt;As a developer advocate you do an important job. You’re both responsible that other people are successful at what they try to do, and on relaying back to your team what you learn. You are inevitably tied to your workplace and — excuse the marketing term — its brand. If you are approachable and helpful, that will contribute a lot to your company’s success. Even if I had put “opinions are my own” in my twitter bio, my behavior will reflect something back on people’s impression of Sanity, and the work being done there. So I owe to my team to be mindful of how I act and communicate. This position is very different from coming from the Humanities, where you are much more your own agent (at least, this was the case where I was studying).&lt;/p&gt;

&lt;p&gt;This connection that you have with your workplace, and the fact, let's be honest, that much of what you’re doing can fall in under the term marketing, also means that people will have certain reasonable expectations of your biases. The serious part is not trying to be coy with whom and what you are representing, and be transparent when you’re discussing things where you obviously have an interest if promoting whatever you do.&lt;/p&gt;

&lt;p&gt;At the same time, you are also a person with all the flaws and particularities that comes with that. Sometimes, people will say disparaging things about whatever you’re working on. Or they will dismiss you as a just a biased representative of where you work. That is the time where you shouldn’t be tempted to go into arguments or make a big fuzz. Try to distill whatever legit criticism can be found, and move on.&lt;/p&gt;




&lt;p&gt;Being a developer advocate is probably the most exciting job I have ever had. The range of different things you can do and the people you encounter is ideal if you’re motivated by learning new things and are excited by learning what other people are creating. It has been an absolute blast being part of launching the developer community for Sanity, and we have a pretty interesting year ahead of us opening a new office in San Francisco, hiring more people, and preparing for the next step.&lt;/p&gt;

&lt;p&gt;I look forward to looking back at the coming year with a new blog post like this. Stay tuned (e.g., by &lt;a href="https://www.knutmelvaer.no/rss.xml"&gt;subscribing to the RSS feed&lt;/a&gt;)!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>career</category>
    </item>
    <item>
      <title>Getting started with Webmentions in Gatsby</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Mon, 24 Jun 2019 10:00:00 +0000</pubDate>
      <link>https://dev.to/kmelve/getting-started-with-webmentions-in-gatsby-15e7</link>
      <guid>https://dev.to/kmelve/getting-started-with-webmentions-in-gatsby-15e7</guid>
      <description>&lt;p&gt;I have been curious to learn more about webmentions and the &lt;a href="https://indieweb.org" rel="noopener noreferrer"&gt;IndieWeb&lt;/a&gt; for a while now. Putting together my new blog seemed like an excellent opportunity to learn more about it. So keep in mind that I’m pretty new to this stuff, and just sharing my learning process as I go along. This is at least a short tutorial to how to get started with making your site webmentions friendly, how to connect them with twitter, start retrieving them with &lt;a href="https://www.gatsbyjs.org" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt;, and how to trigger rebuilds on &lt;a href="https://netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; when new mentions come in. I’ll revisit how to send them in a later tutorial.&lt;/p&gt;

&lt;p&gt;I got started on my webmentions journey by reading Chris’ &lt;a href="https://www.christopherbiscardi.com/post/building-gatsby-plugin-webmentions" rel="noopener noreferrer"&gt;&lt;em&gt;Building Gatsby Plugin Webmentions&lt;/em&gt;&lt;/a&gt; and Chad’s &lt;em&gt;&lt;a href="https://www.chadly.net/embracing-the-indieweb/" rel="noopener noreferrer"&gt;Embracing the IndieWeb&lt;/a&gt;.&lt;/em&gt; Both works were helpful to get started, but they left some details out that may have made it a bit easier to grok. I’ll walk you through all the steps, but do check out their stuff as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Webmentions?
&lt;/h2&gt;

&lt;p&gt;You can read more about it on the &lt;a href="https://indieweb.org/Webmention" rel="noopener noreferrer"&gt;IndieWeb wiki&lt;/a&gt;, but shortly put: Webmentions is an open source project and a service to send and receive messages and pingbacks between sites. Like we all did with Wordpress back in the day.&lt;/p&gt;

&lt;p&gt;The difference are that Webmentions are federated, meaning that you can collect and send mentions from multiple sources. In this tutorial, I’ll start by pulling in twitter mentions via a service called &lt;a href="https://brid.gy" rel="noopener noreferrer"&gt;brid.gy&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get started with Webmentions
&lt;/h2&gt;

&lt;p&gt;To get started with Webmentions you need to sign in on webmention.io. And to sign in you need to authenticate. And to authenticate you need to put some markup on your Gatsby site that tells webmention.io which service it can use. As per instructions you can add the following using either Twitter, GitHub, email, your PGP key, or you own IndieAuth server. I added Twitter and Github:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  Follow &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-card"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"me"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.knutmelvaer.no/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Knut&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; on &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;'https://twitter.com/kmelve'&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;'me'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Twitter (@kmelve)&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;, &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;'https://github.com/kmelve'&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;'me'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;GitHub&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;, or send him an &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"u-email"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;'mailto:knut.melvaer@gmail.com'&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;'me'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;email&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this pretty much looks like your regular piece of HTML. If you look a little closer there is some &lt;code&gt;rel="me"&lt;/code&gt; attribute as well as some class names (&lt;code&gt;h-card&lt;/code&gt;, &lt;code&gt;u-email&lt;/code&gt;). These are microformats (TK), which is an important part of getting webmentions to work. When you publish your site with this markup, you tell webmention that those social accounts are tied to whomever is control of the domain the site is on, and lets you log in via their oAuth-integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fndjrels0%2Fproduction%2Fcdd3356565f50c8c9ce5301a409ee336406dcf8f-1071x874.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fndjrels0%2Fproduction%2Fcdd3356565f50c8c9ce5301a409ee336406dcf8f-1071x874.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the figure above, I have a list of webmentions there that you probably don’t have (yet). We’ll return to how to get that list populated with stuff from twitter, but first, we have to add some microformats to our site, to make it webmention friendly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding microformats2 to your posts
&lt;/h2&gt;

&lt;p&gt;Webmentions use a specification called &lt;a href="http://microformats.org/wiki/h-card" rel="noopener noreferrer"&gt;microformats2&lt;/a&gt; to make sense of contents on a webpage. We’ve already started implementing it in the code snippet above. There’s a lot to microformats that I haven’t unpacked for myself yet, but it’s easy enough to get started. You mainly do so by adding some specified class names to HTML elements that have the specific content that webmention use to populate its fields. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"u-photo"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"http://..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;The Title&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-summary e-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;The summary&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"u-url p-name"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"http://..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;The author&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use &lt;a href="https://indiewebify.me/" rel="noopener noreferrer"&gt;IndieWebify.me&lt;/a&gt; or &lt;a href="https://pin13.net/mf2/" rel="noopener noreferrer"&gt;pin13.net&lt;/a&gt; to validate your markup. I took a couple of tries for me to get it right. When a webmention service read your page, it will parse the HTML and extract this information into a JSON structure, that may look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"h-card"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"The Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"The author"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"The summary"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"photo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"http://..."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"http://..."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"html"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The summary"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rel-urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ended up implementing these “microformated” elements in my post template and hiding them with &lt;code&gt;display: none&lt;/code&gt;. Mainly because I didn’t want an &lt;a href="https://en.wikipedia.org/wiki/ISO_8601" rel="noopener noreferrer"&gt;ISO8601 formatted datetime&lt;/a&gt; stamp visible on the site. I could probably have used a library like &lt;a href="https://date-fns.org/" rel="noopener noreferrer"&gt;date-fns&lt;/a&gt; to format the timestamp, but this did the trick without any dependencies. This is for example how it looks in my Gatsby blog’s React code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;time&lt;/span&gt; 
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; dt-published&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
  &lt;span class="na"&gt;itemprop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"datepublished"&lt;/span&gt; 
  &lt;span class="na"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Z&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="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+01:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;time&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s head over to the interesting part, namely, getting webmentions into Gatsby.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing &lt;code&gt;gatsby-plugin-webmention&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The easiest way to get webmentions into a Gatsby site is to install the gatsby-plugin-webmention plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install gatsby-plugin-webmention
# or
yarn add gatsby-plugin-webmention
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can add the following config to the &lt;code&gt;plugins&lt;/code&gt; array in &lt;code&gt;gatsby-config.js&lt;/code&gt; (obviously replacing my information with your own):&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-plugin-webmention`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;www.knutmelvaer.no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// webmention.io username&lt;/span&gt;
    &lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;github&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kmelve&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kmelve&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// no @&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;mentions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;pingbacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;www.knutmelvaer.no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WEBMENTIONS_TOKEN&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 webmentions token is the one that you find under "API key" when you’re logged into &lt;a href="https://webmention.io/settings" rel="noopener noreferrer"&gt;https://webmention.io/settings&lt;/a&gt;. Remember to also add it to the environment where you build your Gatsby site to production (&lt;a href="https://www.netlify.com/docs/continuous-deployment/#environment-variables" rel="noopener noreferrer"&gt;for example on Netlify&lt;/a&gt;). If all went well, you’ll be able to query your webmentions in the Gatsby GraphQL API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fndjrels0%2Fproduction%2Fd0993e90b5e5cb536f054433a3f96d81f364f873-2642x1606.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fndjrels0%2Fproduction%2Fd0993e90b5e5cb536f054433a3f96d81f364f873-2642x1606.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to get page specific webmentions I did two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate and put the post’s URL into &lt;a href="https://www.gatsbyjs.org/docs/creating-and-modifying-pages/#pass-context-to-pages" rel="noopener noreferrer"&gt;&lt;code&gt;context&lt;/code&gt;&lt;/a&gt; from &lt;code&gt;gatsby-node.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Filter the allWebMentionEntry with the URL aka "the permalink"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’s probably a handful of ways to do this, but I ended up with just generating the full URL in gatsby-node.js, and passing it in via context, so that I could use it as a query param:&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="nx"&gt;postEdges&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isFuture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;publishedAt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateSegment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YYYY/MM&lt;/span&gt;&lt;span class="dl"&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dateSegment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/`&lt;/span&gt;

    &lt;span class="nf"&gt;createPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/templates/blog-post.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;permalink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://www.knutmelvaer.no&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;createPageDependency&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&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;And the GraphQL query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;allWebMentionEntry(filter: {wmTarget: {eq: $permalink}}) {
  edges {
    node {
      wmTarget
      wmSource
      wmProperty
      wmId
      type
      url
      likeOf
      author {
        url
        type
        photo
        name
      }
      content {
        text
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The properties of this query will be pretty self-explanatory when you start to get webmentions data. You can use it to list people who have liked, replied, or reposted your post.&lt;/p&gt;

&lt;p&gt;The simplest way to get some webmentions going is to use a service called brid.gy to bring in mentions of your website on Twitter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting brid.gy
&lt;/h2&gt;

&lt;p&gt;Head over to &lt;a href="https://brid.gy" rel="noopener noreferrer"&gt;brid.gy&lt;/a&gt; and connect your accounts, I think Twitter makes the most sense, at least at first. Enable the listening for responses. There need to be some tweets that mention your site (by domain name) to there being responses. You can, of course, just tweet your self to get something going.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fndjrels0%2Fproduction%2Fb7e4f7cbe80c2aee6a56866248f41e49c8d3e937-2588x1706.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fndjrels0%2Fproduction%2Fb7e4f7cbe80c2aee6a56866248f41e49c8d3e937-2588x1706.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you (re)start your Gatsby site in dev mode, you’ll be able to see the same response data in your GraphQL layer. This will make it a bit easier to implement in your frontend template.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing webmentions in your Gatsby frontend
&lt;/h2&gt;

&lt;p&gt;I’m not going to cover much detail here, this is the creative part! It’s pretty much straight forward though. For example, to filter out all the "likes" and show some avatars with links to the "liker", you can do something along these lines (not saying that this is the definitive way to do it):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WebMentions&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;edges&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;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;node&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;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wmProperty&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;like-of&lt;/span&gt;&lt;span class="dl"&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;likeAuthors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&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;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;wmId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wmId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; likes`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;likeAuthors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;photo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wmId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use this component where you query for webmentions, by sending the &lt;code&gt;allWebMentionEntry&lt;/code&gt; object into it &lt;code&gt;&amp;lt;WebMentions {...allWebmentionEntry} /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Triggering a new build on a new mention
&lt;/h2&gt;

&lt;p&gt;If you’re like me, you’re impatient and want new mentions to appear when they happen. If you are patient, you can be satisfied by having the new mentions appear whenever you rebuild your site. But if you host your Gatsby site with let's say Netlify, you can use a build trigger to automatically rebuild the site, querying the newest mentions. First, you’ll have to add a new &lt;a href="https://www.netlify.com/docs/webhooks/#incoming-webhooks" rel="noopener noreferrer"&gt;build trigger&lt;/a&gt; on Netlify. Copy this, and head over to &lt;a href="https://webmention.io/settings/webhooks" rel="noopener noreferrer"&gt;the webhooks settings&lt;/a&gt; on Webmentions. Paste the Netlify URL into the box (no secret is needed), and hit save. And that’s it! (I realize that we can do some interesting things with this webhook, but we’ll revisit that in a later post.)&lt;/p&gt;

&lt;p&gt;I would also recommend setting up some build notifications on Netlify so that you can keep an eye. Especially if you’re actually putting some content from the webmentions on to your site. This would be the time I told you that you can delete webmentions, and add someone to your blocklist if this is needed. Hopefully, it will not though.&lt;/p&gt;

&lt;h2&gt;
  
  
  Congratulations, you’re now a bit more indie!
&lt;/h2&gt;

&lt;p&gt;There’re still some pieces left to the puzzle. We haven’t set our site to send webmentions or pingbacks yet. And there are more sources than Twitter that we can draw from. I’ll surely return with more fun IndieWeb + Webmentions stuff though. Meanwhile, feel free to reply to me on twitter, or even try webmentioning this post if you have constructive feedback. I’ll happily amend this post and follow up with useful insights.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>indieweb</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to quickly set up a Gatsby.js JAMstack website with a headless CMS</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Wed, 23 Jan 2019 23:00:00 +0000</pubDate>
      <link>https://dev.to/kmelve/how-to-quickly-set-up-a-gatsbyjs-jamstack-website-with-a-headless-cms-4inh</link>
      <guid>https://dev.to/kmelve/how-to-quickly-set-up-a-gatsbyjs-jamstack-website-with-a-headless-cms-4inh</guid>
      <description>&lt;p&gt;In January 2019, we &lt;a href="https://www.sanity.io/blog/get-started-with-gatsby-and-structured-content" rel="noopener noreferrer"&gt;released a new source&lt;/a&gt; plugin that makes it easy to use Sanity as a headless CMS for a JAMstack website built with Gatsby.js. It's pretty easy to install and integrate with exciting projects on Gatsby. If you're new to the static site generator, or want to test the plugin out, we made &lt;a href="https://github.com/sanity-io/example-company-website-gatsby-sanity-combo" rel="noopener noreferrer"&gt;a full company website and a headless CMS example&lt;/a&gt;, with people, projects, a blog, and some info pages. In this tutorial we'll show how to set it up, and how to run Gatsby in development mode on a web server, to get a real-time online preview of content changes. &lt;/p&gt;

&lt;p&gt;The example is a monorepo, containing both the configuration for Sanity Studio, where you'll be editing content, and the Gatsby built website. It's also configured to be deployed straight onto &lt;a href="https://netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; or &lt;a href="https://zeit.co/now" rel="noopener noreferrer"&gt;Now&lt;/a&gt;. You can create a new free Sanity project within it, and be up and running in minutes. Web development in the age of &lt;a href="https://jamstack.org/" rel="noopener noreferrer"&gt;JAMstack&lt;/a&gt; is truly fantastic!&lt;/p&gt;

&lt;p&gt;We feel safe that you can take our company website example, and make it your own. &lt;/p&gt;

&lt;h2&gt;
  
  
  Clone or fork the repository on Github
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://github.com/sanity-io/example-company-website-gatsby-sanity-combo" rel="noopener noreferrer"&gt;example repository on GitHub&lt;/a&gt; and clone, or fork it from there. You can also run this in your terminal in the folder you keep your web-projects (replace the URL with your own if you forked the project):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    git clone https://github.com/sanity-io/example-company-website-gatsby-sanity-combo.git
    &lt;span class="nb"&gt;cd &lt;/span&gt;example-company-website-gatsby-sanity-combo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install the Sanity CLI
&lt;/h2&gt;

&lt;p&gt;It's convenient to have the Sanity CLI when working with projects like this, and it doesn't take long to install. Run the following npm command in the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; @sanity/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install dependencies
&lt;/h2&gt;

&lt;p&gt;This example use &lt;a href="https://npmjs.com" rel="noopener noreferrer"&gt;node package manager&lt;/a&gt; (&lt;code&gt;npm&lt;/code&gt;) for dependencies, you can also use yarn if you prefer that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo
    npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up Sanity.io as a headless CMS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo
    npm run init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this command after the install script is finished. Follow the CLI's instructions to create a Sanity.io project for the website. We recommend setting the dataset to &lt;strong&gt;public&lt;/strong&gt; (you can change it to private afterward if you prefer). A &lt;strong&gt;dataset&lt;/strong&gt; is where all you store all your content, kind of like a database. You can have more than one dataset. For example, if you want a content test bed for development.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;npm run init&lt;/code&gt; command also deploys a GraphQL API for your Sanity project (Sanity supports both &lt;a href="https://www.sanity.io/docs/reference/groq" rel="noopener noreferrer"&gt;GROQ&lt;/a&gt; and GraphQL). The Gatsby source plugin for Sanity uses the GraphQL schema definition to prevent types and fields missing from Gatsby's templating API. As far as we know, this is the only plugin that helps you with that – it's pretty practical!&lt;/p&gt;

&lt;h2&gt;
  
  
  Start the local development server
&lt;/h2&gt;

&lt;p&gt;In your project folder you have two folders: &lt;code&gt;studio&lt;/code&gt; and &lt;code&gt;web&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The studio folder is where you'll find the configuration files for the Sanity Studio, which is an open source editor for your content, built with JavaScript and React. It connects to the hosted API and is real-time, like you have in Google Docs. You can host the Studio anywhere you can host an HTML-file. In the &lt;code&gt;studio/schema&lt;/code&gt; folder you'll find the configuration files for all the types and fields. You can tweak and change these later if you want to, but we'll let them be for now. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;web&lt;/code&gt; folder holds a Gatsby website, with everything you need set up to render the content managed with Sanity. If you're new to Gatsby, we recommend their &lt;a href="https://www.gatsbyjs.org/docs/" rel="noopener noreferrer"&gt;comprehensive documentation&lt;/a&gt; to learn the basic ideas.&lt;/p&gt;

&lt;p&gt;You can start both development servers for the Studio and the Gatsby frontend with a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
    ~/example-company-website-gatsby-sanity-combo
    npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The studio runs on &lt;a href="http://localhost:3333" rel="noopener noreferrer"&gt;localhost:3333&lt;/a&gt;, and the website on &lt;a href="http://locahost:8000" rel="noopener noreferrer"&gt;localhost:8000&lt;/a&gt;. If you open the website you'll be met with an error message. That's because it needs some content to build. So start by opening the studio and log in. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F476ae6eb772c1ce97e0515fb0bfd1cfe28c41f32-2196x1952.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F476ae6eb772c1ce97e0515fb0bfd1cfe28c41f32-2196x1952.png" alt="Company Info in Sanity Studio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="http://localhost:3333/desk/siteSettings" rel="noopener noreferrer"&gt;Site Settings&lt;/a&gt; and &lt;a href="http://localhost:3333/desk/companyInfo" rel="noopener noreferrer"&gt;Company Settings&lt;/a&gt; and fill in at least the names. Make a blog post (just some mock content is fine), a project, and some of the other stuff as well. You should give both your blog- and project entries a &lt;strong&gt;title&lt;/strong&gt;, a &lt;strong&gt;slug&lt;/strong&gt; and preferably a &lt;strong&gt;Published at&lt;/strong&gt; date (in the past). Remember to publish the changes (the blue button down left). Although all changes instantly sync with the hosted backend, they won't appear in the public API without being published.&lt;/p&gt;

&lt;p&gt;Now you probably need to restart the development server, to get Gatsby to build with the new changes. &lt;code&gt;ctrl + C&lt;/code&gt; will quit the current process, and &lt;code&gt;npm start&lt;/code&gt; to start it again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try out watch mode for Gatsby
&lt;/h2&gt;

&lt;p&gt;If you look at the file called &lt;code&gt;gatsby-config.js&lt;/code&gt;, you'll see the following entry in the plugins section:&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gatsby-source-sanity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// To enable preview of drafts, copy .env-example into .env,&lt;/span&gt;
        &lt;span class="c1"&gt;// and add a token with read permissions    &lt;/span&gt;
        &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SANITY_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;watchMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;overlayDrafts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;We have enabled &lt;code&gt;watchMode&lt;/code&gt;, which means that Gatsby injects content changes on the fly, without you having to reload the development server, or refresh the browser. Few other source plugins do this. What's even cooler, is that other people can sit in the same studio, and edit content, and that too is instantly reflected on the frontend development server. The plugin only gets access to published changes by default, but try editing something (maybe add an image to the first blog post), push &lt;strong&gt;Publish&lt;/strong&gt; and see if it updates in the frontend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2Ffab24a742319a8e2395202d433e386593d8bedd4-1338x1022.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2Ffab24a742319a8e2395202d433e386593d8bedd4-1338x1022.gif" alt="Demonstrating watch mode in the gatsby source sanity plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add token to see _all _changes
&lt;/h2&gt;

&lt;p&gt;In the plugin, you maybe noticed &lt;code&gt;token: process.env.SANITY_TOKEN&lt;/code&gt; and &lt;code&gt;overlayDrafts: true&lt;/code&gt;. With a &lt;code&gt;token&lt;/code&gt; with read privileges, you give Gatsby access to unpublished documents, such as drafts. When &lt;code&gt;overlayDrafts&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;, Gatsby will use the draft version of a document if it has access to it. You'll need to save a read token in a file called &lt;code&gt;.env&lt;/code&gt; in the web folder to enable this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo/web
    &lt;span class="nb"&gt;cp&lt;/span&gt; .env-example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can go to &amp;lt;&lt;a href="https://manage.sanity.io/projects/" rel="noopener noreferrer"&gt;YourProjectId&amp;gt;/settings/api&lt;/a&gt; (Manage -&amp;gt; Settings -&amp;gt; API), and &lt;strong&gt;Add New Token&lt;/strong&gt;. Give it a nice descriptive label, and only read rights. Copy it, and paste it in the .env file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo/web/.env
    &lt;span class="nv"&gt;SANITY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YourToken"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To load the token into Gatsby, you'll need to restart the local development server again. It will be worth it though.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F61ab9c832f4fbeb0b6ef4883e983f6a60a2cfb16-1338x1022.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F61ab9c832f4fbeb0b6ef4883e983f6a60a2cfb16-1338x1022.gif" alt="Watch mode with drafts enabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get your Gatsby site on the web with Netlify
&lt;/h2&gt;

&lt;p&gt;Maybe you want to tweak the frontend a bit, change the CSS, or make some adjustments. At some point you want to share it with the world though. We recommend that you put your project on GitHub. If you forked it, commit and push your changes. If you cloned it from us, &lt;a href="https://kbroman.org/github_tutorial/pages/init.html" rel="noopener noreferrer"&gt;follow these instructions&lt;/a&gt; on how to get a local git repo on GitHub.&lt;/p&gt;

&lt;p&gt;When it's on GitHub, head over to Netlify and sign up or log in. If you choose &lt;strong&gt;New site&lt;/strong&gt; from Git and find the repository you just updated, everything is set up and ready, thanks to the &lt;code&gt;netlify.toml&lt;/code&gt; file in the project. Likewise, if you prefer &lt;a href="https://zeit.co/now" rel="noopener noreferrer"&gt;Zeit's now&lt;/a&gt; (or want to use both for ultimate redundancy), you can run &lt;code&gt;npm run now-deploy&lt;/code&gt; in the root folder of the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F0f5e131d88b8eb024e83ab25366e13d4fa2b5d5f-2380x2220.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F0f5e131d88b8eb024e83ab25366e13d4fa2b5d5f-2380x2220.png" alt="Setting up the Sanity.io powered Gatsby.js website on Netlify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To quickly deploy the Sanity studio, run &lt;code&gt;sanity deploy&lt;/code&gt; in the &lt;code&gt;studio&lt;/code&gt; folder and choose a hostname. Now you can invite two additional users for free on the forever-free developer plan. If you need more, it's $10 per user on the pay-as-you-go on the same plan. Gatsby only uses 2 API request to build the whole site. One for all your content, and one for the schema. So you will get great mileage &lt;a href="https://www.sanity.io/pricing/dev-2018-08-21" rel="noopener noreferrer"&gt;with our free plan&lt;/a&gt; with a Gatsby website. We dig it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger new Netlify builds on content changes
&lt;/h3&gt;

&lt;p&gt;Netlify triggers new builds when you push commits to a branch that it monitors. The content, however, is not committed to Git. Fortunately, there are other ways of triggering builds, one of them is using webhooks.&lt;/p&gt;

&lt;p&gt;If you host your site on Netlify, you can go into &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Build &amp;amp; Deploy&lt;/strong&gt; and scroll down to &lt;strong&gt;Build Hooks&lt;/strong&gt;. Choose &lt;strong&gt;Add build hook&lt;/strong&gt;, give it a name, and point to the branch you want to build from. Copy the URL, and return to the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo
    &lt;span class="nb"&gt;cd &lt;/span&gt;studio
    sanity hook create
    ? Hook name: netlify
    ? Select dataset hook should apply to: 
    ? Hook URL: https://api.netlify.com/build_hooks/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Netlify triggers a new deploy of your site everytime you publish some new content edits. &lt;/p&gt;

&lt;h2&gt;
  
  
  BONUS: Content preview online on Heroku
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://awesomereact.com/custom-gatsby-preview-with-heroku" rel="noopener noreferrer"&gt;This helpful tutorial&lt;/a&gt; by Andreas Keller popped up in our feed. He has figured a way to run Gatsby on a development server on Heroku, hence making it possible to get that watch mode with live previews experience on the web. Which is nice if you have editors that can't be expected to run a local development server in the terminal. Let's set it up with the Sanity source plugin to get an unparalleled preview experience!&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the Heroku CLI
&lt;/h3&gt;

&lt;p&gt;Follow &lt;a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up" rel="noopener noreferrer"&gt;these instructions&lt;/a&gt; to install the Heroku CLI. Run &lt;code&gt;heroku login&lt;/code&gt; and log in or sign up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add gatsby-cli as a dev-dependency
&lt;/h3&gt;

&lt;p&gt;To get Heroku to play nice with the monorepo (it likes its apps in the root folder), we must install the gatsby-cli as a dev dependency in the root folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo
    npm &lt;span class="nb"&gt;install &lt;/span&gt;gatsby-cli &lt;span class="nt"&gt;--only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are also other &lt;a href="https://github.com/timanovsky/subdir-heroku-buildpack" rel="noopener noreferrer"&gt;ways of doing it&lt;/a&gt; where you push the &lt;code&gt;web&lt;/code&gt; folder, but then you have to put in the &lt;code&gt;projectId&lt;/code&gt; and &lt;code&gt;dataset&lt;/code&gt; manually in &lt;code&gt;gatsby-config.js&lt;/code&gt;, as these variables are imported from &lt;code&gt;sanity.json&lt;/code&gt; in the &lt;code&gt;studio&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Once you're set, you should do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ~/example-company-website-gatsby-sanity-combo
    &lt;span class="c"&gt;# create a new heroku app&lt;/span&gt;
    heroku create

    &lt;span class="c"&gt;# set node to run in development mode&lt;/span&gt;
    heroku config:set &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;development
    heroku config:set &lt;span class="nv"&gt;NPM_CONFIG_PRODUCTION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;

    &lt;span class="c"&gt;# set the project id and dataset, found in sanity.json&lt;/span&gt;
    heroku config:set &lt;span class="nv"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YourProjectId
    heroku config:set &lt;span class="nv"&gt;DATASET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YourDatasetName

    &lt;span class="c"&gt;# add the read token to Heroku's environment&lt;/span&gt;
    &lt;span class="c"&gt;# make sure that the token isn't wrapped in quotation marks&lt;/span&gt;
    heroku config:set &lt;span class="nv"&gt;SANITY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;web/.env|grep SANITY_TOKEN&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# add the app configuration to run gatsby on heroku's dyno&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"web: cd web &amp;amp;&amp;amp; gatsby develop -p &lt;/span&gt;&lt;span class="nv"&gt;$PORT&lt;/span&gt;&lt;span class="s2"&gt; -H 0.0.0.0"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Procfile

    &lt;span class="c"&gt;# add the changes to git&lt;/span&gt;
    git add Procfile package.json package-lock.json
    git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"Add Procfile and deps for Heroku"&lt;/span&gt;

    &lt;span class="c"&gt;# push it to heroku&lt;/span&gt;
    git push heroku master

    &lt;span class="c"&gt;# open the app in the browser&lt;/span&gt;
    heroku open

    &lt;span class="c"&gt;# check the logs to troubleshoot if things don't work&lt;/span&gt;
    heroku logs &lt;span class="nt"&gt;--tail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This app runs on a free dyno that sleeps after a time of inactivity, and it can take some minutes to start up again. You can of course run it on a paid dyno which gives you full uptime. We cannot guarantee that it will be very stable, since the development server isn't built to actually host a website on the web. If it crashes, you can restart it with &lt;code&gt;heroku restart&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It's pretty cool nonetheless, and undoubtedly useful when you want to give your web editors a way to preview their changes instantly, without having to wait for rebuilds.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>howto</category>
    </item>
    <item>
      <title>How to shift array position in vanilla JavaScript</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Wed, 19 Dec 2018 08:44:47 +0000</pubDate>
      <link>https://dev.to/kmelve/how-to-shift-array-position-in-vanilla-javascript-59oa</link>
      <guid>https://dev.to/kmelve/how-to-shift-array-position-in-vanilla-javascript-59oa</guid>
      <description>&lt;p&gt;I was helping a user over at &lt;a href="https://www.sanity.io"&gt;sanity.io&lt;/a&gt; yesterday doing some content migration, where they wanted to take the last element of an array and put it in the first position. Every time I get a question like this, I like to see if I manage to solve it without going to any libraries. Both because I don't want to introduce more dependencies for the person with the question, but most of all, it's an opportunity for some mental exercise. &lt;/p&gt;

&lt;p&gt;So, how to change an array like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cersei&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="s2"&gt;Joffrey&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="s2"&gt;Ilyn&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="s2"&gt;The Mountain&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="s2"&gt;The Hound&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="s2"&gt;Melisandre&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="s2"&gt;Beric&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="s2"&gt;Thoros&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="s2"&gt;Tywin&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="s2"&gt;Meryn&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="s2"&gt;Walder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;to this?&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Walder&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="s2"&gt;Cersei&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="s2"&gt;Joffrey&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="s2"&gt;Ilyn&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="s2"&gt;The Mountain&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="s2"&gt;The Hound&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="s2"&gt;Melisandre&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="s2"&gt;Beric&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="s2"&gt;Thoros&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="s2"&gt;Tywin&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="s2"&gt;Meryn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;My first instinct was to make a new array just targeting the last element with the list length subtracted by 1, and then spreading the rest of the array using &lt;code&gt;splice&lt;/code&gt;. Push the green &lt;em&gt;run&lt;/em&gt; button to run the code:&lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
  &lt;/code&gt;
  &lt;code&gt;
    
const theList = ["Cersei", "Joffrey", "Ilyn", "The Mountain", "The Hound", "Melisandre", "Beric", "Thoros", "Tywin", "Meryn", "Walder"]

const newList = [theList[theList.length - 1], ...theList.splice(0, theList.length - 1)]

console.log(newList)

  &lt;/code&gt;
&lt;/div&gt;



&lt;p&gt;Some of you will already have guessed why this is a bad idea, and some of you will be like me and always mix up &lt;code&gt;splice&lt;/code&gt; and &lt;code&gt;slice&lt;/code&gt;. Let’s see what happens with &lt;code&gt;theList&lt;/code&gt; when we &lt;em&gt;run&lt;/em&gt; the code above:&lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
const theList = ["Cersei", "Joffrey", "Ilyn", "The Mountain", "The Hound", "Melisandre", "Beric", "Thoros", "Tywin", "Meryn", "Walder"]
const newList = [theList[theList.length - 1], ...theList.splice(0, theList.length - 1)]

  &lt;/code&gt;
  &lt;code&gt;
    
// check output
console.log(newList)
// check output
console.log(theList)

  &lt;/code&gt;
&lt;/div&gt;


&lt;p&gt;Not ideal (unless you're Arya). Replacing &lt;code&gt;splice&lt;/code&gt; with &lt;code&gt;slice&lt;/code&gt; leaves the original array intact, and will not mutate it (which can lead to a mountain of problems):&lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
const theList = ["Cersei", "Joffrey", "Ilyn", "The Mountain", "The Hound", "Melisandre", "Beric", "Thoros", "Tywin", "Meryn", "Walder"]

  &lt;/code&gt;
  &lt;code&gt;
    
const newList = [theList[theList.length - 1], ...theList.slice(0, theList.length - 1)]

console.log(newList)
console.log(theList)

  &lt;/code&gt;
&lt;/div&gt;


&lt;p&gt;This leaves us with exactly what we want. &lt;/p&gt;

&lt;p&gt;Another way to go about it is to use the &lt;code&gt;Array.prototype.reduce&lt;/code&gt;-method, which to me feel a bit cleaner. Also, &lt;code&gt;.reduce&lt;/code&gt; is worth investing time into learning. &lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
const theList = ["Cersei", "Joffrey", "Ilyn", "The Mountain", "The Hound", "Melisandre", "Beric", "Thoros", "Tywin", "Meryn", "Walder"]

  &lt;/code&gt;
  &lt;code&gt;
    
const newList = theList.reduce(
  (accumulatedArray, currentItem, index, originalArray) =&amp;gt;
    index &amp;lt; originalArray.length - 1
      ? [...accumulatedArray, currentItem]
      : [currentItem, ...accumulatedArray],
  []
)

console.log(newList)
console.log(theList)

  &lt;/code&gt;
&lt;/div&gt;


&lt;p&gt;This can, of course, be made into a function. Tempting as it may be, I don't recommend using an &lt;em&gt;anonymous&lt;/em&gt; arrow (&lt;code&gt;=&amp;gt;&lt;/code&gt;) function for this, as it doesn't show up with a name in the console stack trace if something wrong occurs: &lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
const theList = ["Cersei", "Joffrey", "Ilyn", "The Mountain", "The Hound", "Melisandre", "Beric", "Thoros", "Tywin", "Meryn", "Walder"]

  &lt;/code&gt;
  &lt;code&gt;
    
function shiftLastToFirst (theArray) {
  return theArray.reduce(
    (accumulatedArray, currentItem, index, originalArray) =&amp;gt; {
      return index &amp;lt; originalArray.length - 1
        ? [...accumulatedArray, currentItem]
        : [currentItem, ...accumulatedArray]
    },
    []
  )
}
shiftLastToFirst(theList)

  &lt;/code&gt;
&lt;/div&gt;


&lt;p&gt;Now, I'm certain there are many smarter ways of doing this. And the reason I'm writing this up and putting it here is that I want to learn about them. &lt;/p&gt;

&lt;p&gt;How would you go about solving this?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The problem with “you guys”</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Wed, 12 Dec 2018 12:23:18 +0000</pubDate>
      <link>https://dev.to/kmelve/the-problem-with-you-guys-51h7</link>
      <guid>https://dev.to/kmelve/the-problem-with-you-guys-51h7</guid>
      <description>&lt;p&gt;I made a bot that suggests some alternative phrasing when you write &lt;em&gt;guys&lt;/em&gt; in Slack. It made for some discussion.&lt;/p&gt;

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

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



&lt;/p&gt;

&lt;p&gt;I have seen in different Slack communities that people have implemented a Slackbot response that triggers whenever people write ”guys“, suggesting some alternatives that are considered more inclusive. It also links to an article in &lt;a href="https://www.vox.com/2015/6/11/8761227/you-guys-sexism-language" rel="noopener noreferrer"&gt;Vox&lt;/a&gt; about npm’s &lt;em&gt;you guys&lt;/em&gt;-jar. A similar commentary was also published in &lt;a href="https://www.theatlantic.com/family/archive/2018/08/guys-gender-neutral/568231/" rel="noopener noreferrer"&gt;The Atlantic&lt;/a&gt; that includes comments from a linguist. There's also a handful of threads on forums where people discuss whether the word "guys" is considered gender neutral or not.&lt;/p&gt;

&lt;p&gt;Not surprisingly, not everybody was convinced by the bot’s legitimacy. I had a handful of people tell (on behalf of their English speaking part of the world) me that “guys” actually was gender natural (I am aware). Some went further and suggested that this was censoring and undermining the way they talked. It’s tempting to point out how many of them were not… guys. (well, none).&lt;/p&gt;

&lt;p&gt;My tweet also gained a lot of likes and retweets, suggesting that some folks appreciated the idea, or at least wanted to be affiliated by what it signals. And this is taking us closer to the matter of hand. Because I'm all but sure that a “Guys bot” is the right approach to the problem we try to solve: How to make welcoming and inclusive communities in tech. I put it out partly as an experiment and to learn more by the reactions to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody likes being told they're wrong
&lt;/h2&gt;

&lt;p&gt;I have a lot of training in being wrong. I have spent years at university being told I'm wrong in all sorts of creative ways. Being open to being wrong is an essential part of learning and developing knowledge, especially in science. Still, I very often get defensive and moody when I'm told so. It's a very human response. It's something I have to actively work with.&lt;/p&gt;

&lt;p&gt;The reason it’s irritating is that there’s often a moral dimension to it, that doesn’t align with whatever you &lt;em&gt;intended&lt;/em&gt;. I bet that most people that greet a group with “Hi, guys!” don’t intend to be exclusive, but the rather opposite. When you’re instantly hit back with a canned response that suggests that this seemingly innocent way of speech may be considered hurtful to some, I have no problem in seeing that some might find that obtuse.&lt;/p&gt;

&lt;p&gt;I suspect, though, that people who have a lived experience of not being included in all sorts of ways, in a field still dominated by mostly men, may have a more empathetic response because they get what the bot is trying to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bots lack nuance
&lt;/h2&gt;

&lt;p&gt;There are good reasons to object to a bot automatically correcting language in a public community. To borrow the analogy from one of my colleagues, one wouldn't like having something that buzzed every time someone said it in the office space. Like in &lt;em&gt;Demolition Man&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5rVQGT01Kzg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Since nor me or the originators of the Slackbot response have spent time tuning the algorithms, it also triggers on a lot of false positives. Which is somewhat counterproductive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FaVcYQrM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FaVcYQrM.png" alt="Automatic Slackbot response"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason a bot is tempting for community moderatos is that also lessens the chance that you end up in long-winded debates whenever you have to remind people of the Code of Conduct and telling them they’re wrong. Also, you can’t be everywhere at the same time. A bot can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the bot stays (at least for a while)
&lt;/h2&gt;

&lt;p&gt;None of those who have given me critique have been able to convince me to turn off the bot though. That’s mainly because the critique doesn’t come from a place of empathy, but is mostly self-affirming and resisting consideration of what we try to achieve (to be fair, some have also acknowledged what it tries to do, but it usually ends there).&lt;/p&gt;

&lt;p&gt;Some are irritated that the bot corrects what they perceive to be a perfectly legitimate way of addressing a group, considered to be inclusive in their lingual context. And thereby telling me that I'm wrong, and perhaps because I'm not a native speaker (not seeing the irony). &lt;/p&gt;

&lt;p&gt;For someone that spends most of their they day communicating in a second language (my native being Norwegian), I must admit my sympathy is lacking for someone who feels it though to adjust by one word. It’s also telling that they don’t consider English to be a highly diverse and multi-faceted language. And that we might have to take other considerations in an online multi-cultural community where gender bias is a proven issue than in one’s hometown.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not about you guys
&lt;/h2&gt;

&lt;p&gt;I also suspect that some think of this bot as just another example of virtue signaling and political correctness. Recognized as hostile forces to the open and liberal mind by some. Most of those I’ve encountered that have made this their hill to die on aren’t really open to taking in other perspectives or entertain the motivations behind questioning how language can be used to include or exclude people. They do not ask me why I really did this, or what problem I try to solve. So although I find pointing out hypocrisy a lazy argument, it certainly doesn’t help their case.&lt;/p&gt;

&lt;p&gt;So if you are a promoter of the open though and the free word, I'll ask you to reconsider the motivation behind efforts like this bot. For example by watching &lt;a href="https://youtu.be/02gpZuK5gF8" rel="noopener noreferrer"&gt;Patricia Aas’ talk &lt;em&gt;Deconstructing Privilege&lt;/em&gt;&lt;/a&gt;. Or actually listening to the experiences of different underrepresented groups in tech (and elsewhere), and consider how being reminded that you don't really belong might affect your motivation to stay in web development, technology, or whatever you do.&lt;/p&gt;

&lt;p&gt;Because you guys, it's not just about &lt;em&gt;you guys&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsa4dh71ogoxh8z16ekvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsa4dh71ogoxh8z16ekvj.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>community</category>
      <category>discuss</category>
      <category>devrel</category>
      <category>culture</category>
    </item>
    <item>
      <title>Why I love working at Sanity.io</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Tue, 11 Dec 2018 06:57:11 +0000</pubDate>
      <link>https://dev.to/kmelve/why-i-love-working-at-sanityio-4ob7</link>
      <guid>https://dev.to/kmelve/why-i-love-working-at-sanityio-4ob7</guid>
      <description>&lt;p&gt;Four years ago I was a grad student with a Ph.D. fellowship in the Study of Religions, so how did I end up working for a tech startup? This is a post about how I, Knut Melvær, came to run Developer Relations at &lt;a href="https://www.sanity.io" rel="noopener noreferrer"&gt;Sanity.io&lt;/a&gt; – it's also a celebration of following less obvious paths.&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;Cover image: Me presenting Sanity.io on the Google stage at &lt;a href="https://www.slush.com" rel="noopener noreferrer"&gt;Slush&lt;/a&gt;, with &lt;a href="https://twitter.com/bjoerge" rel="noopener noreferrer"&gt;Bjørge&lt;/a&gt;&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;In 2015 I was getting worn down. Recruitment practices in the academy are harsh. The prospect of being passed from one temporary university teaching contract to the next wasn't very appealing either. My fellowship was nearing its end, and while I had both published peer-reviewed research, and done lots of teaching and dissemination – it was challenging working on a thesis using digital methods in a field with very, very little experience with such things. Also, I’d developed a severe depression – which, after a too long stretch, I sought help mastering, and am mostly OK from today (do get help people!).&lt;/p&gt;

&lt;p&gt;A couple of months before my stipend ran out, I got a job offer as an interaction designer (which soon became “technology strategists”) at the wonderful, UX-oriented design agency &lt;a href="https://www.netlife.com" rel="noopener noreferrer"&gt;Netlife&lt;/a&gt;. In addition to my tech-oriented humanities background, I was an experienced web development freelancer. But I was very lucky to get the offer as it not only meant I didn't have to constantly worry about earning a living and how to get the next contract, but I was welcomed to a milieu where people had each other’s back and cheered you on. Not too much of that in the academy. Not that I'm bitter. Or wait.&lt;/p&gt;

&lt;p&gt;I worked at Netlife for three years and enjoyed every minute of it – although multiple concurrent clients with high demands, sometimes on tight budgets and with much at stake, also does take its toll. &lt;/p&gt;

&lt;p&gt;So when I got the offer from Sanity.io to join as a developer advocate, it felt like a special opportunity. I would get to work on a special technology along with some very talented people. It felt like the right time to move on and an opportunity not to be missed.&lt;/p&gt;

&lt;p&gt;I had already had the pleasure of working with Sanity as tech-lead when building Netlife’s new website, using it as a content backend, with &lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; as the frontend, and multiple Node.js-microservices on Heroku. We had also run the same setup for &lt;a href="https://www.u4.no" rel="noopener noreferrer"&gt;U4 Anti-Corruption Resource Centre&lt;/a&gt;. Those experiences inspired me to write the blog post “&lt;a href="https://hackernoon.com/headless-in-love-with-sanity-689960571dc" rel="noopener noreferrer"&gt;Headless in Love with Sanity&lt;/a&gt;”, which — though I didn’t get at the time — kinda ended up being my job application. Notwithstanding, the motivation was a real appreciation to be working with something where you felt a lot of care and thinking had gone into making my life as a developer easier, and frankly, more fun.&lt;/p&gt;

&lt;p&gt;Now that I have been working at Sanity for half a year, I thought it was time to jot down some thought about why it has been such a blast. It’s also a not too subtle pitch for those of you who either are considering applying for a position – or are asked to join. That being said, my motivation to write this it is pretty pure and an opportunity to reflect on what makes my job meaningful and exciting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The people
&lt;/h2&gt;

&lt;p&gt;I, like many others working with technology in Norway, had an admiration the people behind Sanity for many years. They used to be a technology- and design agency called &lt;a href="http://bengler.no" rel="noopener noreferrer"&gt;Bengler&lt;/a&gt;, with a track record for doing weird/challenging/state-of-the-art work, such as making a &lt;a href="http://bengler.no/origo" rel="noopener noreferrer"&gt;social network tied to local publishing&lt;/a&gt;, that launched concurrently with Facebook, &lt;a href="http://bengler.no/grbl" rel="noopener noreferrer"&gt;controller software for 3d printers&lt;/a&gt;, &lt;a href="http://bengler.no/chorder" rel="noopener noreferrer"&gt;a chorded text input device&lt;/a&gt;, or &lt;a href="http://bengler.no/panda" rel="noopener noreferrer"&gt;disruption-as-a-service toolkit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Frankly, coming to work with these people would have been terrifying, if it weren’t that they are all incredibly pleasant, grounded, and open-minded. They challenge you when you haven’t thought properly through the implications of your suggestions, but also cheer you on when you ship. As one of the first “outsiders” in the new company, I have never felt excluded or not a part of the team. Of course, that may come from selection bias, but I would be surprised if the same didn’t account for new, and more diverse hires than myself (a Norwegian white male in his 30s). It's a startup with grown-ups, with families, obligations, hobbies, and things happening outside of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The product
&lt;/h2&gt;

&lt;p&gt;At work, pretty much all of our attention is tied up in what we’re making: Sanity. I have done my fair share of CMS related development, be it Wordpress, Craft CMS, Statamic, Contentful, and others. Although it isn't fair to categorize Sanity as “just another CMS,” used as one, it has undoubtedly been the most fun one to work with (and Craft CMS is pretty darn fun). I believe it’s because Sanity.io opens you to so many possibilities. There are plenty of doors that open when you deal with a real-time backend, having a relational document store with a graph-oriented query language, with &lt;a href="https://github.com/sanity-io/sanity" rel="noopener noreferrer"&gt;an open source React content editing app&lt;/a&gt;. This makes Sanity.io pretty unique and awesome – it took them years to build.&lt;/p&gt;

&lt;p&gt;However, all the little things are as important: some minor functionality in the CLI, some available method on the way you can tweak the document listings or a feature in GROQ. I can’t count how many times I asked if you could do this or that, and while waiting for the answer, discovering that, yeah, you can do it. It's nice to stumble over exactly what you need when you need it. Using Sanity.io has been a series of such experiences. &lt;/p&gt;

&lt;p&gt;Sanity is already remarkable in its own right, but looking at the very secret backlog, there are so many cool things that we can build on top of this stack, that I can’t even. 2019 will be an exciting year, for sure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The community
&lt;/h2&gt;

&lt;p&gt;I have been mistaken so many times since I started in Sanity – which to me, is part of the appeal (that means that I’m learning). One thing I was very wrong about, was my worry about launching the community platform. I was so ready to have to moderate and deal with trolls and hostile people in our &lt;a href="https://slack.sanity.io" rel="noopener noreferrer"&gt;community Slack&lt;/a&gt;. I was very wrong.&lt;/p&gt;

&lt;p&gt;It has been such a joy to get to know our community, get to answer surprisingly challenging questions (because people are using Sanity to solve challenging things), take very constructive feedback, and — this is my favorite thing — see the stuff people are building. The community has grown very fast, but it hasn’t been a single instance of harassment or bad behavior (as far I have been able to gather). As we continue to grow, a key concern is to make everyone feel welcome and included.&lt;/p&gt;

&lt;h2&gt;
  
  
  The office space
&lt;/h2&gt;

&lt;p&gt;I go to work to the coolest office (though the floors are heated). Almost every day (as a commuter I treat myself to the home office once in a while), I enter a converted horse tram depot at Grünerløkka, a lively neighborhood in central Oslo (the capital of Norway). It’s an open space, yet it doesn’t give the feel of an open office. Behind where I tend to sit, there is a workbench where &lt;a href="http://polarworks.no/" rel="noopener noreferrer"&gt;Polarworks&lt;/a&gt; (which also grew out of Bengler) are developing super cool motion control software. It very much feels like a maker space. So although I’m not that into beer and aware that it makes us sound like outtakes from Portlandia, it is indeed nice to have a micro-brewery where good tasting brews are made. Next year we'll be opening an office in San Fransisco, that'll be exciting too!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qeyf83uuh1jrdhksocf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qeyf83uuh1jrdhksocf.jpg" alt="From one of our meetups" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;From one of our meetups&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The challenges
&lt;/h2&gt;

&lt;p&gt;To me personally, the primary motivation that brings me to work every day is many challenges of working on a product like Sanity, which both has many features, but with the ethos of being super easy to use. We sincerely believe Sanity has a place for developers that need a backend for structured content – be it a weekend project, or for enterprise needs. To take a product out in the world is hard work. To prepare your organization for taking on more people is always a challenge. To understand what’s truly useful for people, and how to communicate with them, is not easy. To take time off to recuperate and get enough brain air to stay creative can be difficult when crazy-stuff-we-can’t-talk-about-yet™ is happening every week. To be allowed to be wrong, to experiment, and given the trust to try stuff I haven't really done before are sometimes scary, as there is a great deal of responsibility that goes into it.&lt;/p&gt;

&lt;p&gt;However, those are also the things that drive me, and why I, frankly, love working for Sanity.io. I hope I get to share that pleasure with you some day.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I should also mention our office dogs, my own Jara, and &lt;a href="https://twitter.com/rexxars" rel="noopener noreferrer"&gt;Espen’s&lt;/a&gt; Kokos.&lt;/em&gt; 📸 &lt;a href="https://twitter.com/even" rel="noopener noreferrer"&gt;Even Westvang&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2kt1fwebsj0lf7x9i7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2kt1fwebsj0lf7x9i7t.png" alt="Jara" width="800" height="532"&gt;&lt;/a&gt;&lt;br&gt;
Jara&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3knh1ye16hwcxuxyvgvk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3knh1ye16hwcxuxyvgvk.png" alt="Kokos" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Kokos&lt;/p&gt;

</description>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating Custom Content Blocks: Wordpress Gutenberg vs. Sanity.io</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Fri, 07 Dec 2018 07:38:19 +0000</pubDate>
      <link>https://dev.to/sanity-io/creating-custom-content-blocks-wordpress-gutenberg-vs-sanityio-4k5m</link>
      <guid>https://dev.to/sanity-io/creating-custom-content-blocks-wordpress-gutenberg-vs-sanityio-4k5m</guid>
      <description>&lt;p&gt;Wordpress 5.0 comes with a brand new rich text editor called &lt;a href="https://wordpress.org/gutenberg/" rel="noopener noreferrer"&gt;Gutenberg&lt;/a&gt;. It is highly anticipated and has created both buzz and &lt;a href="https://rianrietveld.com/2018/10/09/i-have-resigned-the-wordpress-accessibility-team/" rel="noopener noreferrer"&gt;controversy&lt;/a&gt;. The promise of Gutenberg is customizability, especially when it comes to adding custom content blocks. If you want to get started with Gutenberg, you can read this &lt;a href="https://www.smashingmagazine.com/2018/10/gutenberg-testimonials-sliderblock/" rel="noopener noreferrer"&gt;excellent introduction in Smashing Magazine&lt;/a&gt;. It is built in React and allow developers to extend the editors basic functionality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F07e5821d81408fde490467f1cffd69613fa301cc-2000x1081.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F07e5821d81408fde490467f1cffd69613fa301cc-2000x1081.png" alt="Custom testimonial block type in Wordpress Gutenberg"&gt;&lt;/a&gt; Custom testimonial block type in Wordpress Gutenberg. Published on smashingmagazine.com&lt;/p&gt;

&lt;p&gt;We couldn't resist though. Since having custom content blocks is in the DNA of &lt;a href="https://www.github.com/sanity-io/sanity" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt;, we wanted to show how easy it is to recreate the testimonials slider that the 12 min read, and 10 part article introduces you to. Like an eleventh of the time easier. 🐇&lt;/p&gt;

&lt;p&gt;Of course, the comparison only goes so far. Wordpress is a classic CMS with a template engine, whereas you can use Sanity as a headless CMS with the frontend framework you would prefer, be it Vue, React or something else. &lt;/p&gt;

&lt;p&gt;If you haven't tried Sanity yet, it only takes two minutes to get started. To create a project and get an instant real-time hosted content API, and the connected open sourced editor locally, run this line in your terminal:&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="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;sanity&lt;/span&gt;&lt;span class="sr"&gt;/cli &amp;amp;&amp;amp; sanity ini&lt;/span&gt;&lt;span class="err"&gt;t
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you choose the blog template in the CLI tool, you're pretty much set to go!&lt;/p&gt;

&lt;h2&gt;
  
  
  The testimonial slider content model
&lt;/h2&gt;

&lt;p&gt;In the tutorial on Smashing Magazine, you learn to make a "testimonial slider" – typically used on marketing pages as a way to visualize social proof for your product.&lt;/p&gt;

&lt;p&gt;To re-create the Wordpress testimonial slider for Sanity you only need to define its content model. We'll take care of the input fields, and the real-time syncing to the datastore. &lt;/p&gt;

&lt;p&gt;The content model is pretty straightforward: First, we make the type for a &lt;code&gt;testimonialSlider&lt;/code&gt;. It's an object, with an array (which also holds the order of the testimonials) of testimonial objects with the fields &lt;code&gt;author&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;content&lt;/code&gt;, and &lt;code&gt;link&lt;/code&gt; to the source. I made the content field be clean text, but we could also have used &lt;code&gt;blockContent&lt;/code&gt; if we wanted to have rich text (and a slider within a slider, in case you are into recursive content patterns). If we add &lt;code&gt;options: { hotspot: true }&lt;/code&gt; to the image field, your editor can even set custom hotspots and crops for the image, which may be useful for image art direction.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testimonialSlider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testimonialSlider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Testimonial slider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fields&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Slider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;of&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testimonial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Testimonial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;fields&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&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="na"&gt;name&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;title&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&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="p"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blockContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blockContent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;of&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testimonialSlider&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;testimonialSlider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;blockContent&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's pretty much it. The user interface will be clean and can be used right away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa2jp512e4wxj10b2w09e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa2jp512e4wxj10b2w09e.gif" alt="Example of the slider user interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get that nice prepared JSON-structure for your frontend, you can use this GROQ query, assuming that your rich text is named &lt;code&gt;content&lt;/code&gt; and used in the document type &lt;code&gt;post&lt;/code&gt;:&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="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&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;content&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="nx"&gt;_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;testimonialSlider&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;slider&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
        &lt;span class="p"&gt;...,&lt;/span&gt;
        &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...,&lt;/span&gt;
          &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;-&amp;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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom preview component
&lt;/h2&gt;

&lt;p&gt;You can also add a custom preview component with some React code:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;client&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;part:@sanity/base/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;urlBuilder&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;@sanity/image-url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urlFor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;urlBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&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;sliderPreview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;marquee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inline-block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginRight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1em&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;figure&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
                &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;urlFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
                &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;marginRight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.5em&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
              &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;legend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;em&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/em&amp;gt;”&amp;lt;br /&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/figure&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/marquee&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;sliderPreview&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include it in your schema by adding this to your &lt;code&gt;testimonialSlider&lt;/code&gt; content type schema:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sliderPreview&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;./sliderPreview.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testimonialSlider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testimonialSlider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Testimonial slider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;slider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sliderPreview&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="cm"&gt;/* the fields */&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;Here I've used the good old HTML element &lt;code&gt;&amp;lt;marquee&amp;gt;&lt;/code&gt; to get a scrolling effect; you probably shouldn't do the same:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2adq0mnxnz4cn6espygz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2adq0mnxnz4cn6espygz.gif" alt="Preview of the testimonial slider block"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond appearances: The advantage of deeply typed rich text content
&lt;/h2&gt;

&lt;p&gt;This testimonial slider example tightly ties to a specific presentation on a webpage, which makes sense in WordPress because it's built to render and manage a website. WordPress saves the input in Gutenberg as HTML, which is what you eventually also get out of the APIs. HTML in content APIs is generally not what you want if you want to use it in your favorite frontend framework, or in something that should render in something other than a web browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.github.com/sanity-io/sanity" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt; saves the content in the editor as &lt;a href="https://www.portabletext.org" rel="noopener noreferrer"&gt;Portable Text&lt;/a&gt;, which makes it portable across any markup, but also makes rich text queryable. It should be easy to create custom editorial experiences, with the custom types and inputs that makes sense in your project or organization, and it should be easy to take that content and fit it to whatever form of presentation.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Get started with the Mux video plugin</title>
      <dc:creator>Knut Melvær</dc:creator>
      <pubDate>Sat, 01 Dec 2018 09:23:15 +0000</pubDate>
      <link>https://dev.to/sanity-io/get-started-with-the-mux-video-plugin-for-sanity-4k2a</link>
      <guid>https://dev.to/sanity-io/get-started-with-the-mux-video-plugin-for-sanity-4k2a</guid>
      <description>&lt;p&gt;When building Sanity, we placed much emphasis on building out a super flexible image pipeline that can transform and re-crop your images for you. We have no ambition of doing the same for video.&lt;/p&gt;

&lt;p&gt;When &lt;a href="https://www.mux.com" rel="noopener noreferrer"&gt;Mux&lt;/a&gt; reached out to us about integrating with their video streaming and analytics platform we had no doubts that it would be a good fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is Mux?
&lt;/h2&gt;

&lt;p&gt;Mux was founded in 2015 by Jon Dahl, Steve Heffernan, Matt McClure, and Adam Brown. Jon and Steve were the co-founders of Zencoder, which got acquired by Brightcove. With a team of engineers from YouTube, Twitch, Brightcove, and Facebook, they're now leading one of the best cloud-based video services on the web.&lt;/p&gt;

&lt;p&gt;Mux is an API-first video platform for streaming and analytics. What sets them apart is their self-optimizing encoding and delivery technology. The service provides high-quality streams for your users that adapt to device, and network conditions. What you also get is transparency on how your videos perform. Mux makes this easily accessible with Mux Data, which gives you detailed video performance metrics – in real-time. &lt;/p&gt;

&lt;p&gt;The performance and functionality of Mux are excellent. Store your full resolution master file with Mux and request whatever format you need – HLS for streaming, MP4 for downloads. Even GIF if you need it. From your frontends, apps, and digital services you can request exactly the format you need. &lt;/p&gt;

&lt;h2&gt;
  
  
  Get started with the mux-video plugin
&lt;/h2&gt;

&lt;p&gt;The Mux plugin for Sanity gives you a way to upload and preview videos easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Run this command in your Sanity project folder:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use in Schema
&lt;/h3&gt;

&lt;p&gt;To use the Mux video input, you create a field as you otherwise would, and use &lt;code&gt;mux.video&lt;/code&gt; for the &lt;code&gt;type&lt;/code&gt;.&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;catVideos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mux.video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add API keys
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dashboard.mux.com/signup?type=video" rel="noopener noreferrer"&gt;Register for Mux&lt;/a&gt; (if you tell them "&lt;code&gt;sanity"&lt;/code&gt; they'll give you $50 worth in credits ✨). If you don't yet have a project on Sanity - &lt;a href="https://www.sanity.io/mux" rel="noopener noreferrer"&gt;we've made a special offer also&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2Fc0152715592e6ac54fe9b6724fb44d34d15fa3b6-2594x2150.png%3Fw%3D1000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2Fc0152715592e6ac54fe9b6724fb44d34d15fa3b6-2594x2150.png%3Fw%3D1000" alt="Mux token configuration illustration" width="1000" height="829"&gt;&lt;/a&gt;The token needs full access to upload files&lt;/p&gt;

&lt;p&gt;Once you're logged in to Mux, find the &lt;a href="https://dashboard.mux.com/settings/access-tokens" rel="noopener noreferrer"&gt;"Access Tokens" page in the settings menu&lt;/a&gt;. Generate new tokens with &lt;strong&gt;full access **on Mux Video&lt;/strong&gt; &lt;strong&gt;and&lt;/strong&gt; Read **on Mux Data, and have them handy for the next step.&lt;/p&gt;

&lt;p&gt;Back in Sanity Studio, find the document where your video field appears, and click the plug-icon 🔌on the Paste your Access Token and Secret Key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F5dfa94404683d70455320b3572009de0eaf2db0e-2284x1534.png%3Fw%3D2000%26h%3D2000%26fit%3Dmax" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.sanity.io%2Fimages%2F3do82whm%2Fproduction%2F5dfa94404683d70455320b3572009de0eaf2db0e-2284x1534.png%3Fw%3D2000%26h%3D2000%26fit%3Dmax" alt="Mux API Credentials" width="2000" height="1343"&gt;&lt;/a&gt;Enter your Mux API credentials&lt;/p&gt;

&lt;h3&gt;
  
  
  Uploading a video
&lt;/h3&gt;

&lt;p&gt;Uploading a video is easy: Use the select button to open the file explorer on your system, drag the file right into the input area, or paste the URL (like I do in the video) to the video in the field. Once it's done uploading, you can select the thumbnail you want for the preview. Check the video in the codesandbox to see how it works.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/rl7q3x473p"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying it with GROQ
&lt;/h3&gt;

&lt;p&gt;In this example, we have added the Mux video as a custom block in rich text. We can then use GROQ to generate the URL for the stream on the frontend. Here we also use concatenation to get the streaming URL out of the box.&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="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&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;text&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
        &lt;span class="p"&gt;...,&lt;/span&gt;
          &lt;span class="nx"&gt;_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;muxVideo&lt;/span&gt;&lt;span class="dl"&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="p"&gt;...,&lt;/span&gt;
            &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&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="s2"&gt;url&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="s2"&gt;https://stream.mux.com/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;playbackId&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we pick out the asset data from the response to this query, we'll get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"121c8c30a649"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"muxVideo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"_createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2018-11-30T18:27:21Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"066e45f9-e2e6-4537-8b40-05f8c0f334d9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"_rev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xLJdqcI4pgly0b1J2cj0o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mux.videoAsset"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"_updatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2018-11-30T18:27:27Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"assetId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KdUXsmAKryppWd1wPiAtNVhMIqc7cPmL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"aspect_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16:9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1543602441"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;28.233333&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KdUXsmAKryppWd1wPiAtNVhMIqc7cPmL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"master_access"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"max_stored_frame_rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"max_stored_resolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"mp4_support"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"passthrough"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"066e45f9-e2e6-4537-8b40-05f8c0f334d9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"playback_ids"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NZQMBbYtVa6pDebOjB8wXRNQvao3RWrv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"public"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ready"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"tracks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;28.142585&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tcte02pHV5iGVYDUqGX5hiT5XqgB8pMym"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"max_channel_layout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stereo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"max_channels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"audio"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;28.166&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ocguJveQvPh95zPcnuitsLLXvLYaTAMwPfgDoqFLD01Q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"max_frame_rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"max_height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"max_width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"video"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"upload video with mux.mp4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"playbackId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NZQMBbYtVa6pDebOjB8wXRNQvao3RWrv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ready"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://stream.mux.com/NZQMBbYtVa6pDebOjB8wXRNQvao3RWrv"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As with our image pipeline, we make sure to have the metadata readily available. This means that you also easily can query for video assets by all these keys. For example will the query &lt;code&gt;[*_type == "mux.videoAsset" &amp;amp;&amp;amp; data.aspect_ratio == "16:9"]&lt;/code&gt; return all uploaded videos with a letterboxed aspect ratio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video playback on the frontend
&lt;/h3&gt;

&lt;p&gt;The final piece of the puzzle is to get your videos to your end users. You can integrate videos on Mux with all sorts of stuff, be it the web, apps, TV platforms, or even offline by providing your users with an mp4-download. We made a video player for React that is easy to integrate into your project. &lt;a href="https://github.com/sanity-io/sanity-mux-player" rel="noopener noreferrer"&gt;Check it out on GitHub&lt;/a&gt; or in the CodeSandbox beneath.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/rl7q3x473p"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  First class video support
&lt;/h3&gt;

&lt;p&gt;We're super happy that Mux reached out to us, and that we get to stand on their shoulders when it comes to video support. We are planning to improve the integration even further, and we're stoked to see what you will make with it. For a more technical and in-depth read about integrating Mux on web frontends, do check out the blog post by our friends in ZEIT, &lt;a href="https://zeit.co/blog/new-zeit-tv" rel="noopener noreferrer"&gt;who just launched their new platform ZEIT TV using Mux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And finally, a cat video. Because everyone should have at least one cat video in their video archive.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/m39x831qp"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.sanity.work/blog/first-class-responsive-video-support-with-the-new-mux-plugin" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>video</category>
      <category>react</category>
    </item>
  </channel>
</rss>
