This service tests the validity of an RSS 2.0 feed, checking to see that it follows the rules of the RSS specification. For advice from the RSS Advisory Board on how to implement RSS and handle issues such as enclosures and HTML encoding, read the RSS Best Practices Profile. This checker is also a validator of Atom and RSS 1.0 feeds.

Use this tester regularly to ensure that your RSS feed continues to work well in the wide audience of RSS readers, podcast clients and other software that supports the format.

 

Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

  • line 64, column 0: Non-html tag: svg (6 occurrences) [help]

    <div> <span> <a href="https://www.rainsberger.ca/docs-ti ...
  • line 146, column 0: content:encoded should not contain loading attribute (19 occurrences) [help]

    <p><img alt=" A version of the Drake/woman two square meme wit ...
  • line 146, column 0: content:encoded should not contain decoding attribute (19 occurrences) [help]

    <p><img alt=" A version of the Drake/woman two square meme wit ...
  • line 146, column 0: content:encoded should not contain fetchpriority attribute (19 occurrences) [help]

    <p><img alt=" A version of the Drake/woman two square meme wit ...
  • line 409, column 11: content:encoded should not contain relative URL references: #references-and-resources (11 occurrences) [help]

    &lt;/ul&gt;</content:encoded><category>docs</category><category>open source< ...
               ^
  • line 575, column 0: content:encoded should not contain iframe tag (2 occurrences) [help]

    &lt;iframe src=&quot;https://www.youtube.com/embed/0-aH18YH2SQ&quot; title=& ...
  • line 730, column 0: content:encoded should not contain data-copied attribute (8 occurrences) [help]

    &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt ...
  • line 730, column 0: content:encoded should not contain data-code attribute (8 occurrences) [help]

    &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt ...
  • line 916, column 0: content:encoded should not contain data-height attribute [help]

    &lt;p data-height=&quot;400&quot; data-default-tab=&quot;html,result&quot; d ...
  • line 916, column 0: content:encoded should not contain data-default-tab attribute [help]

    &lt;p data-height=&quot;400&quot; data-default-tab=&quot;html,result&quot; d ...
  • line 916, column 0: content:encoded should not contain data-slug-hash attribute [help]

    &lt;p data-height=&quot;400&quot; data-default-tab=&quot;html,result&quot; d ...
  • line 916, column 0: content:encoded should not contain data-user attribute [help]

    &lt;p data-height=&quot;400&quot; data-default-tab=&quot;html,result&quot; d ...
  • line 921, column 56: Missing atom:link with rel="self" [help]

    </content:encoded><category>javascript</category></item></channel></rss>
                                                            ^

Source: https://www.rainsberger.ca/blog/rss.xml

  1. <?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>rainsberger.ca | Blog</title><description/><link>https://www.rainsberger.ca/</link><language>en</language><item><title>Reads - May 3, 2025</title><link>https://www.rainsberger.ca/blog/reads-2025-05-03/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/reads-2025-05-03/</guid><description>Code and Coffee virtual conference, looking at open-source maintenance through a relationship lens, dev advocacy, reading the footnotes, and more!
  2.  
  3. </description><pubDate>Sat, 03 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;These “reads” also include some great “watches” I thought I’d share!&lt;/p&gt;
  4. &lt;div&gt;&lt;h2 id=&quot;code-and-coffee-a-virtual-coffee-conference&quot;&gt;Code and Coffee: A virtual coffee conference&lt;/h2&gt;&lt;/div&gt;
  5. &lt;p&gt;I always appreciate the events put on by CFE (Certified Fresh Events), and the first ever &lt;a href=&quot;https://cfe.dev/events/virtual-coffee-conf-2025/&quot;&gt;Code and Coffee virtual conference&lt;/a&gt; was no exception!&lt;/p&gt;
  6. &lt;p&gt;I was super impressed by &lt;a href=&quot;https://www.youtube.com/watch?v=5DiDm4yKaZg&quot;&gt;Accessibility is for Everyone!&lt;/a&gt; by Micha Rodgriguez. This was Micha’s first ever conference talk, and wow is this a sign of great things to come from them!&lt;/p&gt;
  7.  
  8. &lt;p&gt;Then, I had to go off and lie down after Abbey Perini’s &lt;a href=&quot;https://www.youtube.com/live/EvDJpN-jJgo?si=13gwIVGzjQ5cZYpo&amp;#x26;t=13347&quot;&gt;Coding and ADHD: Where We Excel&lt;/a&gt; because, oh no, am I just realizing at age 50 that my particular neurospiciness and social anxiety might actually be undiagnosed Inattentive ADHD and Rejection Sensitive Dysphoria?&lt;/p&gt;
  9.  
  10. &lt;p&gt;Trillium Smith gave a fantastic &lt;a href=&quot;https://www.youtube.com/watch?v=e3xaH1pJKsI&quot;&gt;demo of Talon Voice&lt;/a&gt; that makes me want to start using it right now exclamation point&lt;/p&gt;
  11.  
  12. &lt;div&gt;&lt;h2 id=&quot;foss-backstage-2025&quot;&gt;FOSS Backstage 2025&lt;/h2&gt;&lt;/div&gt;
  13. &lt;p&gt;I devour anything from Shauna Gordon-McKeon, and &lt;a href=&quot;https://www.youtube.com/watch?v=IGRPusk1cgc&quot;&gt;Relationship Problems in Open Source&lt;/a&gt; was no exception! This came close on the heels of reading her insightful &lt;a href=&quot;https://relational-tech.com/blog/six-ways-to-onboard.html&quot;&gt;
  14. Six Ways to Onboard New Contributors&lt;/a&gt;.&lt;/p&gt;
  15.  
  16. &lt;div&gt;&lt;h2 id=&quot;posts&quot;&gt;Posts&lt;/h2&gt;&lt;/div&gt;
  17. &lt;p&gt;Ashley Willis-McNamara reflects on reflect on how the role has evolved, and where it’s headed in &lt;a href=&quot;https://ashley.dev/posts/what-is-developer-advocacy/&quot;&gt;What is developer advocacy? (2025 edition)&lt;/a&gt;. This struck a particular chord with me because it so perfectly articulates some of the sometimes difficult-to-justify “glue work” that holds an open-source project together.&lt;/p&gt;
  18. &lt;p&gt;And, finishing off with an apology. I’m sorry, Emily. I promise I will never recklessly eschew footnotes again after reading &lt;a href=&quot;https://fromemily.com/hi-im-terrified/&quot;&gt;Hi. I’m Terrified, Creatively Constipated, and Existentially Angsty as Fuck. And I’m Judging Every Word of This Post. And It’s Not What I Want It to Be&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>reads</category><category>community</category><category>open source</category></item><item><title>IDX: my first impressions</title><link>https://www.rainsberger.ca/blog/idx-first-impressions/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/idx-first-impressions/</guid><description>&quot;I learned to code on a Chromebook in online editors. My very first Astro project was a forked CodeSandbox of an Astro v0.12 (!) starter template.
  19.  
  20. I have spent the last two years building several websites and maintaining the Astro documentation on Gitpod.
  21.  
  22. Two months ago, I switched to IDX as my exclusive coding environment (and you&apos;re not going to believe what happened next...)&quot;
  23.  
  24. </description><pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I learned to code on a Chromebook in online editors. My very first Astro project was a forked CodeSandbox of an Astro v0.12 (!) starter template.&lt;/p&gt;
  25. &lt;p&gt;I have spent the last two years building several websites and maintaining the Astro documentation on Gitpod.&lt;/p&gt;
  26. &lt;p&gt;Two months ago, I switched to &lt;a href=&quot;https://idx.dev/&quot;&gt;IDX&lt;/a&gt; as my exclusive coding environment &lt;em&gt;(and you’re not going to believe what happened next…)&lt;/em&gt;&lt;/p&gt;
  27. &lt;p&gt;Even though I now have a Linux desktop in my office (slash laundry room), I prefer to use online IDEs.&lt;/p&gt;
  28. &lt;p&gt;Sure, some of this is a holdover from working on a seven year old Chromebook that would freeze and crash randomly. In that case, I could jump into Gitpod on my Android tablet with keyboard and &lt;strong&gt;not lose a keystroke&lt;/strong&gt;. The workspace would still be actively running and my state was preserved.&lt;/p&gt;
  29. &lt;p&gt;In fact, using an online IDE I can be logged in on multiple devices at the same time, using one for my editor and another for my browser preview. I can be working on my desktop, and when Joe tells me it’s espresso time, I can open the Chromebook on the couch if I still want to get a few things out of my head before committing.&lt;/p&gt;
  30. &lt;p&gt;Since the announcement that Gitpod’s hosted offering is ending and they are focusing on self-hosted and enterprise users, I decided to switch to IDX full-time to see whether it would be a suitable option for me. I have a Google account (a deal breaker for some) and use Android mobile devices, so using a Google-hosted project is not a problem for me. I decided the best way was to jump in, and I removed the “open in Gitpod” Chrome extension so I wouldn’t be tempted. I was going to figure out how (and whether!) IDX would work.&lt;/p&gt;
  31. &lt;p&gt;Let’s get one thing out of the way first: IDX is &lt;em&gt;sloooow&lt;/em&gt;.&lt;/p&gt;
  32. &lt;p&gt;Starting up a workspace can take 30 seconds. Initializing a brand new workspace for the first time can take a minute. When you make a change to your Astro website, the browser preview will update in 12-18 seconds. In comparison, the same tasks on Gitpod typically take about half of that time. So, I’m used to slow, and this feels slow even to &lt;em&gt;me&lt;/em&gt;!&lt;/p&gt;
  33. &lt;p&gt;But for me, it’s worth the wait.&lt;/p&gt;
  34. &lt;p&gt;Once I got my footing in IDX and started working in a few repos, I was pleased to find that the sluggishness of the browser preview doesn’t extend to the familiar code editor, which is nearly identical to VS Code. Keystrokes don’t drop or lag, and every tab and menu item is instantly responsive.&lt;/p&gt;
  35. &lt;p&gt;I have access to the same plugins I did with Gitpod through Open VSX, including the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=astro-build.astro-vscode&quot;&gt;official Astro VS Code extension&lt;/a&gt;, and our &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=astro-build.houston&quot;&gt;Houston theme&lt;/a&gt;. I also now have the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github&quot;&gt;GitHub Pull Requests extension&lt;/a&gt; installed to manage all of our Astro docs contributions. Signing in to GitHub from IDX has always worked flawlessly, and the work flow is familiar.&lt;/p&gt;
  36. &lt;p&gt;And I am happy to confirm that IDX works well on my 14” Samsung tablet in Android mobile Chrome, too. Even though it’s my third device when I’m at home, there are some trips where I only take my tablet, and it’s important that I can continue to access and work on GitHub repositories while travelling.&lt;/p&gt;
  37. &lt;p&gt;Of course, every piece of software has its quirks. I wouldn’t say it has any more or less than Gitpod… just different ones.&lt;/p&gt;
  38. &lt;p&gt;Both Gitpod and IDX create “workspaces” that show up in your dashboard. A new workspace is created for each repository that you edit. I have already given feedback in the IDX community forums that it would be nice to be able to create an overall settings profile vs. setting up profiles for each new workspace. I find that most of my preferences are about &lt;em&gt;how I work&lt;/em&gt; (show all whitespace, configure word wrap, move the main panel to the right), and not &lt;em&gt;what is going on in this particular project&lt;/em&gt;. Gitpod allows me to set global preferences that apply to all workspaces by default.&lt;/p&gt;
  39. &lt;p&gt;Gitpod also allowed me to open the same repository in multiple workspaces at the same time. This meant I could work, mess things up, then just abandon the workspace and start over fresh with a new workspace. In fact, it was &lt;em&gt;intended&lt;/em&gt; to work this way. Gitpod considers workspaces to be ephemeral so you’re always going back to start over from your source regularly. They even warn against keeping any one workspace for too long. (Sync? What is that?)&lt;/p&gt;
  40. &lt;p&gt;IDX’s strict, “We know you already have a workspace for this repo, so this is the one you get!” policy seemed more limiting at first. But now I’m finding that I enjoy my dashboard &lt;em&gt;actually&lt;/em&gt; being workspaces that correspond to the projects I’m working on. It’s not a random mess of single-use, arbitrarily named items. I’m finding I have become more organized, and more disciplined, with better repo maintenance habits.&lt;/p&gt;
  41. &lt;p&gt;Perhaps because of this difference, IDX handles simultaneous changes upstream and downstream &lt;em&gt;much&lt;/em&gt; better than my Gitpod workspaces, which always seemed to throw errors and require git commands in the terminal to resolve. It’s a small difference, but when the whole point of open source repos is to work collaboratively, having IDX handle this aspect seamlessly makes a huge difference. It feels like it’s working &lt;em&gt;with&lt;/em&gt; my workflow, not against it.&lt;/p&gt;
  42. &lt;p&gt;So, while I &lt;em&gt;hope&lt;/em&gt; IDX initialization and browser preview gets faster, I have no complaints with reliability. Not everyone can handle opening a workspace, and &lt;em&gt;then&lt;/em&gt; going to make a quick coffee (not the reverse). And I wouldn’t blame you if you were one of those people!&lt;/p&gt;
  43. &lt;p&gt;But, &lt;a href=&quot;https://www.rainsberger.ca/blog/community-driven-astro-docs/#docs-are-never-done&quot;&gt;docs are never done&lt;/a&gt; so I’m in this for the long haul! Not only do I personally prefer the flexibility of a cloud development experience to setting up, maintaining, and troubleshooting a local machine, and the ability to seamlessly pick up where I left off on another device. I also think it’s important for someone on our team to be using the same tools that many in our community will be using.&lt;/p&gt;
  44. &lt;p&gt;An entire generation grew up with Chromebooks in schools. Some only have access to tablets and mobile devices. When I started learning to code, I couldn’t justify buying a new laptop for a hobby I wasn’t even sure was going to go anywhere. (Spoiler alert, it did!)&lt;/p&gt;
  45. &lt;p&gt;My primary goal in leading Astro’s documentation is empowerment. My purpose is to equip our community with the knowledge and resources they need to build amazing websites of their own.&lt;/p&gt;
  46. &lt;p&gt;Online development environments like IDX open up web development to so many more people, and I am proud to use (and abuse!) them. I &lt;em&gt;want&lt;/em&gt; to push them to their limits, and provide informed, helpful user feedback so they’ll get better. Because if &lt;em&gt;I&lt;/em&gt; can build Astro sites in a browser tab, then anyone can!&lt;/p&gt;</content:encoded><category>no local dev environment</category><category>community</category><category>open source</category></item><item><title>Reads - October 6, 2024</title><link>https://www.rainsberger.ca/blog/reads-2024-10-06/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/reads-2024-10-06/</guid><description>Community building advice from FeverBee, sidebar navigation advice from Tom Johnson for large documentation sites, and more!
  47.  
  48. </description><pubDate>Sun, 06 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here are some things I’ve recently been reading and enjoyed/learned from!&lt;/p&gt;
  49. &lt;ul&gt;
  50. &lt;li&gt;&lt;a href=&quot;https://www.feverbee.com/lurkersandlearners/&quot;&gt;Why 95% Of Your Community Visitors Don’t Participate (And What You Should Do About It!)&lt;/a&gt; and &lt;a href=&quot;https://www.feverbee.com/engagementskills/&quot;&gt;Stop Undervaluing Community Engagement Skills! – Communities Die Without Them&lt;/a&gt; by Richard Mulligan of FeverBee.&lt;/li&gt;
  51. &lt;li&gt;&lt;a href=&quot;https://idratherbewriting.com/files/doc-navigation-wtd/design-principles-for-doc-navigation/&quot;&gt;Building navigation for your documentation site: 5 best practices in design&lt;/a&gt; by Tom Johnson at I’d Rather Be Writing.&lt;/li&gt;
  52. &lt;li&gt;&lt;a href=&quot;https://tri.be/blog/designing-navigation-for-content-heavy-sites/&quot;&gt;Designing Navigation for Content-Heavy Sites&lt;/a&gt; by Kyle at Modern Tribe. (He eats hot dogs.)&lt;/li&gt;
  53. &lt;li&gt;&lt;a href=&quot;https://abbycovert.com/writing/information-architecture-for-navigation/&quot;&gt;Information Architecture for Navigation&lt;/a&gt; by sensemaker Abby Covert.&lt;/li&gt;
  54. &lt;/ul&gt;
  55. &lt;p&gt;I may come back and expand upon these, or I may follow up in later posts. There are no rules! This is my first “Reads!”&lt;/p&gt;</content:encoded><category>reads</category><category>community</category><category>open source</category><category>information architecture</category></item><item><title>50 Docs tips in 50 days</title><link>https://www.rainsberger.ca/blog/50-docs-tips-in-50-days/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/50-docs-tips-in-50-days/</guid><description>It&apos;s 50 days until I turn 50! So I thought I&apos;d celebrate with a different docs tip every day.
  56.  
  57. </description><pubDate>Mon, 24 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I realized while working &lt;em&gt;on&lt;/em&gt; this site that it’s been a while since I’ve written &lt;em&gt;for&lt;/em&gt; this site!&lt;/p&gt;
  58. &lt;p&gt;So, I’m hoping I can jump-start my writing by taking advantage of the delightful coincidence that I’ve got 50 days left until I’m 50 and motivate myself to write one, small, helpful or interesting tidbit per day.&lt;/p&gt;
  59. &lt;p&gt;(At least, I hope they are! They are things that help me while &lt;a href=&quot;https://www.rainsberger.ca/blog/community-driven-astro-docs/&quot;&gt;leading Astro’s community-driven documentation site&lt;/a&gt;.)&lt;/p&gt;
  60. &lt;p&gt;I’ll make a separate post for each one, and will share in &lt;a href=&quot;https://mastodon.social/@sarah11918/112671713862058779&quot;&gt;a Fediverse thread on my Mastodon account&lt;/a&gt; but I’ll come back to this one and update the list as we go.&lt;/p&gt;
  61. &lt;p&gt;Let’s see if I can do it!&lt;/p&gt;
  62. &lt;p&gt;&lt;em&gt;2025-08-23 Update: I did it!&lt;/em&gt;&lt;/p&gt;
  63. &lt;p&gt;You can now see and browse &lt;a href=&quot;https://www.rainsberger.ca/docs-tips/&quot;&gt;all the docs tips&lt;/a&gt; (which I hope to continue to add to even after the original 50) on the main section of my site.&lt;/p&gt;
  64. &lt;div&gt; &lt;span&gt; &lt;a href=&quot;https://www.rainsberger.ca/docs-tips/&quot;&gt; &lt;span&gt;Take me to all the docs tips!&lt;/span&gt; &lt;/a&gt;  &lt;/span&gt; &lt;svg aria-hidden=&quot;true&quot; width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z&quot; /&gt;&lt;/svg&gt; &lt;/div&gt; </content:encoded><category>docs</category></item><item><title>Developing Astro with Gitpod</title><link>https://www.rainsberger.ca/blog/gitpod-astro/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/gitpod-astro/</guid><description>From a 7 year-old Chromebook to an Android tablet to a Linux desktop... all my building with Astro is done in a cloud development environment thanks to Gitpod! No local development environment? No problem!
  65.  
  66. </description><pubDate>Wed, 18 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I spend much of my day making sure people can get started and build with &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt;. I am regularly working in several Astro websites: this personal site, Astro Docs, Astro Docs Docs…&lt;/p&gt;
  67. &lt;p&gt;Even though I wrote a tutorial that includes instructions on setting up and using VS Code for your first Astro project, I don’t actually have a local code editor installed on any machine I use!&lt;/p&gt;
  68. &lt;p&gt;Instead, all of my development is done in the cloud, through &lt;a href=&quot;https://www.gitpod.io/&quot;&gt;Gitpod&lt;/a&gt;.&lt;/p&gt;
  69. &lt;p&gt;Cloud environments aren’t new. I learned web development, and built my first projects entirely in Scrimba’s online platform. My React birding app was built in Replit. My first Astro websites were built and maintained entirely on CodeSandbox. Astro regularly encourages our community members to create minimal reproductions of their issues on StackBlitz to share with the team. During our weekly “Talking and Doc’ing” events in the Astro Discord, we often have several members jump into a shared GitHub Codespace to work on a project in real-time together.&lt;/p&gt;
  70. &lt;p&gt;But, Gitpod was the first full cloud developer environment that could entirely support a full workflow. I can install the Astro VS Code extension, configure start-up scripts, commit back to GitHub or, if I realize I’ve made a horrible mistake, just close the tab and start fresh again with a new workspace. It’s now what I use every day, both personally and professionally, to maintain all the Astro sites I work on.&lt;/p&gt;
  71. &lt;p&gt;Although you can open any of Astro’s official starter templates in a few different cloud environments at &lt;a href=&quot;https://astro.new&quot;&gt;astro.new&lt;/a&gt;, the best way to get started with a new Astro project in Gitpod is to start from an existing repository of your own. Use the instructions below every time you want to make a new Astro (or &lt;a href=&quot;https://starlight.astro.build&quot;&gt;Starlight&lt;/a&gt;) website!&lt;/p&gt;
  72. &lt;div&gt;&lt;h2 id=&quot;starting-a-new-astro-project&quot;&gt;Starting a new Astro project&lt;/h2&gt;&lt;/div&gt;
  73. &lt;ol&gt;
  74. &lt;li&gt;
  75. &lt;p&gt;Create a new, blank repository on GitHub, GitLab or BitBucket.&lt;/p&gt;
  76. &lt;/li&gt;
  77. &lt;li&gt;
  78. &lt;p&gt;Open that new repository in Gitpod using one of the following methods:&lt;/p&gt;
  79. &lt;ul&gt;
  80. &lt;li&gt;
  81. &lt;p&gt;install &lt;a href=&quot;https://www.gitpod.io/docs/browser-extension&quot;&gt;Gitpod’s browser extension&lt;/a&gt; or &lt;a href=&quot;https://www.gitpod.io/docs/browser-bookmarklet&quot;&gt;Gitpod’s browser bookmarklet&lt;/a&gt; to add an “Open in Gitpod” button right on your GitHub/GitLab repository page!&lt;/p&gt;
  82. &lt;/li&gt;
  83. &lt;li&gt;
  84. &lt;p&gt;prefix your GitHub repository’s full URL with &lt;code dir=&quot;auto&quot;&gt;gitpod.io/#&lt;/code&gt; and enter that URL into a browser window (e.g. &lt;code dir=&quot;auto&quot;&gt;gitpod.io/#https://github.com/sarah11918/astro&lt;/code&gt;)&lt;/p&gt;
  85. &lt;/li&gt;
  86. &lt;/ul&gt;
  87. &lt;/li&gt;
  88. &lt;li&gt;
  89. &lt;p&gt;When your repository finishes opening in Gitpod’s editor, type &lt;code dir=&quot;auto&quot;&gt;npm create astro@latest&lt;/code&gt; in the terminal window to launch the Astro CLI wizard which will guide you through setting up a new project.&lt;/p&gt;
  90. &lt;p&gt;(Want to start your project from an existing Astro theme or template? You can use &lt;a href=&quot;https://docs.astro.build/en/install/auto/#starter-templates&quot;&gt;the template flag&lt;/a&gt; as shown in Astro docs. For example, to open a new Starlight project, type &lt;code dir=&quot;auto&quot;&gt;npm create astro@latest -- --template starlight&lt;/code&gt;)&lt;/p&gt;
  91. &lt;/li&gt;
  92. &lt;li&gt;
  93. &lt;p&gt;Follow the instructions and when asked where to install the project, type &lt;code dir=&quot;auto&quot;&gt;./&lt;/code&gt; (Do not add a folder name. This will create your project at the root of your repository.)&lt;/p&gt;
  94. &lt;/li&gt;
  95. &lt;li&gt;
  96. &lt;p&gt;The final set of instructions will tell you to start the dev server with the command &lt;code dir=&quot;auto&quot;&gt;npm run dev&lt;/code&gt;. Your workspace is now ready for coding!&lt;/p&gt;
  97. &lt;/li&gt;
  98. &lt;li&gt;
  99. &lt;p&gt;Add a &lt;code dir=&quot;auto&quot;&gt;.gitpod.yml&lt;/code&gt; file to the root of your project to automatically run commands every time you re-open your Astro project. My file installs dependencies, starts the dev server and opens a preview of my site in another browser tab:&lt;/p&gt;
  100. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;.gitpod.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;npm install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;npm run dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  101. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;port&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;4321&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;onOpen&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;open-browser&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  102. &lt;/li&gt;
  103. &lt;li&gt;
  104. &lt;p&gt;After working on your site, you can commit your changes to local version control, and eventually back to your source repository (or throw them away!) via the Source Control menu item in the left navigation.&lt;/p&gt;
  105. &lt;p&gt;Any changes you make are saved to this “Workspace” which is a particular instance of your repository. This workspace will save its own state, even between starting/stopping the workspace, but will only push back to your online source code when you choose to commit and sync.&lt;/p&gt;
  106. &lt;p&gt;To work on &lt;strong&gt;this&lt;/strong&gt; version of your code, re-open the workspace. To go back and start fresh from source again, re-open your repository from one of the two earlier methods.&lt;/p&gt;
  107. &lt;p&gt;If you don’t like what you did in a particular workspace, then just delete (or ignore) the workspace! Unused workspaces will automatically delete after 14 days of inactivity via &lt;a href=&quot;https://www.gitpod.io/docs/life-of-workspace/#garbage-collection&quot;&gt;Gitpod’s Garbage Collection&lt;/a&gt;.&lt;/p&gt;
  108. &lt;/li&gt;
  109. &lt;/ol&gt;
  110. &lt;div&gt;&lt;h2 id=&quot;working-on-existing-projects&quot;&gt;Working on existing projects&lt;/h2&gt;&lt;/div&gt;
  111. &lt;p&gt;Of course, most of my time is spent working on existing projects. With my Gitpod browser extension, I am just one click away from opening any branch of any repository. I use this to:&lt;/p&gt;
  112. &lt;ul&gt;
  113. &lt;li&gt;
  114. &lt;p&gt;Work on my personal websites&lt;/p&gt;
  115. &lt;/li&gt;
  116. &lt;li&gt;
  117. &lt;p&gt;Contribute to Astro Docs, knowning that my “fork” is never behind or out of date&lt;/p&gt;
  118. &lt;/li&gt;
  119. &lt;li&gt;
  120. &lt;p&gt;Edit Pull Requests to the Astro Docs, because I can open up any PR branch and work in my full editing environment&lt;/p&gt;
  121. &lt;/li&gt;
  122. &lt;/ul&gt;
  123. &lt;div&gt;&lt;h2 id=&quot;work-on-any-machine&quot;&gt;Work on any machine&lt;/h2&gt;&lt;/div&gt;
  124. &lt;p&gt;In fact, this very article was started on a desktop machine in my office while my partner was making espresso in the kitchen. When he was ready to sit with morning espresso in front of the television for our morning routine, I opened &lt;strong&gt;the same Gitpod workspace&lt;/strong&gt; on my laptop on the couch and kept writing.&lt;/p&gt;
  125. &lt;p&gt;I hadn’t even committed my earlier work: Gitpod’s workspaces hold everything in memory so that I can pick up on a different machine at a moment’s notice and never lose a keystroke. (This was quite handy when my 7 year-old Chromebook was prone to random freezing, and I’d need to jump to a different device to keep working.)&lt;/p&gt;
  126. &lt;p&gt;I’m now back at my desk, finishing off this post.&lt;/p&gt;
  127. &lt;p&gt;So, I &lt;em&gt;could&lt;/em&gt; install VS Code locally, I guess. But, why would I? My setup is identical, and instantaneous, on any device and in any room of the house. I have even travelled for two weeks with only an Android tablet and continued to work on Astro docs on the road that way.&lt;/p&gt;
  128. &lt;p&gt;It’s never “works on my machine” with me, because in fact, it never is my machine! With Gitpod as my only development environment, it just “works.”&lt;/p&gt;</content:encoded><category>docs</category><category>open source</category><category>astro</category><category>no local dev environment</category></item><item><title>Stop writing docs. Start helping!</title><link>https://www.rainsberger.ca/blog/stop-writing-start-helping/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/stop-writing-start-helping/</guid><description>Good docs can be the difference between a happy, successful user of your project and ... a happy, successful user of someone else&apos;s project. But documentation is often a task left to people who don&apos;t feel comfortable writing it. This talk presented at ViteConf 2023 presents a new way to think about &quot;writing good docs&quot; and some action items that will immediately improve any existing documentation... without doing any writing at all!
  129.  
  130. </description><pubDate>Thu, 05 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(approximate transcript below, in “speaker notes” formatting rather than properly written, with some slides sprinkled in and &lt;a href=&quot;#references-and-resources&quot;&gt;resources and references&lt;/a&gt; at the end)&lt;/em&gt;&lt;/p&gt;
  131. &lt;p&gt;I’m going to ask a question and we’ll get back to the answer a little later.&lt;/p&gt;
  132. &lt;p&gt;“Are your docs… good?”&lt;/p&gt;
  133. &lt;p&gt;Whether your current docs are…&lt;/p&gt;
  134. &lt;ul&gt;
  135. &lt;li&gt;a README&lt;/li&gt;
  136. &lt;li&gt;a few markdown files&lt;/li&gt;
  137. &lt;li&gt;a Discord server&lt;/li&gt;
  138. &lt;li&gt;a CHANGELOG&lt;/li&gt;
  139. &lt;li&gt;the code itself&lt;/li&gt;
  140. &lt;li&gt;an entire website&lt;/li&gt;
  141. &lt;li&gt;… or nothing at all!&lt;/li&gt;
  142. &lt;/ul&gt;
  143. &lt;p&gt;… they can &lt;em&gt;always&lt;/em&gt; get better!&lt;/p&gt;
  144. &lt;p&gt;Not what you wanted to hear, right? This actually sounds pretty overwhelming… OR… is it a COMFORTING fact that “docs are never done”… so don’t expect them to be! You’ll never get there! You CAN’T get there.&lt;/p&gt;
  145. &lt;p&gt;&lt;strong&gt;You don’t have to WORRY about getting there.&lt;/strong&gt;&lt;/p&gt;
  146. &lt;p&gt;&lt;img alt=&quot; A version of the Drake/woman two square meme with two blue jays, one disliking the statement Docs Are Never Done with the second jay looking intrigued at the same sentence.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1043&quot; height=&quot;646&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fdocsneverdone.DHH4pbZY.png&amp;amp;w=1043&amp;amp;h=646&quot;&gt;&lt;/p&gt;
  147. &lt;p&gt;With docs, you CANNOT, you must not, let “the perfect” be the enemy of:&lt;/p&gt;
  148. &lt;ul&gt;
  149. &lt;li&gt;the good.&lt;/li&gt;
  150. &lt;li&gt;the good &lt;em&gt;enough&lt;/em&gt;.&lt;/li&gt;
  151. &lt;li&gt;the #NWTWWHB. (Not worse than what we had before)&lt;/li&gt;
  152. &lt;/ul&gt;
  153. &lt;p&gt;My name is Sarah, and I’m the docs lead at Astro.&lt;/p&gt;
  154. &lt;p&gt;I hope in just a few minutes’ time, you’ll see how achievable “better” docs are, even without:&lt;/p&gt;
  155. &lt;ul&gt;
  156. &lt;li&gt;… a technical writer&lt;/li&gt;
  157. &lt;li&gt;… a team of volunteers&lt;/li&gt;
  158. &lt;li&gt;… writing experience&lt;/li&gt;
  159. &lt;li&gt;… a lot of time&lt;/li&gt;
  160. &lt;/ul&gt;
  161. &lt;p&gt;Whether you’re:&lt;/p&gt;
  162. &lt;ul&gt;
  163. &lt;li&gt;
  164. &lt;p&gt;… crafting your very first README&lt;/p&gt;
  165. &lt;/li&gt;
  166. &lt;li&gt;
  167. &lt;p&gt;… adding the changeset for your next PR&lt;/p&gt;
  168. &lt;/li&gt;
  169. &lt;li&gt;
  170. &lt;p&gt;… preparing a guide for using a new feature&lt;/p&gt;
  171. &lt;/li&gt;
  172. &lt;li&gt;
  173. &lt;p&gt;… starting to think about redesigning your entire documentation site (hint: Starlight!)&lt;/p&gt;
  174. &lt;/li&gt;
  175. &lt;/ul&gt;
  176. &lt;p&gt;I’m going to make your docs better, I’m going to make YOU a better, more confident docs writer, without doing much WRITING at all!&lt;/p&gt;
  177. &lt;p&gt;&lt;img alt=&quot;A small sparrow standing on a bridge railing amid seeds with an upturned, confused head position.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1110&quot; height=&quot;573&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fwhyhavedocs.BAbtLo4H.png&amp;amp;w=1110&amp;amp;h=573&quot;&gt;&lt;/p&gt;
  178. &lt;p&gt;Why do projects have documentation? Why do &lt;em&gt;you&lt;/em&gt; have docs, if you do, for your project?&lt;/p&gt;
  179. &lt;p&gt;You might have said, “to document an API” or “to show how to use a feature” or “explain what the project is.”&lt;/p&gt;
  180. &lt;p&gt;I would argue, the sole purpose of documentation, the only reason it exists, is to be helpful.&lt;/p&gt;
  181. &lt;ul&gt;
  182. &lt;li&gt;&lt;strong&gt;internal docs:&lt;/strong&gt; help with cross-team collaboration and onboarding&lt;/li&gt;
  183. &lt;li&gt;&lt;strong&gt;external docs:&lt;/strong&gt; help people understand, evaluate and use your project&lt;/li&gt;
  184. &lt;li&gt;&lt;strong&gt;open source docs:&lt;/strong&gt; help people contribute to your project&lt;/li&gt;
  185. &lt;/ul&gt;
  186. &lt;p&gt;&lt;img alt=&quot;Three blue jays standing in a row, each labelled as a different kind of docs: internal, external, open source&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1145&quot; height=&quot;641&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Ftypesofdocs.wQxOJ9SB.png&amp;amp;w=1145&amp;amp;h=641&quot;&gt;&lt;/p&gt;
  187. &lt;p&gt;Documentation even helps &lt;strong&gt;you&lt;/strong&gt; as you’re building, making design decisions, learning, and leaving yourself notes.&lt;/p&gt;
  188. &lt;p&gt;Documentation is… a source of truth, docs is support, docs is record-keeping, docs is even marketing, promotion and community building …&lt;/p&gt;
  189. &lt;p&gt;&lt;img alt=&quot;A small structure covered in grafitti with crows on top listing all the things docs is from the previous sentence.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1147&quot; height=&quot;646&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fdocsis.CnJLvZXF.png&amp;amp;w=1147&amp;amp;h=646&quot;&gt;&lt;/p&gt;
  190. &lt;p&gt;… but ultimately docs &lt;strong&gt;exist&lt;/strong&gt; to &lt;em&gt;help&lt;/em&gt;.&lt;/p&gt;
  191. &lt;p&gt;Remember when I asked at the beginning, “Are your docs ‘good’?” How did that make you feel? Was that an easy question to answer?&lt;/p&gt;
  192. &lt;p&gt;What if I ask instead, “Are your docs &lt;em&gt;helpful&lt;/em&gt;”?&lt;/p&gt;
  193. &lt;p&gt;For many people, I think that second question feels different.&lt;/p&gt;
  194. &lt;p&gt;&lt;img alt=&quot;Two blue jays, one looking drab and disgruntled under the word good. The second blue jay has wings outstretched as if showing off under the word helpful&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1117&quot; height=&quot;630&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fgoodhelpful.B65cILqA.png&amp;amp;w=1117&amp;amp;h=630&quot;&gt;&lt;/p&gt;
  195. &lt;p&gt;Changing the question you ask will immediately put you on the path to “better” docs… more helpful docs!&lt;/p&gt;
  196. &lt;p&gt;Notice that this ALSO changed the task of making docs from primarily a &lt;em&gt;writing&lt;/em&gt; task to a &lt;em&gt;helping&lt;/em&gt; task!&lt;/p&gt;
  197. &lt;p&gt;And, YOU ARE the foremost expert on your project, so you are the BEST person to help!&lt;/p&gt;
  198. &lt;div&gt;&lt;h2 id=&quot;are-your-docs-helpful&quot;&gt;”Are your docs helpful?”&lt;/h2&gt;&lt;/div&gt;
  199. &lt;p&gt;&lt;img alt=&quot;&amp;quot;&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1147&quot; height=&quot;642&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fareyourdocshelpful.3wi_k-v-.png&amp;amp;w=1147&amp;amp;h=642&quot;&gt;&lt;/p&gt;
  200. &lt;p&gt;So how do we answer this question?&lt;/p&gt;
  201. &lt;p&gt;We begin to answer it by first understanding that it’s really a collection of questions, that start with the phrase:&lt;/p&gt;
  202. &lt;p&gt;Is this helping someone…&lt;/p&gt;
  203. &lt;ul&gt;
  204. &lt;li&gt;get started with my project&lt;/li&gt;
  205. &lt;li&gt;figure out what my project is or does?&lt;/li&gt;
  206. &lt;li&gt;evaluate whether it’s right for their needs? (so you get the &lt;em&gt;right&lt;/em&gt; users in the first place!)&lt;/li&gt;
  207. &lt;li&gt;accomplish their OWN goals using MY project (e.g. add authentication to password protect some pages)&lt;/li&gt;
  208. &lt;li&gt;troubleshoot something in their project that’s not working as expected&lt;/li&gt;
  209. &lt;li&gt;use my project to the fullest&lt;/li&gt;
  210. &lt;li&gt;avoid common pitfalls&lt;/li&gt;
  211. &lt;li&gt;keep up with the latest changes in my project, so they can successfully update &lt;em&gt;their&lt;/em&gt; project&lt;/li&gt;
  212. &lt;/ul&gt;
  213. &lt;p&gt;Evaluating whether your docs are&lt;/p&gt;
  214. &lt;ul&gt;
  215. &lt;li&gt;HELPFUL&lt;/li&gt;
  216. &lt;li&gt;helpful TO SOMEONE&lt;/li&gt;
  217. &lt;li&gt;helpful to someone FOR SOMETHING&lt;/li&gt;
  218. &lt;/ul&gt;
  219. &lt;p&gt;… will get you further, faster, than any other single docs intervention.&lt;/p&gt;
  220. &lt;p&gt;&lt;img alt=&quot;&amp;quot;&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1143&quot; height=&quot;643&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fdocsmustbehelpfulto.J47P8GFf.png&amp;amp;w=1143&amp;amp;h=643&quot;&gt;&lt;/p&gt;
  221. &lt;p&gt;&lt;img alt=&quot;&amp;quot;&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1147&quot; height=&quot;644&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Ftosomeoneforsomething.C-D8Xx7K.png&amp;amp;w=1147&amp;amp;h=644&quot;&gt;&lt;/p&gt;
  222. &lt;p&gt;Your docs can only be helpful &lt;strong&gt;to someone&lt;/strong&gt; and that someone…&lt;/p&gt;
  223. &lt;p&gt;Helpful TO SomeONE WHO IS:&lt;/p&gt;
  224. &lt;ul&gt;
  225. &lt;li&gt;Human&lt;/li&gt;
  226. &lt;li&gt;(With needs/wants/desires/hopes/dreams)&lt;/li&gt;
  227. &lt;li&gt;In a particular mood&lt;/li&gt;
  228. &lt;/ul&gt;
  229. &lt;p&gt;WHO HAS:&lt;/p&gt;
  230. &lt;ul&gt;
  231. &lt;li&gt;Context&lt;/li&gt;
  232. &lt;li&gt;Goals/purpose&lt;/li&gt;
  233. &lt;li&gt;Motivations, expectations&lt;/li&gt;
  234. &lt;/ul&gt;
  235. &lt;p&gt;WITH A CERTAIN EXPERIENCE LEVEL WITH:&lt;/p&gt;
  236. &lt;ul&gt;
  237. &lt;li&gt;Code&lt;/li&gt;
  238. &lt;li&gt;The industry&lt;/li&gt;
  239. &lt;li&gt;Your project&lt;/li&gt;
  240. &lt;/ul&gt;
  241. &lt;p&gt;WITH VARYING&lt;/p&gt;
  242. &lt;ul&gt;
  243. &lt;li&gt;Language proficiencies&lt;/li&gt;
  244. &lt;li&gt;Bad experiences (“burned before”)&lt;/li&gt;
  245. &lt;li&gt;Pre- or (mis) conceptions&lt;/li&gt;
  246. &lt;/ul&gt;
  247. &lt;p&gt;AND ONLY LIMITED&lt;/p&gt;
  248. &lt;ul&gt;
  249. &lt;li&gt;Attention&lt;/li&gt;
  250. &lt;li&gt;Patience&lt;/li&gt;
  251. &lt;li&gt;Time&lt;/li&gt;
  252. &lt;li&gt;Energy&lt;/li&gt;
  253. &lt;li&gt;Resources (internet speed/cap, hardware)&lt;/li&gt;
  254. &lt;/ul&gt;
  255. &lt;p&gt;They also need to help someone &lt;strong&gt;do something&lt;/strong&gt;:&lt;/p&gt;
  256. &lt;ul&gt;
  257. &lt;li&gt;Learn&lt;/li&gt;
  258. &lt;li&gt;Conceptualize&lt;/li&gt;
  259. &lt;li&gt;Evaluate&lt;/li&gt;
  260. &lt;li&gt;Achieve&lt;/li&gt;
  261. &lt;li&gt;Build&lt;/li&gt;
  262. &lt;li&gt;Fix&lt;/li&gt;
  263. &lt;li&gt;Test&lt;/li&gt;
  264. &lt;li&gt;Upgrade&lt;/li&gt;
  265. &lt;li&gt;Improve&lt;/li&gt;
  266. &lt;li&gt;Experiment&lt;/li&gt;
  267. &lt;li&gt;Convince (themselves, someone else)&lt;/li&gt;
  268. &lt;li&gt;Solve a business problem or technical challlenge&lt;/li&gt;
  269. &lt;/ul&gt;
  270. &lt;p&gt;But, docs should ultimately be helpful at getting people OUT of docs, and back into (using) your project.&lt;/p&gt;
  271. &lt;p&gt;&lt;img alt=&quot;An eagle flying away over water&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1146&quot; height=&quot;644&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Foutofdocs.BRkq9Kno.png&amp;amp;w=1146&amp;amp;h=644&quot;&gt;&lt;/p&gt;
  272. &lt;p&gt;Now, let’s look at some characteristics of &lt;strong&gt;helpful documentation&lt;/strong&gt;:&lt;/p&gt;
  273. &lt;div&gt;&lt;h2 id=&quot;clear-and-correct&quot;&gt;CLEAR AND CORRECT&lt;/h2&gt;&lt;/div&gt;
  274. &lt;blockquote&gt;
  275. &lt;p&gt;If your docs are wrong, they are not helpful.&lt;/p&gt;
  276. &lt;/blockquote&gt;
  277. &lt;p&gt;If docs are factually wrong, if they’re misleading, if they’re outdated, if they’re technically correct but so confusing you’d never know it… they are not correct. They are WRONG.&lt;/p&gt;
  278. &lt;p&gt;You might even have some existing documentation that … isn’t really helping anyone do anything! Instead, it’s more words on the screen making it harder to see the helpful content!&lt;/p&gt;
  279. &lt;p&gt;Action Items:&lt;/p&gt;
  280. &lt;ul&gt;
  281. &lt;li&gt;Read every statement in your docs for ACCURACY&lt;/li&gt;
  282. &lt;li&gt;Or, if you’re starting fresh, ONLY WRITE TRUE STATEMENTS&lt;/li&gt;
  283. &lt;li&gt;Go through each part of your docs and identify WHO this helps, and WHAT it helps them do&lt;/li&gt;
  284. &lt;li&gt;Less is more: both in content AND in style!&lt;/li&gt;
  285. &lt;li&gt;Use clear, simple language: No one ever complained, “Gee, these docs are just &lt;a href=&quot;https://vimeo.com/238673931#t=2045s&quot;&gt;too easy to read&lt;/a&gt;!”&lt;/li&gt;
  286. &lt;/ul&gt;
  287. &lt;p&gt;&lt;img alt=&quot;Screenshot of Ashley Bischoff giving a talk called 1Up Your Writing with Plain Language at Fronteers Conference 2017 and a slide that reads Because no one has ever complained that somethign was too easy to read.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1332&quot; height=&quot;715&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Ftooeasytoread.CuaaC9L1.png&amp;amp;w=1332&amp;amp;h=715&quot;&gt;&lt;/p&gt;
  288. &lt;p&gt;If you’re not sure whether something in your docs is entirely clear and correct, and you can’t immediately see how to make it better… REMOVE IT:&lt;/p&gt;
  289. &lt;blockquote&gt;
  290. &lt;p&gt;&lt;em&gt;“No documentation means I go look somewhere else for information. Incorrect documentation means I waste my time.”&lt;/em&gt; - Mason Egger&lt;/p&gt;
  291. &lt;/blockquote&gt;
  292. &lt;p&gt;Incorrect docs reduce credibility. They can make people frustrated enough to stop using your project and choose another.&lt;/p&gt;
  293. &lt;p&gt;If your users can’t be successful, then they do NOT use your project; they DON’T spread word of mouth (at least, not the good kind), they don’t create items themselves that showcase your project. And they don’t contribute back and improve your project.&lt;/p&gt;
  294. &lt;p&gt;&lt;img alt=&quot;Two ducks swimming, one with a cursing emoji face over its head representing incorrect docs. The second is a duckling looking up sweetly representing the friendlier reaction when you have incomplete docs, as if asking &amp;quot;Could you add...?&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1147&quot; height=&quot;642&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fincorrectincomplete.CWF50lse.png&amp;amp;w=1147&amp;amp;h=642&quot;&gt;&lt;/p&gt;
  295. &lt;p&gt;If it’s not clear, and correct… delete it! I am giving you permission! It wasn’t helping you anyway! It was frustrating people trying to use your project and potentially generating ill will and bad vibes!&lt;/p&gt;
  296. &lt;p&gt;If you’re worried you might have deleted something important, it’s fine. It’s the internet! Someone will tell you.&lt;/p&gt;
  297. &lt;p&gt;&lt;img alt=&quot;An XKCD cartoon where someone is on the computer, saying they can&amp;amp;#x27;t come to bed yet because someone is wrong on the internet&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1142&quot; height=&quot;643&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fwrongoninternet.BTF0Y3sI.png&amp;amp;w=1142&amp;amp;h=643&quot;&gt;&lt;/p&gt;
  298. &lt;p&gt;CHECK IN: Congratulations! You’ve made your docs better and you haven’t written a single thing!&lt;/p&gt;
  299. &lt;p&gt;We’re going to take things one step further and make your docs even more helpful:&lt;/p&gt;
  300. &lt;div&gt;&lt;h2 id=&quot;navigable-and-discoverable&quot;&gt;Navigable and Discoverable&lt;/h2&gt;&lt;/div&gt;
  301. &lt;ul&gt;
  302. &lt;li&gt;
  303. &lt;p&gt;Can people move around your documentation and find what they need?&lt;/p&gt;
  304. &lt;/li&gt;
  305. &lt;li&gt;
  306. &lt;p&gt;Are things where people expect to look? If they first look in the wrong spot, can they easily GET to the right spot?&lt;/p&gt;
  307. &lt;/li&gt;
  308. &lt;/ul&gt;
  309. &lt;p&gt;These concepts relate to Information Architecture, and you can get into things like “signposts”, “escape hatches/off ramps”. These are all the structural things we add to our documentation to help people quickly and easily situate themselves and move around.&lt;/p&gt;
  310. &lt;p&gt;When someone lands in your your docs, can they get where they need to go before they lose hope? And remember that a lot of people will enter your documentation via a web search, and not necessarily “&lt;a href=&quot;https://everypageispageone.com/&quot;&gt;on page one&lt;/a&gt;.” So &lt;em&gt;every&lt;/em&gt; page you have needs to pull their own weight. This is &lt;em&gt;not&lt;/em&gt; just a task for a landing page.&lt;/p&gt;
  311. &lt;p&gt;The good news though, if there’s only one page, your reader can’t be on the wrong page.&lt;/p&gt;
  312. &lt;p&gt;&lt;img alt=&quot;A book cover titled Every Page is Page One next to the thinking, pointing at brain meme&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;984&quot; height=&quot;529&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fpageone.CQgXcS2B.png&amp;amp;w=984&amp;amp;h=529&quot;&gt;&lt;/p&gt;
  313. &lt;p&gt;I’m serious! If you don’t know how to structure your content, there is nothing wrong with one huge README to start! Even if your readers have to look around, at least they’ll know they’re on the right page!&lt;/p&gt;
  314. &lt;p&gt;If the only reason docs exist is to be HELPFUL, to SOMEONE, trying to DO SOMETHING, then the first step in organizing your content is thinking about how to get your readers to the material that actually helps them accomplish the task they came for. e.g.:&lt;/p&gt;
  315. &lt;ul&gt;
  316. &lt;li&gt;If they are coming to quickly look up a reference value, like a property name or config option, make sure they don’t get stuck in an onboarding tutorial!&lt;/li&gt;
  317. &lt;li&gt;If they want to learn about what needs your project solves so they can decide whether to use it, don’t make them get stuck in implementation details before they even know what it is or does!&lt;/li&gt;
  318. &lt;/ul&gt;
  319. &lt;p&gt;Here’s where a framework like &lt;a href=&quot;https://diataxis.fr&quot;&gt;Diataxis&lt;/a&gt; can be helpful: by identifying parts of your documentation by &lt;strong&gt;content type&lt;/strong&gt; and &lt;strong&gt;reader goal&lt;/strong&gt;, you can logically group sections of your docs and start to provide a helpful structure.&lt;/p&gt;
  320. &lt;p&gt;But the key thing is, if someone is not reading your docs like a book, top-to-bottom, first-page to last-page, do you have a plan for how will they discover and navigate to the clear, correct information they need?&lt;/p&gt;
  321. &lt;p&gt;Action item:&lt;/p&gt;
  322. &lt;ul&gt;
  323. &lt;li&gt;go to literally any random point in your documentation, and imagine you are a reader who is not in the right place to get the info you need for a particular goal. Think about how your docs could direct them there, quickly and accurately.&lt;/li&gt;
  324. &lt;li&gt;Is this solved by a TOC? a search widget? a “How to read these docs” page? an internal link?&lt;/li&gt;
  325. &lt;li&gt;If you have multiple pages or files, do the titles accurately represent the content? Does your content live under the title you’d expect?&lt;/li&gt;
  326. &lt;/ul&gt;
  327. &lt;p&gt;So, at this point, I’ve now basically said: Don’t lie (and, delete any lies), and don’t hide stuff (if you have to, throw everything on a single page. Good news, CTRL+F works for everyone!).&lt;/p&gt;
  328. &lt;p&gt;This is, I think, STILL an achievable bar for docs that help your readers without any new writing!&lt;/p&gt;
  329. &lt;p&gt;If every statement in your docs is true, and people can find, read and understand what they mean… Congratulations! You have Minimum Viable Docs! (&lt;em&gt;whispers If you have to, you can stop now&lt;/em&gt;)&lt;/p&gt;
  330. &lt;p&gt;&lt;img alt=&quot;A sparrow on a wooden boardwalk with the title Minimum Viable Docs - Clear and Correct (no lies), Discoverable and Navigable (no hiding)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1145&quot; height=&quot;644&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fmvd.DTfb0LPl.png&amp;amp;w=1145&amp;amp;h=644&quot;&gt;&lt;/p&gt;
  331. &lt;p&gt;But, of &lt;em&gt;course&lt;/em&gt;, there &lt;em&gt;are&lt;/em&gt; characteristics of well-written docs, and there are also some pretty common anti-patterns.&lt;/p&gt;
  332. &lt;p&gt;There’s no shortage of talks on “how to write good documenation” that go into specifics, and I DO recommend you check out some great ones if you want to get better at writing! But that can get overwhelming and we already know that WRITING is secondary to HELPING.&lt;/p&gt;
  333. &lt;p&gt;&lt;img alt=&quot;A collage of images of various resource; talks, books, podcasts that are linked from ths post.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1146&quot; height=&quot;641&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fresources.BkVLsn0o.png&amp;amp;w=1146&amp;amp;h=641&quot;&gt;&lt;/p&gt;
  334. &lt;ul&gt;
  335. &lt;li&gt;It might feel like there’s a scary Docs Police waiting to criticize you and that there are a lot of potential failure pitfalls.&lt;/li&gt;
  336. &lt;li&gt;Instead of thinking of these as things to worry about getting wrong, think of them as things that you DON’T have to worry about; things NOT TO DO because they are NOT YOUR JOB as a helper.&lt;/li&gt;
  337. &lt;li&gt;These things “thou shalt not do” actually REMOVE pressure and responsibility, and are guard rails to keep you focused on a productive path towards helping.&lt;/li&gt;
  338. &lt;/ul&gt;
  339. &lt;p&gt;&lt;img alt=&quot;A screenshot of a pulll request suggested edit made by Sarah. The original was a very long, excited description about installing Bun, and the suggested change for docs is simply: Use the following command to install Bun, with the added note Booo... Sarah is boring!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;917&quot; height=&quot;315&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fboo.CB3rkFL1.png&amp;amp;w=917&amp;amp;h=315&quot;&gt;&lt;/p&gt;
  340. &lt;p&gt;So, I absolutely love this social media post, because it perfectly demonstrates everything we’ve been talking about here.&lt;/p&gt;
  341. &lt;p&gt;It’s CLEAR, and CORRECT. If you’re looking for the command to install Bun, these are the words you will search for! It introduces exactly what’s coming next, and it’s not hidden in a bunch of other words.&lt;/p&gt;
  342. &lt;p&gt;This edit is NOT me saying, “BAD AUTHOR, BAD DOCS!”&lt;/p&gt;
  343. &lt;p&gt;This edit is me freeing the pull request submitter from the responsibility to:&lt;/p&gt;
  344. &lt;ul&gt;
  345. &lt;li&gt;write something clever&lt;/li&gt;
  346. &lt;li&gt;motivate the reader&lt;/li&gt;
  347. &lt;li&gt;get all the punctuation correct in longer, multi-clause sentences&lt;/li&gt;
  348. &lt;li&gt;have 10 times as many words to proofread and spellcheck&lt;/li&gt;
  349. &lt;/ul&gt;
  350. &lt;p&gt;My edit reminds you to focus on “helping” instead of “writing.”&lt;/p&gt;
  351. &lt;p&gt;Similarly, many other “Docs Don’ts” are actually “don’t worry abouts!”&lt;/p&gt;
  352. &lt;p&gt;If less is more, then here are some things you can remove or stop doing that reduce clutter and confusion in your docs.&lt;/p&gt;
  353. &lt;p&gt;&lt;img alt=&quot;&amp;quot;&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1137&quot; height=&quot;639&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fwe.Bn8xqECX.png&amp;amp;w=1137&amp;amp;h=639&quot;&gt;&lt;/p&gt;
  354. &lt;ol&gt;
  355. &lt;li&gt;Don’t use “we”, because you’re not sitting there with your potentially frustrated reader
  356. &lt;ul&gt;
  357. &lt;li&gt;This frees you from the extra work of checking that all your we/us/our/let’s all agree. You know what’s super easy to check? You and your.&lt;/li&gt;
  358. &lt;li&gt;Using “you” also naturally puts the emphasis on your reader, and what they are doing. It guides you to thinking about helping THEM. (What might THEIR set up look like? instead of writing “our” which can trick you into thinking about your OWN context or situation that your reader might not share.)&lt;/li&gt;
  359. &lt;li&gt;Often, these instructions work without any “you” at all, and become even clearer.&lt;/li&gt;
  360. &lt;/ul&gt;
  361. &lt;/li&gt;
  362. &lt;/ol&gt;
  363. &lt;p&gt;&lt;img alt=&quot;&amp;quot;&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1149&quot; height=&quot;638&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fshould.Wi1eN3TI.png&amp;amp;w=1149&amp;amp;h=638&quot;&gt;&lt;/p&gt;
  364. &lt;ol start=&quot;2&quot;&gt;
  365. &lt;li&gt;Don’t use “should” - Should implies uncertainty, and your readers are looking to YOU for what to do. If your reader really MUST do something, just say that.
  366. &lt;ul&gt;
  367. &lt;li&gt;Again, sounds like a rule we just made up! But I guarantee you that we are freeing you from feedback from a confused reader!&lt;/li&gt;
  368. &lt;li&gt;“You should create a new folder for your blog posts.” Do I… have to do this? What happens if I don’t, and how bad is that? What else could I do?&lt;/li&gt;
  369. &lt;li&gt;Not only do your sentences get clearer, but your reader stays laser-focused on the task at hand without any doubt. -&gt; Create a new folder for your blog posts.&lt;/li&gt;
  370. &lt;li&gt;I am giving you permission to avoid writing, and just tell someone directly what to do! Even when more things are possible, if you WANT them to do this to have a successful outcome, just say it that way. THIS FREES YOU from the responsibility of describing every possible path when you, the expert in your own project, already have a recommendation and know the happy path. You can help. Don’t write. Just help.&lt;/li&gt;
  371. &lt;/ul&gt;
  372. &lt;/li&gt;
  373. &lt;/ol&gt;
  374. &lt;p&gt;ACTION ITEMS:&lt;/p&gt;
  375. &lt;ul&gt;
  376. &lt;li&gt;Don’t stress out about writing rules, but embrace them as telling you things that aren’t your responsibility!&lt;/li&gt;
  377. &lt;li&gt;Pick one or two (I suggest “we” and “should”), or just read through your docs looking for things that aren’t your responsibility, and remove them!&lt;/li&gt;
  378. &lt;/ul&gt;
  379. &lt;p&gt;In conclusion, think of yourself as a HELPER. Someone who just happens to be helping in writing.&lt;/p&gt;
  380. &lt;ul&gt;
  381. &lt;li&gt;helpers don’t need to entertain or write beautiful stories&lt;/li&gt;
  382. &lt;li&gt;they need to make CLEAR, CORRECT information available. Ideally in such a way that readers can DISCOVER, and NAVIGATE it. (CTRL+F is your friend!)&lt;/li&gt;
  383. &lt;/ul&gt;
  384. &lt;p&gt;And The best help is CONTEXTUAL: it is FOR someone who is trying to DO something specific.&lt;/p&gt;
  385. &lt;ul&gt;
  386. &lt;li&gt;this person may also not be in the greatest state to RECIEVE help, but they are in your docs because they need it.&lt;/li&gt;
  387. &lt;li&gt;don’t overwhelm. Less is always more.&lt;/li&gt;
  388. &lt;li&gt;You can probably improve your docs RIGHT NOW by &lt;em&gt;deleting&lt;/em&gt;, not writing more!
  389. &lt;ul&gt;
  390. &lt;li&gt;delete words like “should”; delete outdated or unmaintained docs, even if you can’t yet replace them; delete entire pages if you are afraid people won’t find them, and put everything on one page if you need to!&lt;/li&gt;
  391. &lt;/ul&gt;
  392. &lt;/li&gt;
  393. &lt;/ul&gt;
  394. &lt;p&gt;&lt;img alt=&quot;A shiny black and purple grackle amid the words Don&amp;amp;#x27;t write, help: clear &amp;amp;#x26; correct; discoverable; navigable; contextual; for someone; to do something; less is more&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1142&quot; height=&quot;630&quot; src=&quot;https://www.rainsberger.ca/.netlify/images?url=_astro%2Fdontwritehelp.CI9oSO_g.png&amp;amp;w=1142&amp;amp;h=630&quot;&gt;&lt;/p&gt;
  395. &lt;p&gt;You can have great docs even if you aren’t a great writer. Because in many cases, maybe even most of the time, the less you write, the more you help.&lt;/p&gt;&lt;!-- Everything in docs must be true, but, not everything that is true belongs in docs... in part because not every true statement is *helpful*.
  396.  
  397. Incomplete documentation is not a crime, it&apos;s an invitation. Invite your readers to help you help them, and tell you what&apos;s missing. It is not your responsibility to
  398.  
  399. If you can&apos;t imagine a situation in which someone might need this information to accomplish a specific task, then why is it there? --&gt;
  400. &lt;div&gt;&lt;h2 id=&quot;references-and-resources&quot;&gt;References and Resources&lt;/h2&gt;&lt;/div&gt;
  401. &lt;ul&gt;
  402. &lt;li&gt;&lt;a href=&quot;https://diataxis.fr&quot;&gt;Diataxis&lt;/a&gt;&lt;/li&gt;
  403. &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=9WobKoE9OPI&quot;&gt;Talk - Mason Egger: Write Docs Devs Love: Ten Tips To Level Up Your Tech Writing&lt;/a&gt;&lt;/li&gt;
  404. &lt;li&gt;&lt;a href=&quot;https://vimeo.com/238673931#t=2045s&quot;&gt;Talk - Ashley Bischoff: “1Up Your Writing with Plain Language” at Fronteers Conference 2017&lt;/a&gt;&lt;/li&gt;
  405. &lt;li&gt;&lt;a href=&quot;https://docsfordevelopers.com/&quot;&gt;Book - Docs for Developers&lt;/a&gt;&lt;/li&gt;
  406. &lt;li&gt;&lt;a href=&quot;https://writeusefulbooks.com/&quot;&gt;Book - Write Useful Books&lt;/a&gt;&lt;/li&gt;
  407. &lt;li&gt;&lt;a href=&quot;https://xmlpress.net/publications/eppo/&quot;&gt;Book - Every Page is Page One&lt;/a&gt;&lt;/li&gt;
  408. &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YW4IfoJM30g&quot;&gt;Audio - Making Documentation Developers Love&lt;/a&gt;&lt;/li&gt;
  409. &lt;/ul&gt;</content:encoded><category>docs</category><category>open source</category><category>conference talks</category></item><item><title>The value of non-code contributions to open source</title><link>https://www.rainsberger.ca/blog/non-code-contributions/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/non-code-contributions/</guid><description>One of the most rewarding parts about leading Astro Docs is welcoming non-code contributors to open source! We still have work to do, but the open source community is slowly starting to realize (and capitalize on!) the value of writers, translators, designers, testers, content creators, speakers, community support members.
  410.  
  411. </description><pubDate>Sat, 20 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;the-value-of-non-code-contributions&quot;&gt;The value of non-code contributions&lt;/h2&gt;&lt;/div&gt;
  412. &lt;p&gt;I’ve heard people speak dismissively of PRs that fix a typo or update a broken link. But, maybe that speaks to attitudes towards docs in general, and we won’t get into that…&lt;/p&gt;
  413. &lt;p&gt;But, if you are a project maintainer who cares about helping and encouraging others to &lt;em&gt;use&lt;/em&gt; your work, attention to these little details conveys a big message to your community. Typos are distracting. Broken links are frustrating!&lt;/p&gt;
  414. &lt;p&gt;Installation instructions that aren’t clear mean some people aren’t installing your package. And, it can project an image of sloppiness that reflects on your code, even if that’s not the case! Great design elements in your product add polish, and a carefully-designed logo and marketing website adds brand awareness. Testing your product, or participating in user experience testing, can expose uncaught weaknesses and highlight areas for improvement.&lt;/p&gt;
  415. &lt;p&gt;When the community translates your docs, you gain a wider audience. When someone speaks about your product at a conference or writes a guide to using your project, new people learn about your work and how it can solve their problems.&lt;/p&gt;
  416. &lt;p&gt;When people who don’t contribute code actively participate in your online community spaces, other members get help and feel supported while they code. And then &lt;em&gt;they&lt;/em&gt; might choose to contribute back. Sometimes, by offering more community support, and sometimes in the form of code itself… that they learned from your non-code contributing community peeps!&lt;/p&gt;
  417. &lt;div&gt;&lt;h2 id=&quot;supporting-non-code-contributors&quot;&gt;Supporting non-code contributors&lt;/h2&gt;&lt;/div&gt;
  418. &lt;p&gt;It’s especially important to be supportive of non-code contributors who may &lt;em&gt;already&lt;/em&gt; feel under-valued or less-than because they are “only” contributing to docs, design, support, testing or product awareness and advocacy. They might also think that devs “just know” how to navigate all the intricacies of GitHub, and so asking for help is further branding them as non-code peeps. (Spoiler alert: knowing how to submit a PR on GitHub is &lt;em&gt;not&lt;/em&gt; a skill automatically conferred by knowing how to sling bits!)&lt;/p&gt;
  419. &lt;div&gt;&lt;h2 id=&quot;new-contributor--code-newbie&quot;&gt;&lt;strong&gt;New contributor !== code newbie:&lt;/strong&gt;&lt;/h2&gt;&lt;/div&gt;
  420. &lt;p&gt;Contributing to open source, knowing the process of submitting PRs or the conventions of your project, can be overwhelming or intimidating for &lt;em&gt;anyone&lt;/em&gt; who’s never done it before, regardless of coding ability.&lt;/p&gt;
  421. &lt;p&gt;That’s why non-code contributions can be great onboarding experiences for your future code contributors! There is little practical difference when submitting a PR and navigating the GitHub process between code and non-code contributions. A non-code contribution can be a gentle way for a first-time contributor to figure out the actual act of contributing before &lt;em&gt;also&lt;/em&gt; worrying about how their code will be received or judged by a project maintainer.&lt;/p&gt;</content:encoded><category>docs</category><category>open source</category></item><item><title>Astro&apos;s Community-Driven Docs</title><link>https://www.rainsberger.ca/blog/community-driven-astro-docs/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/community-driven-astro-docs/</guid><description>What community-driven means to Astro Docs.
  422.  
  423. </description><pubDate>Fri, 04 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This was orignally written in early June 2022, in response to the question, “Have you written anything about your community-driven approach to Docs at Astro?” My first response was, “Give me a few days.” My second response was this.&lt;/em&gt;&lt;/p&gt;
  424. &lt;div&gt;&lt;h2 id=&quot;community-driven&quot;&gt;Community-Driven&lt;/h2&gt;&lt;/div&gt;
  425. &lt;p&gt;To us, community-driven means:&lt;/p&gt;
  426. &lt;ul&gt;
  427. &lt;li&gt;
  428. &lt;p&gt;&lt;strong&gt;collaborative&lt;/strong&gt; - docs are reviewed, discussed and approved publicly on GitHub&lt;/p&gt;
  429. &lt;/li&gt;
  430. &lt;li&gt;
  431. &lt;p&gt;&lt;strong&gt;responsive&lt;/strong&gt; - docs are written not just abstractly keeping the reader in mind, but often directly in response to stated or observed needs from the community&lt;/p&gt;
  432. &lt;/li&gt;
  433. &lt;li&gt;
  434. &lt;p&gt;&lt;strong&gt;participatory&lt;/strong&gt; - docs are open to contributions (of any type) from any member of the community&lt;/p&gt;
  435. &lt;/li&gt;
  436. &lt;/ul&gt;
  437. &lt;div&gt;&lt;h2 id=&quot;pr-process&quot;&gt;PR Process&lt;/h2&gt;&lt;/div&gt;
  438. &lt;p&gt;What makes us slow, makes us grow!&lt;/p&gt;
  439. &lt;p&gt;Inspired by the collaborative nature of the Astro core project itself, no PR passes without an LGTM from at least one (other) Team Docs member.&lt;/p&gt;
  440. &lt;p&gt;&lt;em&gt;(Fun fact: since we are open to contributions from community members of all experience levels, many who contribute to our docs were unfamiliar with what LGTM stood for. Some ventured tentative guesses, many of which were way more fun than “Looks Good To Me.” After exploring various alternatives, our current favourite is, &lt;strong&gt;“Let’s Get That Money!”&lt;/strong&gt;)&lt;/em&gt;&lt;/p&gt;
  441. &lt;p&gt;Does it make it slower that we as maintainers don’t even merge our own PRs with a simple typo fix?&lt;/p&gt;
  442. &lt;p&gt;Yeah. But, we accept this tradeoff. It’s a simple way to ensure that an author didn’t inadvertently introduce a new typo to be fixed. But also, it means that:&lt;/p&gt;
  443. &lt;ul&gt;
  444. &lt;li&gt;
  445. &lt;p&gt;We &lt;strong&gt;encourage looking at the PRs regularly&lt;/strong&gt; so that everyone can be kept up to date with what is happening, to the extent that they want.&lt;/p&gt;
  446. &lt;/li&gt;
  447. &lt;li&gt;
  448. &lt;p&gt;We can easily &lt;strong&gt;receive contributions from &lt;em&gt;any&lt;/em&gt; community member&lt;/strong&gt; in the form of an LGTM, even if they are not willing or able to write content or do more time-consuming tasks such as reviewing an entire page or testing code examples.&lt;/p&gt;
  449. &lt;/li&gt;
  450. &lt;li&gt;
  451. &lt;p&gt;We naturally &lt;strong&gt;put built-in onboarding and guard rails in place&lt;/strong&gt; to be able to manage these contributions from such a wide range of contributors, and to be able to direct them to small PR contributions first.&lt;/p&gt;
  452. &lt;/li&gt;
  453. &lt;li&gt;
  454. &lt;p&gt;We &lt;strong&gt;demonstrate everything that goes into a docs site&lt;/strong&gt;, down to typo fixes, and model a diverse range of contributions for those wanting to get involved.&lt;/p&gt;
  455. &lt;/li&gt;
  456. &lt;li&gt;
  457. &lt;p&gt;We &lt;strong&gt;set realistic expectations of the process of “getting merged,”&lt;/strong&gt; and that not every idea immediately makes it into production. And, it gives explicit permission to think about the PR carefully, as well as to wait for other perspectives, or second-thoughts, to surface.&lt;/p&gt;
  458. &lt;/li&gt;
  459. &lt;li&gt;
  460. &lt;p&gt;We  &lt;strong&gt;provide an open opportunity for public proof of open source involvment&lt;/strong&gt;, and our contributors can claim and own this experience.&lt;/p&gt;
  461. &lt;/li&gt;
  462. &lt;/ul&gt;
  463. &lt;div&gt;&lt;h2 id=&quot;support-as-docs&quot;&gt;Support as Docs&lt;/h2&gt;&lt;/div&gt;
  464. &lt;p&gt;Long before there was a “Team Docs,” Astro had an active “Support Squad” role on Discord. Our approach to support has become the stuff of legends, and some people have chosen to use Astro, still in alpha itself until recently, on the basis of our community alone.&lt;/p&gt;
  465. &lt;p&gt;When “Team Docs” was established, many of our inaugural members were also seasoned Squaddies. We knew the questions people were asking in our support threads, and we had lots of practice answering them. It was natural for us to apply that experience to the docs.&lt;/p&gt;
  466. &lt;blockquote&gt;
  467. &lt;p&gt;If someone asks a question, answer with documentation. If the documentation doesn’t exist, write the documentation, then answer the question with documentation.
  468. Jen Luker
  469. &lt;a href=&quot;https://twitter.com/knitcodemonkey/status/1486214423190519811&quot;&gt;https://twitter.com/knitcodemonkey/status/1486214423190519811&lt;/a&gt;&lt;/p&gt;
  470. &lt;/blockquote&gt;
  471. &lt;p&gt;As a “newer” project with very few answers written on blogs or Stack Overflow, we knew that the only public place people were able to find answers was in our Discord channel. Team Docs had the advantage of knowing exactly what our users were asking. We could use this to steer our documentation decisions, to add or update content, and to prioritize.&lt;/p&gt;
  472. &lt;p&gt;We created crudely-categorized, monthly tallys of the general topics our users were asking about to point us to areas of existing documentation that could be improved. We also had a supply of raw content already written, and unsuspecting future docs contributors to get us started!&lt;/p&gt;
  473. &lt;p&gt;One regular task we have now incorporated into Team Docs is to go through support threads and be a little bolder about asking, “What could we have put in the docs that would have helped you out with this?” or “Where in the docs would you have expected to find this?” and to even suggest that thread participants (question askers and answerers alike) are welcome to make issues and PRs to the docs repo… partly to save &lt;em&gt;us&lt;/em&gt; from recreating what’s already in the thread, but also to encourage and onboard new contributors.&lt;/p&gt;
  474. &lt;div&gt;&lt;h2 id=&quot;rewriting-in-public&quot;&gt;(Re)Writing in Public&lt;/h2&gt;&lt;/div&gt;
  475. &lt;p&gt;Since we were the only game in town, our docs were not only &lt;strong&gt;our&lt;/strong&gt; single source of truth; they were &lt;strong&gt;the&lt;/strong&gt; single source of truth.&lt;/p&gt;
  476. &lt;p&gt;Although we knew our docs needed restructuring, they also needed to keep up with constantly evolving features that come with early version product changes. We didn’t feel that we could split our resources writing a second “idealized” set of docs from scratch behind the scenes while at the same time maintaining the only docs that existed for our community. They needed to work &lt;strong&gt;now&lt;/strong&gt;&lt;/p&gt;
  477. &lt;p&gt;We decided to edit existing content in place, guided by two key questions inspired by our Support Squad background:&lt;/p&gt;
  478. &lt;ul&gt;
  479. &lt;li&gt;
  480. &lt;p&gt;Is this content &lt;strong&gt;correct&lt;/strong&gt;?&lt;/p&gt;
  481. &lt;/li&gt;
  482. &lt;li&gt;
  483. &lt;p&gt;Is this content &lt;strong&gt;helpful&lt;/strong&gt;?&lt;/p&gt;
  484. &lt;/li&gt;
  485. &lt;/ul&gt;
  486. &lt;p&gt;Maybe our existing explanation on how page routing works in Astro was a little underwhelming. But if it was &lt;strong&gt;correct&lt;/strong&gt; and if it gave the reader some immediate &lt;strong&gt;help&lt;/strong&gt; to get them going or unstuck, it was serving its purpose until we could prioritize rewriting.&lt;/p&gt;
  487. &lt;div&gt;&lt;h2 id=&quot;how-can-i-help-if-i-have-some-time-today&quot;&gt;”How can I help, if I have some time today?”&lt;/h2&gt;&lt;/div&gt;
  488. &lt;p&gt;Now that we have a full-fledged Team Docs, I attempt to “wrangle” their efforts and energies by &lt;strong&gt;explicitly demonstrating how any member of the community can contribute&lt;/strong&gt;.&lt;/p&gt;
  489. &lt;p&gt;Regularly, I post messages in our Astro Discord #docs that answer what I (tongue-in-cheekly) assume to be everyone’s burning question, &lt;strong&gt;“How can I help, if I have some time today?”&lt;/strong&gt;&lt;/p&gt;
  490. &lt;p&gt;These answers might include anything (because, docs really does require a bit of &lt;em&gt;everything&lt;/em&gt;) as I attempt to push the boundaries of how we think of “docs,” and who is a “docs person.”&lt;/p&gt;
  491. &lt;p&gt;These “answers” are concrete, pointed tasks that I validate by explicitly asking for them.&lt;/p&gt;
  492. &lt;p&gt;Lots of people want to “help” but might feel overwhelmed about where to start, or unsure whether their contribution will be useful. They might not have a lot of time or energy, and might not realize just how valuable the smallest contribution can be, especially when my own typo fix might &lt;strong&gt;still&lt;/strong&gt; sitting in a PR!&lt;/p&gt;
  493. &lt;p&gt;Just some of the tasks I’ve highlighted include:&lt;/p&gt;
  494. &lt;ul&gt;
  495. &lt;li&gt;
  496. &lt;p&gt;reviewing particular PRs with a quick description of what it involves&lt;/p&gt;
  497. &lt;/li&gt;
  498. &lt;li&gt;
  499. &lt;p&gt;writing new content, in response to an existing issue&lt;/p&gt;
  500. &lt;/li&gt;
  501. &lt;li&gt;
  502. &lt;p&gt;testing a particular code sample or set of instructions&lt;/p&gt;
  503. &lt;/li&gt;
  504. &lt;li&gt;
  505. &lt;p&gt;fixes to the site or styling improvements&lt;/p&gt;
  506. &lt;/li&gt;
  507. &lt;li&gt;
  508. &lt;p&gt;researching something that needs to be written&lt;/p&gt;
  509. &lt;/li&gt;
  510. &lt;li&gt;
  511. &lt;p&gt;translating a particular word or phrase, if not an entire page&lt;/p&gt;
  512. &lt;/li&gt;
  513. &lt;li&gt;
  514. &lt;p&gt;brainstorming a list of “common error messages” for our new Troubleshooting page&lt;/p&gt;
  515. &lt;/li&gt;
  516. &lt;li&gt;
  517. &lt;p&gt;labeling issues and PRs, even if you don’t do anything with/about them&lt;/p&gt;
  518. &lt;/li&gt;
  519. &lt;/ul&gt;
  520. &lt;p&gt;… all the way down to simply stating a preference between two link colours! No contribution is too small!&lt;/p&gt;
  521. &lt;p&gt;And then when people do step up, we celebrate their efforts. We have added a “FacePile” to our main docs landing page showing the GitHub avatars of every contributor to the docs repo. We regularly show off our docs progress in our Discord Showcase channel, because our docs site &lt;em&gt;is&lt;/em&gt; a showcase of our community members’ efforts!&lt;/p&gt;
  522. &lt;div&gt;&lt;h2 id=&quot;aspirations&quot;&gt;Aspirations&lt;/h2&gt;&lt;/div&gt;
  523. &lt;p&gt;I do have some specific goals moving forward, and I hope that by building a solid community foundation around our docs site, we will be in a sustainable position to achieve them. It is easier for me, as docs lead, to step back and let the system chug along if I know that our regular docs maintenance process is well-established, and works even without me on the critical path.&lt;/p&gt;
  524. &lt;p&gt;I have even seen one of our lead translators from our i18n group start addressing their crew with their own delightful, “How can I help?” posts in the Discord. We aim to provide our community docs members with clear, consistent messages so they can feel confident contributing to the docs. Modeling these tasks, routines, and ceremonies publicly also means that budding community leaders can feel confident stepping into leadership roles.&lt;/p&gt;
  525. &lt;p&gt;This early investment in community-driven docs now frees me up to spend some focused time writing our first introductory tutorial from scratch, which is as good an ulterior motive as it gets. My background in education and curriculum writing, and my current involvement in projects like #DevEdBookClub on Twitter can bring some relevant theory and practice not only to the tasks of planning, prioritizing, and steering the efforts of our contributors, but also to creating some fresh content influenced by common industry models and practices.&lt;/p&gt;
  526. &lt;p&gt;I am also working to formalize our communication channels between Support Squad and Team Docs, with written contributor guides for each role so they know how they can be supporting &lt;em&gt;each other&lt;/em&gt; in their interconnected efforts.&lt;/p&gt;
  527. &lt;p&gt;We also want to give our docs a thorough “Every Page is Page One” treatment. I have started to emphasize to Team Docs that, no matter how much of a page turner it might be, few people will read our docs site like a book, cover to cover. Furthermore, you can’t be guaranteed that they will arrive to the docs site on the landing page. All pages have to be welcoming to new arrivals. Now that our content is &lt;strong&gt;correct&lt;/strong&gt; and &lt;strong&gt;helpful&lt;/strong&gt;, it needs to also be &lt;strong&gt;discoverable&lt;/strong&gt; and &lt;strong&gt;navigable&lt;/strong&gt;.&lt;/p&gt;
  528. &lt;div&gt;&lt;h2 id=&quot;docs-are-never-done&quot;&gt;Docs are never done&lt;/h2&gt;&lt;/div&gt;
  529. &lt;p&gt;The docs are never done is a true, and also potentially overwhelming statement. It can be all the more overwhelming, and intimidating, when this all plays out publicly, in real-time. As we are trying to systematically improve the site as a whole with a unified approach, we are also constantly responding to internal demands and external feedback.&lt;/p&gt;
  530. &lt;p&gt;We have opted for a community approach to our docs that does its best to work with and for our community: to encourage contributions from people who might never have thought of themselves as contributors, and to provide a structure that allows them to feel comfortable, and even celebrated, while doing so.&lt;/p&gt;
  531. &lt;p&gt;Astro has attracted and kept users despite its still-beta status because of its strong commitment to cultivating a vibrant, healthy community. Happy people overlook a surprising number of bugs, missteps and limitations, especially when they can see that someone is working to address them.&lt;/p&gt;
  532. &lt;p&gt;We bring that same community vibe to our docs, and provide an easy way for anyone to jump in themselves, and &lt;em&gt;become&lt;/em&gt; that someone who is working to address them!&lt;/p&gt;</content:encoded><category>astro</category><category>docs</category><category>open source</category></item><item><title>Doc&apos;ing the Docs!</title><link>https://www.rainsberger.ca/blog/documenting-the-docs/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/documenting-the-docs/</guid><description>A brief history of what&apos;s been going on in the Astro docs.
  533.  
  534. </description><pubDate>Wed, 06 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Since the docs are about to get a lot more eyes on them after the Astro Beta Lauch Week, I thought I’d take a moment to “doc the docs” for those who might want a window into our recent progress.&lt;/p&gt;
  535. &lt;p&gt;People have very kindly been referring to “the new docs” or “a re-writing of the docs” but, docs are &lt;em&gt;always&lt;/em&gt; evolving… and at least in the case of a pre-v1 beta product, potentially outdated as soon as they’re published! It sometimes feels like they’ll never be caught up enough to qualify as “new.” But they are “actively maintained,” and sometimes, that’s the best you can hope for. 😅&lt;/p&gt;
  536. &lt;p&gt;Calling them “new” might also set up the expectation that we think we’re “done” and, nothing could be further from the truth! We’re just getting started…&lt;/p&gt;
  537. &lt;p&gt;With new users joining the Astro community, and current members upgrading from previous versions, it was important to us all that the docs get some love and a paint job to help everyone get off to a solid start.&lt;/p&gt;
  538. &lt;div&gt;&lt;h2 id=&quot;where-we-started&quot;&gt;Where We Started&lt;/h2&gt;&lt;/div&gt;
  539. &lt;p&gt;As new features get added and others become deprecated, open source docs often (if you’re lucky!) get &lt;strong&gt;patched&lt;/strong&gt;. Over time, one single page can lose its “single page-iness.” It can sound like it was written by a dozen different people in a dozen different places. (Spoiler alert: it probably was.)&lt;/p&gt;
  540. &lt;p&gt;It can end up being a confusing mix of general overview information too vague to be useful and highly-specific examples that solved one community member’s problem that one single time… whether or not they were even &lt;em&gt;intended&lt;/em&gt; to work in the first place! (“Here we find the elusive “documented undocumented feature in its native habitat…”)&lt;/p&gt;
  541. &lt;p&gt;Things can end up added on a page because “other things like it are on this page” and not because that’s where a new or confused reader would go to find them. The scope of the page can creep, or content can end up duplicated (or even worse, not &lt;em&gt;exactly&lt;/em&gt; duplicated) across multiple pages.&lt;/p&gt;
  542. &lt;p&gt;Step one for me with the Astro docs was to smooth out these rough edges.&lt;/p&gt;
  543. &lt;div&gt;&lt;h2 id=&quot;where-we-are&quot;&gt;Where We Are&lt;/h2&gt;&lt;/div&gt;
  544. &lt;p&gt;We feel like we’ve mostly hit phase one of our goals: in addition to some technical reference docs now being auto-generated and updated, every page in the “Learn” sidebar has been read through and vetted for accuracy… typos, last-minute URL changes, and &lt;em&gt;entirely brand new configurations as of last week&lt;/em&gt; aside. Oh, and by the way, Astro does SSR now?&lt;/p&gt;
  545. &lt;p&gt;Pages have been edited, and in some cases rearranged or combined with other pages so that &lt;strong&gt;each page clearly tells you about a thing&lt;/strong&gt;. (And if we did it correctly, that thing is the page title!)&lt;/p&gt;
  546. &lt;p&gt;It doesn’t tell you &lt;em&gt;everything&lt;/em&gt; about a thing. I can’t even guarantee it tells you &lt;em&gt;most things&lt;/em&gt; about a thing. I know there are things about those things that you really want to know that it doesn’t (yet) tell you. But what it does tell you, it tells you &lt;em&gt;pretty&lt;/em&gt; well.&lt;/p&gt;
  547. &lt;p&gt;I’d &lt;em&gt;like&lt;/em&gt; to think that it probably tells you well enough about the thing that, if something’s not right there, you’ll &lt;strong&gt;know&lt;/strong&gt; that it’s… just not in the docs! So, you hop into the &lt;a href=&quot;https://astro.build/chat&quot;&gt;Astro Discord&lt;/a&gt; and you ask about the thing there. Then, we make notes about what support questions get asked, to remind us of the things we haven’t yet put in the docs.&lt;/p&gt;
  548. &lt;div&gt;&lt;h2 id=&quot;support-team-docs&quot;&gt;Support-Team-Docs!&lt;/h2&gt;&lt;/div&gt;
  549. &lt;p&gt;Our eager team, with a full community of support behind us, has been working steadily for months to make the Astro docs a clean, reliable resource to get you started with Astro v1. We know it’s not perfect, and we do have plans for more, and more &lt;em&gt;types&lt;/em&gt; of content going forward. It’s never going to be “done”… but that’s just the reality of supporting developers. And, that’s what docs are: support.&lt;/p&gt;
  550. &lt;p&gt;Astro is known for (notorious for??) its committment to community. We have long had a dedicated “Support Squad” whose members each receive individual notifications for every new support question posted in our Discord. Recently, we also added a “Team Docs” role that can similarly summon members with a mere mention. Both of these opt-in roles are open to any member of the community who feels like they don’t already get enough notifications.&lt;/p&gt;
  551. &lt;p&gt;We are all eager and enthusiastic to help you through any issues and get you back to building your site! And, we hope you’ll help us help you!&lt;/p&gt;
  552. &lt;div&gt;&lt;h2 id=&quot;go-you&quot;&gt;Go, You!&lt;/h2&gt;&lt;/div&gt;
  553. &lt;p&gt;If you find a typo, a link to a page that we’ve moved, or the term &lt;code dir=&quot;auto&quot;&gt;renderer&lt;/code&gt; when it should be an &lt;code dir=&quot;auto&quot;&gt;integration&lt;/code&gt; now, you can let us know, or you can &lt;a href=&quot;https://www.rainsberger.ca/posts/contribute-open-source-docs-edit-page-on-github/&quot;&gt;edit the page on GitHub&lt;/a&gt; yourself! One of the most rewarding aspects of working closely with the docs team this year has been seeing the number of small edits submitted by “first-time contributors.”&lt;/p&gt;
  554. &lt;p&gt;If you feel a topic hasn’t been covered in docs, or an example is confusing, come chat in our &lt;code dir=&quot;auto&quot;&gt;#docs&lt;/code&gt; channel, or file a &lt;a href=&quot;https://github.com/withastro/docs/issues&quot;&gt;GitHub Issue&lt;/a&gt; in the docs repository. (Maybe if you have the time, do a quick check to see if someone has already mentioned something similar, or whether there’s an active &lt;a href=&quot;https://github.com/withastro/docs/pulls&quot;&gt;pull request&lt;/a&gt; related to your comment first… but do get involved!)&lt;/p&gt;
  555. &lt;div&gt;&lt;h2 id=&quot;launching-into-the-future&quot;&gt;Launching into the Future&lt;/h2&gt;&lt;/div&gt;
  556. &lt;p&gt;I’m excited for the future possibilities with our docs, and I’m personally hoping to get the chance to bring bit of my own teaching background and style into some dedicated walk-through guides and tutorials for onboarding new astronauts.&lt;/p&gt;
  557. &lt;p&gt;Astro, and the entire Astro community, is so user-friendly that we want our docs to be every bit as welcoming and supportive to developers of all experience levels. We know we can get you building with Astro, and we can’t wait to show you how!&lt;/p&gt;
  558. &lt;p&gt;Thanks for hanging in there as we made it to a v1 Docs beta, too. Stick around, and see where we go next! 🚀&lt;/p&gt;</content:encoded><category>astro</category><category>docs</category><category>open source</category></item><item><title>React to XElement in Astro: sBird to xBird</title><link>https://www.rainsberger.ca/blog/xelement-bird-1/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/xelement-bird-1/</guid><description>aFuzzyBear and I have started a community, build-in-public project where we take my React-in-Astro sBird app and recreate all the same functionality using XElement, natively in Astro! The first video is now up on YouTube.
  559.  
  560. </description><pubDate>Mon, 07 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last weekend, aFuzzyBear and I spent 3hrs on live-chat in the Astro Discord while other community members joined in. I’ve started editing the footage and will be uploading it in smaller pieces.&lt;/p&gt;
  561. &lt;p&gt;This first video is an introduction to our project, to Astro and to XElement.&lt;/p&gt;
  562. &lt;p&gt;See the demo and our up-to-the-moment progress at &lt;a href=&quot;https://xelement-bird.netlify.app&quot;&gt;https://xelement-bird.netlify.app&lt;/a&gt;&lt;/p&gt;
  563. &lt;div&gt;&lt;h2 id=&quot;about-xelement&quot;&gt;About XElement&lt;/h2&gt;&lt;/div&gt;
  564. &lt;p&gt;XElement is an Astro-native solution to providing interactive web elements without the need for script tags or any other JavaScript framework components (React, Preact, Vue, Svelte, Solid…)&lt;/p&gt;
  565. &lt;p&gt;npm package - &lt;a href=&quot;https://www.npmjs.com/package/astro-xelement&quot;&gt;https://www.npmjs.com/package/astro-xelement&lt;/a&gt;&lt;/p&gt;
  566. &lt;p&gt;XElement Docs - &lt;a href=&quot;https://xelement-docs.vercel.app&quot;&gt;https://xelement-docs.vercel.app&lt;/a&gt;&lt;/p&gt;
  567. &lt;div&gt;&lt;h2 id=&quot;this-video&quot;&gt;This video:&lt;/h2&gt;&lt;/div&gt;
  568. &lt;p&gt;0:00 - Introduction to Astro and this project&lt;/p&gt;
  569. &lt;p&gt;1:17 - What is “sBird”?&lt;/p&gt;
  570. &lt;p&gt;2:59 - Building in React vs Astro vs React-in-Astro&lt;/p&gt;
  571. &lt;p&gt;6:06 - Partial Hydration in Astro&lt;/p&gt;
  572. &lt;p&gt;12:14 - How XElement accomplishes interactivity natively in Astro&lt;/p&gt;
  573. &lt;p&gt;15:00 - XElement component demonstration&lt;/p&gt;
  574. &lt;p&gt;Since I can’t fit the entire transcript in the YouTube video description, here it is all on this page.&lt;/p&gt;
  575. &lt;iframe src=&quot;https://www.youtube.com/embed/0-aH18YH2SQ&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
  576. &lt;p&gt;Transcript:&lt;/p&gt;
  577. &lt;p&gt;aFuzzyBear  0:00&lt;br&gt;
  578. What we’re going to do is just have a quick overview of the bird app that is written in React, then we will introduce XElement. And then we’re going to get working on “xbird”, which is the reverse engineering of XElement and sBird.&lt;/p&gt;
  579. &lt;p&gt;Right. So what do we know about Astro? Astro is a static site generator that focuses on basically sending zero JavaScript, well as little JavaScript to the client as possible. And it does some fantastic things in terms of its progressive hydration when it comes to using other frameworks like React, Svelte, Vue, Preact, Solid, etc.&lt;/p&gt;
  580. &lt;p&gt;And XElement is Astro’s first and only web component framework that at the present moment allows you to create dynamic HTML elements from a very simple and intuitive interface. It sends pure JavaScript down the wire to the client, there is no renders, no partial hydrations… nothing required like that. It is as vanilla, as close to vanilla, as you can get. So that is the introduction. And let’s get demonstrating sBird. Sarah, do you want to talk about sBird?&lt;/p&gt;
  581. &lt;p&gt;Sarah Rainsberger  1:23&lt;br&gt;
  582. Sure. So sBird is my little bird app. It uses the eBird API and eBird is a global bird organization where birders around the world submit reports of the birds they’ve observed, a big citizen science project.&lt;/p&gt;
  583. &lt;p&gt;This bit of the app we’re looking at right now is specifically to see what rare or unusual birds people have recorded in a particular area. So that’s what this shows here. So I make an API call, and I can see sightings that are pending review. So like that Sandhill Crane, these are sightings people have reported, but I have them classified as pending: they haven’t been reviewed yet. So if you’re waiting, you’re like, “Did they look at my bird report yet…?” This is where I go to check.&lt;/p&gt;
  584. &lt;p&gt;And then, there are birds recently confirmed. So I know when my sighting was actually confirmed. And then so down below, I have other sections that Fuzzy is showing that are doing other things. This is a section if I want to see which birds have been reported at all in the last 30 days. These are things that I use when I’m out reporting birds. I want to know whether something is rare. I want to know, “Has anybody else seen an Icelandic gull lately in this area? Is that really what this could be?” And other things like that.&lt;/p&gt;
  585. &lt;p&gt;So these are the kinds of things that I built for myself using React because that’s what I learned. And then when I learned Astro, I could put this entire React app in an Astro page on my website. And now we’re going to try to see if we can get rid of the React and build the same functionality in XElement. That’s today’s task.&lt;/p&gt;
  586. &lt;p&gt;Unknown Speaker  3:25&lt;br&gt;
  587. Yep. And I just want to ask you a couple of questions. How did you find using Astro and a third party component like React? Like, what was your experience when you came to building this React part that we are just about to explore the code for?&lt;/p&gt;
  588. &lt;p&gt;Sarah Rainsberger  3:44&lt;br&gt;
  589. Well, so one change I had to make was because I built the thing originally in React before I even knew about Astro. And so of course, that was a single page application. So you’re looking at routes, things like that.&lt;/p&gt;
  590. &lt;p&gt;So the first thing was when I came to Astro, I sort of had to make some decisions about whether I am going to try to replicate an SPA inside of an Astro page, which I sort of did at first. And then I was like, “Well, let’s take advantage of Astros routing!” And so then I broke my app apart, and I had different React pieces on different Astro pages.&lt;/p&gt;
  591. &lt;p&gt;But then I would get into issues when I wanted to share some state like a default location. I wanted someone to be able to set a default location. And then Astro had the quite major upgrade to version 0.21. So I had to rebuild the site, anyway, because there were a bunch of things at this point that sort of needed some fine tuning to upgrade. And so at that point, I just actually threw them back all onto one page. And, what you’re seeing now is actually a subset of what the original app was.&lt;/p&gt;
  592. &lt;p&gt;So that was one issue. And I think we hear that a lot in the Discord, trying to wrangle state and context, things that you’re used to when you basically start from an App.js file. But in Astro because everything is split onto different pages naturally, we look to the Astro SPA plugin or XElement, other things like that. The second thing is, if you look in my code, on the sBird page, for the version we have here, this (&lt;code dir=&quot;auto&quot;&gt;client:load&lt;/code&gt;) works. But there have been some issues with React where I have had to use client:only=“react” to get the app to run properly.&lt;/p&gt;
  593. &lt;p&gt;aFuzzyBear  6:06&lt;br&gt;
  594. So I just want to quickly say, for those who are not familiar with the client load directives that Astro uses, this is how Astro gets around their partial hydration. I’m just going to bring up their page, their documentation is getting a lot better, I have to say. Thank you, Sarah. And just for those who don’t know, Sarah, is working as well on the docs for Astro at the present moment.&lt;/p&gt;
  595. &lt;p&gt;So yeah, the concept of partial hydration and Astro is that it is not your single page application like Sarah has just mentioned, where everything is within a JSX file. And life inside a JSX file is life inside JavaScript. But Astro and these new concepts like partial hydration, which describes Islands Architecture, takes your interactive elements, and they become one off components.&lt;/p&gt;
  596. &lt;p&gt;Because approximately 80% of your application is static, that being the static HTML content that React is constantly rendering, along with the additional JavaScript functionality. So Astro takes the concept of islands and really drives home this ethos, where within this picture, (here is a brilliant picture that kind of emphasizes it), you have several small applications, whereas in the past, this used to be one giant application. And React would render all these small parts together. Whereas with Astro, it only renders out the static parts that do not ever really change. There’s no real need for dynamism over the top of it. And the stuff that doesn’t need any dynamic components or interactions for instance, a sidebar, or a header array at the top, a little table of contents on the right hand side… So these things here are small applications that are embedded on to the actual page itself. And Astro then goes one step further to make only some components interactive on the client.&lt;/p&gt;
  597. &lt;p&gt;There are several ways of doing this, like Sarah mentioned there is the client:load directive, which is currently what’s implemented on sBird at the moment, which loads the components when the DOM has finished and the JavaScript is ready, then starts to hydrate all the static parts of your page and starts to make them interactive. And client:idle is pretty much the same thing. But this happens when the thread is free, the main thread comes free. client:visible is a very cool and extremely powerful hydration selector where it uses the intersection observer to see whether or not the element itself has become visible onto the viewport and if it has, then it starts interaction. Likewise, we’ve the client:media hydration query. So, on certain viewports, on certain view sizes, you could have certain islands that only hydrate that interactivity on a given media query.&lt;/p&gt;
  598. &lt;p&gt;And then, if all else fails, and you’re struggling with getting your UI framework to work, it’s normally because a lot of the UI frameworks have hooks that require access to the DOM straight away. For instance, the React plugin ecosystem is built around the React model. This assumes that when React loads, that the document is there, etc. So there is no pre concept of islands or multi page architecture when it comes to a lot of the React ecosystem. But Astro provides you with ways to get around those gotchas and client:only is a very good one, if you’re struggling with your application, regardless of what framework, try the client only.&lt;/p&gt;
  599. &lt;p&gt;And, and a typical question we normally get in support and the community channels, especially for those new to Astro, is that you can’t hydrate Astro components. And this page, and I highly recommend checking out the partial hydration page on Astro docs, explains it well, because Astro components are HTML components. And, really, there is no server runtime. And they’re straight up HTML. So a string of HTML and, and like it says here, in order for you to make it interactive, you’re going to need to convert it into a framework of your choice. And what if there is a case where, like me, you don’t like these frameworks?&lt;/p&gt;
  600. &lt;p&gt;Now, this is where I’m going to introduce XElement. Because, personally speaking, when I came into Astroland, I was happy with the fact that I didn’t need to write a lot in my cage, in a JSX file. So the less Reacty I could get my site to be, the happier as a developer I am. And that’s just my own preference. And that’s what inspired XElement to come into fruition.&lt;/p&gt;
  601. &lt;p&gt;Me and an excellent maintainer and contributor to the community, Jonathan Neal, we got together and we basically came up with a way that we could incorporate XElement into Astro to allow you to have that client side runtime, and interactivity and deliver it without the use of having a UI framework as a middleman in this case. These frameworks really do empower Astro to create fantastic, fantastic experiences, however, for those who just don’t like using UI frameworks, there is something else out there now.&lt;/p&gt;
  602. &lt;p&gt;Before this, in Astro if you wanted to use any sort of client side interactivity, you would use a good old fashioned script tag, right where it would be placed, unbundled using Astro’s magic. And attached to the page, right. There’s no need for any client side hydration with us because it literally just fires once the script is ready. And this inspired XElement to take this one step further, because as you can see here, let me see if I can zoom in. Just to show this point.&lt;/p&gt;
  603. &lt;p&gt;There’s one heading element along with the button. Now this button we wanted action on it, we just want it when it clicks, we just want to change the text from “not clicked” to “clicked.” Right. Now, the standard approach would be to just go script document query selector. Second add event listener on to it to specify the event listener, and then retargeting the h1, we get the enter text, and then we’re just changing that to click. It’s a bit verbose, especially as a developer when you’re constantly having to do this for more than one component. And this is where XElement comes in.&lt;/p&gt;
  604. &lt;p&gt;So we’ve actually got a page set for us right now to demonstrate some XElement components. Thank you, Sarah. And now this page is all components using JavaScript on the client side, created within Astro without using any UI framework. And let’s break them down. This one here, as you probably noticed, is a type and text as third party script that we’re calling, which basically just takes a string and just prints it out on the screen as if it’s being typed out right in front of us. Quite cool, really is. And we’ve also got everyone’s counter, where we just increase the count, and decrease the count.&lt;/p&gt;
  605. &lt;p&gt;And we’ve got a flashy little animation going on here. We’ve got a couple of animations. And we had a SURPRISE, and I ruined it, we’ll try it again. And so this text is designed to move to the right after a certain period. And this is all using the web animation API. The web animation API is actually incorporated into XElement and makes this whole thing a lot easier for you. And if we do click this text, we get confetti. And it only fires once, if you notice, right. So you can control event behavior and propagation and the likes to give you that fine-grained control over your element’s interactions. Start Stop control animation. At the bottom, we have a request animation and frame clock, which is just basically updating the time, every millisecond. So every 60 frames per second, this thing is going off quite nicely.&lt;/p&gt;
  606. &lt;p&gt;And none of these are interfering with each other. So for instance, if one was to break, the rest of this page will still keep working. Next up, we’re going to be asking for data from an API call. And here, we’re just doing a suspenseful action where we just have a loading, you can see that there is a little loading state there, right? Let’s just do this. Again. Quick data loading brought back the data. Now this is a client side fetch request that is going off. And then we’re just populating the DOM once we get the data. And all of this all works at native JavaScript speed. And we have Astro to thank for that right now. That is the introduction. Let’s get cracking. Do you think Sarah?&lt;/p&gt;
  607. &lt;p&gt;Sarah Rainsberger  18:26&lt;br&gt;
  608. Yeah, let’s do it.&lt;/p&gt;</content:encoded><category>videos</category><category>astro</category><category>xelement</category></item><item><title>Contribute to Open Source Docs via &quot;Edit this page&quot; on GitHub</title><link>https://www.rainsberger.ca/blog/contribute-open-source-docs-edit-page-on-github/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/contribute-open-source-docs-edit-page-on-github/</guid><description>Have you ever been reading documentation for an open source project and found a typo, or an out-of-date code example? If there&apos;s an &quot;edit this page on GitHub&quot; link, then you&apos;re only a few clicks away from contributing to Open Source and helping out a project!
  609.  
  610. </description><pubDate>Thu, 10 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;With open source projects, not only can you &lt;em&gt;see&lt;/em&gt; the code, you can help &lt;em&gt;edit and maintain&lt;/em&gt; the code, too!&lt;/p&gt;
  611. &lt;p&gt;Here’s an example of how you can contribute to &lt;a href=&quot;https://docs.astro.build&quot;&gt;Astro’s documentation&lt;/a&gt;, right from your browser!&lt;/p&gt;
  612. &lt;div&gt;&lt;h2 id=&quot;edit-this-page&quot;&gt;Edit this page&lt;/h2&gt;&lt;/div&gt;
  613. &lt;p&gt;On every page of the Astro documentation, there is a pencil icon and a link to “Edit this page” in the right hand sidebar.&lt;/p&gt;
  614. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLU_kl-WFfHVC6TBI-CZe7esReIiCzC_xaPd4kdjQFri7mVsOFovee04s5p76FzRKR_hKbPtVUjdYYDeFUx6lzuIsXp52p9H5KqzSvkn0uQz8JYtKKzcp50J7B0g56lxQ-itFF3mhbfsCH9zxcwM7vQiTg=w2367-h1334-no?&quot; alt=&quot;Astro Docs home page, with the edit this page link circled.&quot;&gt;&lt;/p&gt;
  615. &lt;p&gt;Click this link!  Your browser will navigate to the Astro Docs source repository on GitHub, taking you directly to the file for the page you’re viewing. To make a contribution to this file, select the pencil icon to edit. If you are not logged in, you will be prompted to log in.&lt;/p&gt;
  616. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLWVjV1esyJ6ytzpgiCBX204uQoDfINTRCUqX1GN936Rd5MkPr4aZrkwuWORHWF9NggpJ4YIUu1ptidj2jjak2J8kW8Mj_k0tCuN79Vo0RY8jNPjviK26fKNoRmM-HsLmfz4INflxaGbuzh9e4j7YF_M_w=w2132-h1009-no?&quot; alt=&quot;GitHub page, wit the pencil icon for editing the page highlighted, and hover text: You must be logged in to make or propose changes.&quot;&gt;&lt;/p&gt;
  617. &lt;p&gt;If you &lt;em&gt;are&lt;/em&gt; logged in, the pencil icon will take you to edit this file in your fork of this project. (If this is your first time editing a project, a fork will automatically be created in your own GitHub account. Yay! You now own a copy of the Astro docs!)&lt;/p&gt;
  618. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLWipslaN8fxh8j2IdCnyfyJhiv_6zVd-EuvkNVyxrZR5lTJr5S5_jwUFKyB24qXVRIW2vtdCK_mAprpaIV4EIuDvUzqFGoceXqTwqDCtfDT7U6gSCm2PP6InF6x7wQScP_Eyx1-jwMtoYeP-PQkq-OyPQ=w2132-h1009-no?&quot; alt=&quot;GitHub page, wit the pencil icon for editing the page highlighted, and hover text this file in your fork of the project.&quot;&gt;&lt;/p&gt;
  619. &lt;div&gt;&lt;h2 id=&quot;propose-changes&quot;&gt;Propose Changes&lt;/h2&gt;&lt;/div&gt;
  620. &lt;p&gt;After clicking the pencil icon to edit that file, you will be greeted by a banner reminding you that you do not have permission to make changes &lt;em&gt;directly&lt;/em&gt; to the file. Instead, you will make changes in your &lt;em&gt;own&lt;/em&gt; copy of the documents, then submit a pull request to the original project.&lt;/p&gt;
  621. &lt;p&gt;In edit mode, you can flip between typing Markdown source code and previewing those changes on the page.&lt;/p&gt;
  622. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLXJqnQSZ1S1A0N7DGLLMlmGH0hM0Et9cmzqMOLa8TsE_2YAdt2JL7FB-vV4KMFCmZ7-fhV0WT-q2N77YWo8TEYqS_yuGzX3BPPY-UOl94JGmisEbxoGyKC_eIHKElAkvuaSxCvHq5NTJbi1QG1O8XTFOA=w2132-h1223-no?&quot; alt=&quot;Editing a page in GitHub, with a banner highlighted that reads: You&amp;#x27;re making changes in a project that you don&amp;#x27;t have write access to. Submitting a change will write it to a new branch in your fork so you can send a pull request.&quot;&gt;&lt;/p&gt;
  623. &lt;p&gt;Once you have made changes, use the “Propose Changes” button at the bottom of the page to submit your new version of the page to the Open Source project for consideration. Be sure to include a short but descriptive title of what you changed, and optionally, a longer description. This could be a more thorough explanation of what you changed, or why you believe the change was necessary or appropriate.&lt;/p&gt;
  624. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLXWu82RfWuzpY1OYplqYyQTPpr3eFNJhs9JIunoRHsUBNtCXv6a87ZvVZk93zCRgvYgudH4SErQrqgzGYsoVR7JKhED2P1uR709clbLmM1J_4lVSTVoWt164V5HHkeKf-Xt_Z2FAOO2jL-w4FRN_1MlGQ=w1849-h805-no?&quot; alt=&quot;The Propose Changes text entry submission box, with space to enter a title and a description.&quot;&gt;&lt;/p&gt;
  625. &lt;p&gt;After “proposing changes,” you’ll still have two more steps to go (and two more chances to back out!) in order to create a pull request. So there’s absolutely no risk in going this far!&lt;/p&gt;
  626. &lt;div&gt;&lt;h2 id=&quot;create-a-pull-request&quot;&gt;Create a pull request&lt;/h2&gt;&lt;/div&gt;
  627. &lt;p&gt;Next, you’ll be taken to a page that performs a check to make sure that your changes are able to be merged, without conflict, into the open source repository. It’s at this point that you’ll click the submit button to “create a pull request” (PR)… but this is only the button that takes you to &lt;em&gt;another&lt;/em&gt; page where you’ll have a chance to edit your PRs title and description before &lt;em&gt;actually&lt;/em&gt; opening it (sending your proposed changes to the original repository).&lt;/p&gt;
  628. &lt;p&gt;It’s totally safe to click here! You’ve still got one more chance to back out!&lt;/p&gt;
  629. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLVNBeNY81MqF9gzK-_kfFX5we3Kk8SyMYHSujsi1wGyvAR0_pyHRZQrTXk4XppHA9jiwTupp8yMXyd6inn4TB3-wPltW7uXs12uGBtaZeuvcZX4m2eeyJ3jZNNhQF0qwGPDtP7EYpcBqF_mj_rZBQ327Q=w1747-h195-no?&quot; alt=&quot;Message: Able to merge. These branches can be automatically merged. Followed by a submit button to Create Pull Request.&quot;&gt;&lt;/p&gt;
  630. &lt;p&gt;The next page you’ll reach will again confirm that your changes can be merged without creating a conflict, and will allow you to adjust your title and description as necessary. (This screenshot shows a pull request to one of my own repositories this time, instead of the Astro docs.)&lt;/p&gt;
  631. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLXinD_jpQl7ciFjpI2yN8E-lJPgpcTbPOu7O89Bm9CC85AL0cC9udngyowgur5QFzAJV0-UVibRylt8RGTP9EZKtxx6ZbnkagBZCObaKJ2-N-PLrNg6CVEQy4UnYXnW2OxhYd7cW-OmINk1RIGPO9KwtQ=w1747-h836-no?authuser=0&quot; alt=&quot;The Open a Pull Request page on GitHub. A more advanced editor for creating a more elaborate description, and then a final create pull request button at the bottom.&quot;&gt;&lt;/p&gt;
  632. &lt;blockquote&gt;
  633. &lt;p&gt;⚠️ &lt;strong&gt;When you click “Create a pull request” on this screen, now you &lt;em&gt;actually&lt;/em&gt; create a pull request! This one counts!&lt;/strong&gt;&lt;/p&gt;
  634. &lt;/blockquote&gt;
  635. &lt;p&gt;Here, you can leave a comment in Markdown, and also preview your comment. So, if you’d like to add a more descriptive or elaborate description of your changes here, including lists, formatting, code blocks… feel free!&lt;/p&gt;
  636. &lt;p&gt;Also, there is a checkbox (selected by default) at the bottom, just before the submit button, for allowing edits by maintainers. This allows a maintainer of the project to accept your pull request while still making a change like fixing a typo or addressing a style issue. Perhaps the maintainer agrees with the idea of your proposted changes, but is unable to accept them exactly as you’ve written them. By checking this box, you’re allowing the maintainer to modify your changes so that they can still accept your pull request. Otherwise, if the maintainer cannot accept your changes &lt;em&gt;exactly&lt;/em&gt; as you’ve proposed them, they will need to ask you to make changes and resubmit, or will be forced to deny your proposed changes entirely.&lt;/p&gt;
  637. &lt;p&gt;Once you are satisfied with the content of your pull request, click the button to submit (for realz!) and you’ll be taken to a confirmation screen that shows your “open” pull request, in the original repository.&lt;/p&gt;
  638. &lt;div&gt;&lt;h2 id=&quot;success&quot;&gt;Success!&lt;/h2&gt;&lt;/div&gt;
  639. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLVm_4gUSrAdry7tFHPm2qiWnXNHS_x4LoYOLRRDnbXIYlg31Ia4uVOxynamMfysRFj1M9c8PI01AlrVi1vhmJmMaQ5-WpP2DG_zJnJ7yX_O0e_CBL1Ciydd42ojuO4nNOeF7k2qqsqu3x-Epzl2-J3JoA=w1806-h1229-no?authuser=0&quot; alt=&quot;A GitHub page for a completed pull request, showing its status as open, options for closing it or adding another comment, as well as a button to unsubscribe from further notifications about this request.&quot;&gt;&lt;/p&gt;
  640. &lt;p&gt;Congratulations! Your contribution has left your hands! Your pull request joins all the other pull requests (shown in the upper left) to that project.&lt;/p&gt;
  641. &lt;p&gt;You can still add a follow up comment or decide to close the pull request at any time by revisiting this page. You can’t “delete” a pull request, but you can “close” it to let the maintainers of the project know that you are withdrawing your proposed changes. The pull request continues to exist, (and can even be re-opened with the press of a button!) but closed PRs are typically hidden out of sight behind a default filter that only shows “open” (unresolved) pull requests.&lt;/p&gt;
  642. &lt;p&gt;Also be aware that you will be automatically subscribed to receive notifications for any activity on this pull request. You can customize your notification preferences, but by default, you will receive an email when there is any activity on your request.&lt;/p&gt;
  643. &lt;div&gt;&lt;h2 id=&quot;continuing-to-contribute&quot;&gt;Continuing to Contribute&lt;/h2&gt;&lt;/div&gt;
  644. &lt;p&gt;Your GitHub profile will now contain local copies, that &lt;em&gt;you&lt;/em&gt; own, of the repositories to which you submitted changes. This means, you can easily revisit them at any time and contribute again and again!&lt;/p&gt;
  645. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLVtcxnpUc5qai86ZKw32mIiHV6FpZMVqqUEtvsagHAXMskeohdGKB-QWJYfp42U-Mud9BBUJmuMTn9iIMq8vnw9SoAsL7VXUFgv4Kykf1DNIt9Rb_7A4dSizI1krJsn2rRXl-OfLAYN80fpZcleeRtqIw=w1828-h694-no?authuser=0&quot; alt=&quot;A GitHub profile page showing the user&amp;#x27;s repositories. Under each local repository, it reads Forked from... the original project&quot;&gt;&lt;/p&gt;
  646. &lt;p&gt;You can continue to edit files on GitHub, or you can open these repositories however you prefer to work on them: locally on your machine, in an online development environment or code editor like Gitpod or CodeSandbox, or by using the handy ”.” (period key) shortcut while on GitHub to open github.dev for a VS Code editing experience instead of GitHub’s default individual file editing page.&lt;/p&gt;
  647. &lt;div&gt;&lt;h3 id=&quot;️-avoid-merge-conflicts&quot;&gt;⚠️ Avoid merge conflicts!&lt;/h3&gt;&lt;/div&gt;
  648. &lt;p&gt;Remember how GitHub checked &lt;em&gt;multiple times&lt;/em&gt; to make sure your changes could be merged into the original repository without any conflicts? Remember, the open source project probably has several people contributing to it, and it is changing all the time! (Even if you only work on your local copy every now and then.)&lt;/p&gt;
  649. &lt;p&gt;To make sure that any new changes you propose are compatible with the &lt;em&gt;current version&lt;/em&gt; of the project, before you begin editing, you should always &lt;em&gt;&lt;strong&gt;fetch upstream&lt;/strong&gt;&lt;/em&gt; so that your project incorporates any new changes since the last time you contributed.&lt;/p&gt;
  650. &lt;p&gt;&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AM-JKLXlr6bZkeal-1mmFhUgME_5LEmxsCICrfEo5ppodxVJ5MqYNC3DbKeuwhkeIhG2UD_DnM_New6XkQLuFzK8EJf5IXS5w8QGPuczxRa7UXvAJX0C4Yt6UponzpNrKpE4rufZdGONlgbyI9Eeo3KUoeYHyg=w1534-h449-no?&quot; alt=&quot;The main page of a forked, local repository showing This branch is 11 commits behind as well as Contribute and Fetch upstream options&quot;&gt;&lt;/p&gt;
  651. &lt;p&gt;Navigating into one of your repositories should show you if your forked copy of the project is &lt;em&gt;behind&lt;/em&gt; (i.e. not caught up with changes to) the original. There will also be an option to “fetch upstream” which will add all the new changes, and project commit history of the original project to your own.&lt;/p&gt;
  652. &lt;p&gt;&lt;strong&gt;Always do fetch upstream first, before starting to make changes to your local copy!&lt;/strong&gt;&lt;/p&gt;
  653. &lt;p&gt;There is even a &lt;a href=&quot;https://github.com/apps/pull&quot;&gt;handy GitHub app called “Pull”&lt;/a&gt; that you can authorize to run automatically to perform this action at regular intervals so that you can avoid going a long time without fetching, and avoid issues of massive, even breaking, changes in the original project conflicting with what’s in your local copy. You should still fetch manually before each work session though, to catch any up-to-the-minute changes before you begin editing.&lt;/p&gt;
  654. &lt;p&gt;Any changes you make here are &lt;em&gt;only&lt;/em&gt; local changes, contained in &lt;em&gt;your&lt;/em&gt; repository. So feel free to experiment! You don’t have to send your changes back every time you make them… or, ever! You can work independently for as long as you want and make as many commits &lt;em&gt;to your own project&lt;/em&gt; as you like. (Just remember to fetch upstream each time you begin again, to keep up-to-date with any upstream changes.)&lt;/p&gt;
  655. &lt;p&gt;When you &lt;em&gt;do&lt;/em&gt; have new changes commited to your local fork of the project that you want to contribute back via a new pull request, go back to your repository’s main page. Instead of “fetching upstream,” this time you can “Contribute” back to the original project. (These options are next to each other on the page.)&lt;/p&gt;
  656. &lt;p&gt;“Contribute” will start the process for a brand new pull request, first by checking for merge conflicts, and then by allowing you to provide a good title and description for your changes. Your pull request, once opened, is attached to the original project for review, and the cycle begins again!&lt;/p&gt;
  657. &lt;div&gt;&lt;h2 id=&quot;thank-you-for-contributing-to-open-source&quot;&gt;Thank you for contributing to open source!&lt;/h2&gt;&lt;/div&gt;</content:encoded><category>docs</category><category>open source</category></item><item><title>Creating an Astro layout - screencast and transcript</title><link>https://www.rainsberger.ca/blog/create-astro-layout/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/create-astro-layout/</guid><description>This is a screencast and transcript of refactoring one of the basic Astro examples to create an initial BaseLayout component.
  658.  
  659. </description><pubDate>Thu, 20 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Trying out some new technology, and since I can’t fit the entire transcript in the YouTube video description, here it is all on this page.&lt;/p&gt;
  660. &lt;div&gt;
  661. &lt;iframe src=&quot;https://www.youtube.com/embed/9bVuIBD70wc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
  662. &lt;/div&gt;
  663. Transcript:
  664. &lt;p&gt;0:01&lt;br&gt;
  665. Here, we’re going to take a look at creating an astro layout component. So I’m just gonna open my project up in Gitpod and get it arranged the way I want.&lt;/p&gt;
  666. &lt;p&gt;0:15&lt;br&gt;
  667. The intro to any Astro project is going to be at source/pages/index.astro. So let’s jump in there and take a look at what this looks like.&lt;/p&gt;
  668. &lt;p&gt;0:27&lt;br&gt;
  669. Any Astro page is going to be separated into two sections: we’ve got this code fence block section at the top, and then we’ve got our HTML rendering part at the bottom. So what I want to do is look down and see that the second part of an Astro page file will render to a complete HTML document. You can see it starts with open HTML, and finishes with a closing HTML tag. To make that a little easier to see, I’m just going to clean up some of these code comments, and I’m going to collapse some of these tags so we can just get a sense of the structure and see what’s going on with this rendering here. Collapsing… collapsing… navigating through… just so we can see that essentially what we have within HTML tags is a head and a body.&lt;/p&gt;
  670. &lt;p&gt;1:29&lt;br&gt;
  671. And in our body, we’ve got main, we’ve got header, we’ve got some components. And I’m going to add a little bit of text, just to separate that out, because maybe we’re not sure what this Tour component is doing and how that’s different from the header. So now, I can refresh my browser preview here in Gitpod.&lt;/p&gt;
  672. &lt;p&gt;1:51&lt;br&gt;
  673. I’m just going to organize things the way I like to see them, I can have a couple of panes going, and I can make my browser preview kind of small on the right, because I just want to see at a glance what’s going on here and I want more space for my code.&lt;/p&gt;
  674. &lt;p&gt;2:08&lt;br&gt;
  675. So now we can see that yes, we do have some text on the page, let’s do the same with the frontmatter. Let’s delete some of these code comments where they’re guiding us for the places to put our JavaScript and TypeScript. And at the very top of the page is where an Astro File expects to receive its component imports, whether they’re Astro components, or React components or Svelte components.&lt;/p&gt;
  676. &lt;p&gt;2:41&lt;br&gt;
  677. And now we are ready to make our first layout. So we’re going to go back to source, create a layouts folder. And we’ll create the file BaseLayout.astro. It’s empty, but it exists. So before we forget, let’s go back into index.astro, and import BaseLayout. And we’re going to import it exactly the same way we import our other components… noting that with all these Astro components and framework components that do get imported into an Astro File, you DO need to include the file extension.&lt;/p&gt;
  678. &lt;p&gt;3:27&lt;br&gt;
  679. So a quick refresh shows we didn’t break anything. We also didn’t really do anything, but at least we’re importing a file that exists. Now, let’s choose some stuff to go into that BaseLayout folder. And I’m thinking, what we don’t want to have to copy each time we make a new Astro page is HTML and head. So let’s start there.&lt;/p&gt;
  680. &lt;p&gt;3:53&lt;br&gt;
  681. We’re going to cut it out of index. And we’ll clean it up a bit and move it into our base layout. Right now BaseLayout.astro is providing HTML and head, so we can take that closing tag out of our index file. And our index right now is just responsible for rendering the body tag. To use the layout component that we imported, we are going to wrap the content here in open and close BaseLayout tags. Alright, so we can see the body, the main, the header (let’s just just format this out)… this is what the index page is responsible for rendering, so let’s refresh and we get …an error: “Title is not defined.”&lt;/p&gt;
  682. &lt;p&gt;4:48&lt;br&gt;
  683. All right, well, let’s take a look at that because we have certainly defined a title here. The problem is that the index.astro file isn’t using that title. The title is being used in BaseLayout.astro. So what we’re going to have to do is pass that title information into our layout. And we’re just going to do that via props, title equals title. Excellent. Refresh.&lt;/p&gt;
  684. &lt;p&gt;5:21&lt;br&gt;
  685. And we still get the error, because although we have SENT the information, we haven’t properly RECEIVED the information in our layout component. So now we’re going to need a code fence. And we’re going to need to import that title property from Astro.props. Perfect. That is going to receive the title just fine. And then BaseLayout will be able to use that title to create the title tag in our head. So we refresh, and there’s no error… but there’s also nothing else on the page. Okay, so what’s going on here?&lt;/p&gt;
  686. &lt;p&gt;6:06&lt;br&gt;
  687. Well, if we look at what our BaseLayout is actually rendering, (and that &lt;em&gt;is&lt;/em&gt; what’s getting rendered to index, because we’ve wrapped everything in BaseLayout), all that we’re sending to index is the HTML tag and a head.&lt;/p&gt;
  688. &lt;p&gt;6:21&lt;br&gt;
  689. We need somewhere to SLOT IN the content that’s actually being provided at index.astro. And in Astro, we do that via a self closing tag called slot. And now as soon as the layout knows where to slot in the information that’s wrapped in the other page, we have our original page back up again, looks exactly the same.&lt;/p&gt;
  690. &lt;p&gt;6:36&lt;br&gt;
  691. Now I’m just going to pop this out in Gitpod into a full tab browser preview because sometimes the simple browser in Gitpod might not have all the same interactivity as the full page preview does. So I just want to show you that those buttons, the counters are in fact working.&lt;/p&gt;
  692. &lt;p&gt;7:11&lt;br&gt;
  693. In fact, the page looks identical to the page we started with, because all we did was pull out the head and enclosed HTML tags. And we’re now rendering them instead via a layout. Alright, so then the whole point of having a layout is to be able to make another page that’s going to use the same thing. So to create a second page in our project, let’s take a look at what index is rendering and figure out what we’re going to need to throw in page two to also render a full document.&lt;/p&gt;
  694. &lt;p&gt;8:01&lt;br&gt;
  695. The first thing we should do is make sure we’re importing the layout. I’m going to start a code fence and I’m going to put a layout, our BaseLayout in there. And let’s take one of the counters, let’s take the Svelte counter, and we will also import that into page two. So we can use that to get some test render. And we know that our layout expects a page title. So let’s give this page a title: “Page Two.”&lt;/p&gt;
  696. &lt;p&gt;8:32&lt;br&gt;
  697. Now we’re ready to actually render some HTML. So we’re going to start again with BaseLayout component, passing the title information, open and close tags to wrap whatever now we decided to render on page two. And we said we wanted to render a counter on page two. So here’s our Svelte counter. And framework components &lt;em&gt;do&lt;/em&gt; need a client directive. I’m just going to choose Load, we’re not going to wait till the page is visible on the page. This is just a very small page anyway.&lt;/p&gt;
  698. &lt;p&gt;9:14&lt;br&gt;
  699. We’ll put a bit of text in here. So right now we’ve got a paragraph tag, and we’ve got a Svelte counter rendered. We go back to index and and look at what we wrapped here. Notice that we do need the body tag; the body was rendered in index. Our layout is not taking care of that. So we are going to put our body and we’re going to put our main tags on page two. I’m pretty sure this default project, its CSS does make use of the main tag. So just to keep things consistent, let’s make sure we’ve also got main in here and then we need to close out main, close out body. Okay, structurally, we should have the same thing that we had for our index page. So I’m going to go up and navigate manually to page two in my little preview here. And in fact, yes, so we have a paragraph rendered, and we have a counter rendered. Now you can’t see in this preview, but if you look at the top of the page, it does actually specify that the title is page two. So that’s working as well. Excellent.&lt;/p&gt;
  700. &lt;p&gt;10:44&lt;br&gt;
  701. Now, if we go back and compare to the index site, though, our index had a header, and our second page does not. Now you might not want every page to say welcome to Astro. But you may very well want the same header on all your pages. So we can, again, refactor and we can pull the header into the layout. But by doing so this time, we have to make sure that we’re also bringing into layout the main and the body tags.&lt;/p&gt;
  702. &lt;p&gt;11:19&lt;br&gt;
  703. So let’s go into the layout and after our head, that’s where we’re going to insert the body, main and header. And then after our slot, we’ll close off the main and close off the body. The slot can go wherever you want that wrapped content to be.&lt;/p&gt;
  704. &lt;p&gt;11:48&lt;br&gt;
  705. Now, if we go back to index, obviously, we don’t want those closing tags duplicated, so we’ll get rid of them. Now our index component is looking pretty minimal, quite easy to read. (I’m not dealing with all the indentation and formatting right now.) But now when we go to page two, same thing, we don’t want our page rendering the body and main tags. Our layout is taking care of that. So refresh the index page, again, looks identical.&lt;/p&gt;
  706. &lt;p&gt;12:18&lt;br&gt;
  707. And that’s what we’re going for: we are not designing, we are not creating anything new here. We are just exploring how to use refactoring to take out some stuff from the pages and have them instead rendered via an Astro layout component.&lt;/p&gt;
  708. &lt;p&gt;12:39&lt;br&gt;
  709. Now if we can have two pages, we can have three pages. So now let’s create page three. And let’s make it super minimal. Let’s see the bare minimum we need to create a new page and what it looks like when there is nothing on a page.&lt;/p&gt;
  710. &lt;p&gt;13:01&lt;br&gt;
  711. We will need the layout. And we will need to give it a title. But I’m going to remove everything wrapped in the layout in the BaseLayout ta. I’m going to remove the paragraph and the counter. I’m going to manually navigate to page three. And what do we have? We have our header. But notice that we DO have our header and we DO have a page and it works… even with nothing inside the BaseLayout open and close tags so your slot can be empty. But this gives you an idea of what your layout looks like with nothing there. This is what the layout is bringing to the table.&lt;/p&gt;
  712. &lt;p&gt;13:47&lt;br&gt;
  713. So we created a couple of new pages. But most importantly, we recreated that index page and didn’t really change anything. It looks exactly to the eye the way it did before. But now it’s being rendered using an Astro layout component.&lt;/p&gt;
  714. &lt;p&gt;Transcribed by &lt;a href=&quot;https://otter.ai&quot;&gt;https://otter.ai&lt;/a&gt;&lt;/p&gt;</content:encoded><category>videos</category><category>astro</category></item><item><title>Creating individual tag pages in Astro via dynamic routes</title><link>https://www.rainsberger.ca/blog/dynamic-routing-tag-pages-in-astro/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/dynamic-routing-tag-pages-in-astro/</guid><description>Now that I&apos;m on a roll with dynamic routing via getStaticPaths() in Astro, I&apos;m checking the next item off my Astro blog wish list: pages to display blog posts by tag.
  715.  
  716. </description><pubDate>Wed, 12 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One issue I was struggling to fully understand regarding &lt;code dir=&quot;auto&quot;&gt;getStaticPaths()&lt;/code&gt; in Astro was… why?&lt;/p&gt;
  717. &lt;p&gt;As I “sneak-previewed” when I described &lt;a href=&quot;https://www.rainsberger.ca/posts/rss-in-astro/&quot;&gt;adding an RSS feed to this Astro blog&lt;/a&gt;, generating a page for each &lt;code dir=&quot;auto&quot;&gt;tag&lt;/code&gt; from all my blog posts can be done with &lt;strong&gt;dynamic routing&lt;/strong&gt;. This is the concept I set out to learn to start the new year, since thus far, all my pages have been created via Astro’s automatic &lt;strong&gt;static routing&lt;/strong&gt; which only requires placing &lt;code dir=&quot;auto&quot;&gt;.md&lt;/code&gt; and/or &lt;code dir=&quot;auto&quot;&gt;.astro&lt;/code&gt; files somewhere under the &lt;code dir=&quot;auto&quot;&gt;src/pages/&lt;/code&gt; path.&lt;/p&gt;
  718. &lt;div&gt;&lt;h2 id=&quot;dynaming-routing-to-create-pages-that-arent-there&quot;&gt;Dynaming Routing to create pages that… “aren’t there”&lt;/h2&gt;&lt;/div&gt;
  719. &lt;p&gt;The way dynamic routing first made sense to me was to think of using it for “creating pages that aren’t there.” (This initial way of thinking of it has helped me understand it more fully. But, this was how it started.)&lt;/p&gt;
  720. &lt;p&gt;It seemed weird to me to (need to?) use dynamic routing to eventually end up at &lt;code dir=&quot;auto&quot;&gt;rainsberger.ca/posts/my-first-post&lt;/code&gt; because… it already existed via static routing! If &lt;code dir=&quot;auto&quot;&gt;src/pages/posts/my-first-post.md&lt;/code&gt; (or &lt;code dir=&quot;auto&quot;&gt;src/pages/posts/my-first-post.astro&lt;/code&gt;) exists, then Astro creates that url automatically and I can totally “get to” a page for that blog post. I didn’t understand examples I found about creating post pages/urls dynamically because I didn’t understand &lt;em&gt;why&lt;/em&gt; I’d need to do that. (So, I think my brain kind of turned off in protest.)&lt;/p&gt;
  721. &lt;p&gt;(It also probably didn’t help (me) that &lt;code dir=&quot;auto&quot;&gt;getStaticPaths()&lt;/code&gt; is also used elsewhere, and isn’t just an Astro thing. So, I never thought to look outside of Astro to figure out what this was, nor did I have prior experience with it to bring to Astro and be like, “Oh, cool. So just like how I do this thing in NextJs…”)&lt;/p&gt;
  722. &lt;p&gt;So, the first thing that helped me get started with Astro’s dynamic routing was to envision the specific use case of &lt;strong&gt;making a page that wasn’t automatically created statically because I hadn’t put a file somewhere&lt;/strong&gt;.&lt;/p&gt;
  723. &lt;p&gt;I had &lt;code dir=&quot;auto&quot;&gt;src/pages/posts/my-first-post.md&lt;/code&gt; but I did NOT have anything like &lt;code dir=&quot;auto&quot;&gt;src/pages/posts/tags/blogging.md&lt;/code&gt;. However, I understood that &lt;strong&gt;dynamic routing&lt;/strong&gt; would let me make pages at those URLS even without those files.&lt;/p&gt;
  724. &lt;div&gt;&lt;h2 id=&quot;creating-a-tag-list-page&quot;&gt;Creating a ‘Tag List’ page&lt;/h2&gt;&lt;/div&gt;
  725. &lt;p&gt;I &lt;em&gt;did&lt;/em&gt; know how to make &lt;code dir=&quot;auto&quot;&gt;src/pages/tags/index.astro&lt;/code&gt;, and I didn’t even need &lt;code dir=&quot;auto&quot;&gt;getStaticPaths()&lt;/code&gt; to do it. So, I started there.&lt;/p&gt;
  726. &lt;p&gt;This page is &lt;strong&gt;statically&lt;/strong&gt; generated, since it’s an Astro page component file somewhere under &lt;code dir=&quot;auto&quot;&gt;/src/pages&lt;/code&gt;. Its content uses &lt;code dir=&quot;auto&quot;&gt;Astro.fetchContent()&lt;/code&gt;, just like my Blog Page or my Full Post Archive page that fetch information about all my Markdown blog post files (ie: content from the Markdown front matter, including its array of tags).&lt;/p&gt;
  727. &lt;p&gt;The difference is that this time I need to create a &lt;code dir=&quot;auto&quot;&gt;Set&lt;/code&gt; of my tags, so that each tag is only listed once. Then I can display each element of the set.&lt;/p&gt;
  728. &lt;p&gt;So with a bit of JavaScript in my Astro front matter, this page doesn’t require a ton of heavy lifting:&lt;/p&gt;
  729. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/pages/tags/index.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; BaseLayout &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../../layouts/BaseLayout.astro&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;let &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Tags&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  730. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;allPosts&lt;/span&gt;&lt;span&gt; = await &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fetchContent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../posts/*.md&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;...new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;([]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;concat&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;([],allPosts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;)))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Tags&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;display: flex; flex-wrap: wrap; margin: 0 auto&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sort&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;/tags/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt; post.tags)))]---&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  731. &lt;div&gt;&lt;h2 id=&quot;creating-individual-tag-pages&quot;&gt;Creating individual tag pages&lt;/h2&gt;&lt;/div&gt;
  732. &lt;p&gt;But now for making a page that &lt;em&gt;doesn’t exist&lt;/em&gt;! Magic!&lt;/p&gt;
  733. &lt;div&gt;&lt;h3 id=&quot;page-slugs--url-routes&quot;&gt;Page slugs / url routes&lt;/h3&gt;&lt;/div&gt;
  734. &lt;p&gt;To create url routes of the form &lt;code dir=&quot;auto&quot;&gt;rainsberger.ca/tags/tagname&lt;/code&gt;, I need to create &lt;code dir=&quot;auto&quot;&gt;src/pages/tags/[tag].astro&lt;/code&gt; The &lt;code dir=&quot;auto&quot;&gt;[tag]&lt;/code&gt; in brackets indicates that this one file will create dynamic routes for multiple different tag names.&lt;/p&gt;
  735. &lt;div&gt;&lt;h3 id=&quot;page-layout&quot;&gt;Page Layout&lt;/h3&gt;&lt;/div&gt;
  736. &lt;p&gt;Because I’m making pages, I still need to structure this &lt;code dir=&quot;auto&quot;&gt;.astro&lt;/code&gt; file like a proper Astro Page Component: it either needs full &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;html&gt;&amp;#x3C;/html&gt;&lt;/code&gt; or needs an Astro Layout. Since I want this page to look like the rest of my pages, I’ll import in the front matter, then wrap my content in my regular &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;BaseLayout&gt;&lt;/code&gt; component.&lt;/p&gt;
  737. &lt;div&gt;&lt;h3 id=&quot;page-content&quot;&gt;Page Content&lt;/h3&gt;&lt;/div&gt;
  738. &lt;p&gt;The content I want to render is some information about each of my &lt;em&gt;blog posts&lt;/em&gt; that happen to be tagged with &lt;em&gt;one specific tag&lt;/em&gt;. So, I’ll need a way to access all my posts (even if I don’t display all of them on a particular page).&lt;/p&gt;
  739. &lt;div&gt;&lt;h3 id=&quot;page-logic&quot;&gt;Page Logic&lt;/h3&gt;&lt;/div&gt;
  740. &lt;p&gt;This page needs to:&lt;/p&gt;
  741. &lt;ul&gt;
  742. &lt;li&gt;fetch info about all my posts&lt;/li&gt;
  743. &lt;li&gt;sort my posts in date order&lt;/li&gt;
  744. &lt;li&gt;create a set of tags used from all the posts&lt;/li&gt;
  745. &lt;/ul&gt;
  746. &lt;p&gt;And then this page needs to return (for rendering as HTML):&lt;/p&gt;
  747. &lt;ul&gt;
  748. &lt;li&gt;an array of &lt;em&gt;tag name (&lt;code dir=&quot;auto&quot;&gt;params&lt;/code&gt;)/posts with that tag name&lt;/em&gt; (&lt;code dir=&quot;auto&quot;&gt;props&lt;/code&gt;) objects&lt;/li&gt;
  749. &lt;/ul&gt;
  750. &lt;div&gt;&lt;h2 id=&quot;astro-page-component&quot;&gt;Astro Page Component&lt;/h2&gt;&lt;/div&gt;
  751. &lt;p&gt;Everything except the &lt;code dir=&quot;auto&quot;&gt;getStaticPaths()&lt;/code&gt; function looks very much like an Astro page I’ve created before where I’ve fetched content from my Markdown posts and rendered them to the page.&lt;/p&gt;
  752. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/pages/tags/[tag].astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; BaseLayout &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../../layouts/BaseLayout.astro&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  753. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// here&apos;s where getStaticPaths() will go!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  754. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;posts&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;props&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;params&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  755. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;let &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;tag;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Posts tagged with &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;posts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; - &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;hr&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;/tags/&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;See all tags...&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;    &lt;main&gt;        &lt;p&gt;Posts tagged with {title}&lt;/p&gt;        {posts.map(post =&gt;            &lt;p&gt;{post.date} - &lt;a href=&quot;&quot;&gt;{post.title}&lt;/a&gt;&lt;/p&gt;        )}        &lt;hr&gt;        &lt;p&gt;&lt;a href=&quot;&quot;&gt;See all tags...&lt;/a&gt;&lt;/p&gt;    &lt;/main&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  756. &lt;p&gt;Once we get our &lt;code dir=&quot;auto&quot;&gt;tag&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;posts&lt;/code&gt; from our &lt;code dir=&quot;auto&quot;&gt;getStaticPaths()&lt;/code&gt; function, we can create any content layout we want using that tag name, and all the content normally available from a Markdown post’s front matter like title, date, url, description, hero image etc.&lt;/p&gt;
  757. &lt;div&gt;&lt;h2 id=&quot;using-getstaticpaths-to-fetch-tag-and-post-data&quot;&gt;Using getStaticPaths() to fetch tag and post data&lt;/h2&gt;&lt;/div&gt;
  758. &lt;p&gt;This function will do my fetching, sorting, creating and adding to a set of tags and return a set of filtered posts corresponding to each tag.&lt;/p&gt;
  759. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// (function to go inside src/pages/tags/[tag].astro)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  760. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export async function getStaticPaths(&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;allPosts&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fetchContent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../posts/*.md&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;sortedPosts&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;allPosts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sort&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; =&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Date&lt;/span&gt;&lt;span&gt;(b&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; - &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Date&lt;/span&gt;&lt;span&gt;(a&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;allTags&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sortedPosts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; allTags&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(tag))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  761. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; Array&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(allTags)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;filteredPosts&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;sortedPosts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; =&gt; &lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(tag))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;params: { tag },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;props: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;posts: filteredPosts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt; new Date(b.date) - new Date(a.date));  const allTags = new Set();  sortedPosts.map(post =&gt; {      post.tags &amp;#x26;&amp;#x26; post.tags.map(tag =&gt; allTags.add(tag))  })  return Array.from(allTags).map((tag) =&gt; {    const filteredPosts = sortedPosts.filter((post) =&gt; post.tags.includes(tag))    return {      params: { tag },      props: {        posts: filteredPosts      }    };  });}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  762. &lt;p&gt;And now… yes, we have tags! You can &lt;a href=&quot;https://www.rainsberger.ca/tags&quot;&gt;see the list of tags&lt;/a&gt; and you can click on any tag to be taken to its tag page.&lt;/p&gt;
  763. &lt;div&gt;&lt;h2 id=&quot;linking-to-tag-pages-elsewhere-on-the-site&quot;&gt;Linking to tag pages elsewhere on the site&lt;/h2&gt;&lt;/div&gt;
  764. &lt;p&gt;You might notice that on this post’s page itself, you can see a list of clickable tags generated from its front matter: &lt;code dir=&quot;auto&quot;&gt;tags: [&quot;blogging&quot;, &quot;astro&quot;]&lt;/code&gt;. This is an array that can be used in any &lt;code dir=&quot;auto&quot;&gt;.astro&lt;/code&gt; component that fetches your front matter data.&lt;/p&gt;
  765. &lt;p&gt;Now that I have tag pages, I can update my &lt;code dir=&quot;auto&quot;&gt;MarkdownPostLayout.astro&lt;/code&gt; so that each post displays its own linked tags. Here’s a simplified version of this nested layout, which is itself inside my &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;BaseLayout&gt;&lt;/code&gt; (so that these posts look like all my other pages). I’m displying each tag, linked to its own tag page, between the posts title and the author/date.&lt;/p&gt;
  766. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/layouts/MarkdownPostLayout.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; BaseLayout &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../layouts/BaseLayout.astro&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const {&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;} = &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;props&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;display:flex;&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;/tags/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Written by: &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;author&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; on &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;postDate&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;article&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;slot&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;article&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;/posts&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;See more posts ...&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;    &lt;main&gt;        &lt;h1&gt;{content.title}&lt;/h1&gt;        &lt;div&gt;            {content.tags.map((tag) =&gt; &lt;p&gt;&lt;a href=&quot;&quot;&gt;{tag}&lt;/a&gt;&lt;/p&gt;)}        &lt;/div&gt;        &lt;p&gt;Written by: {content.author} on {postDate}&lt;/p&gt;        &lt;article&gt;          &lt;slot&gt;&lt;/slot&gt;        &lt;/article&gt;        &lt;p&gt;&lt;a href=&quot;&quot;&gt;See more posts ...&lt;/a&gt;&lt;/p&gt;    &lt;/main&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  767. &lt;p&gt;Similarly, I updated both my main Blog page showing my recent posts, as well as my full Post Archive listing to include these linked tags along with other post content.&lt;/p&gt;
  768. &lt;p&gt;I think it’s safe to say you can now find tags all over the place on this blog! So, you have no excuse for not checking them out.  ;)&lt;/p&gt;</content:encoded><category>blogging</category><category>astro</category></item><item><title>Thinking in Astro, Coming from React</title><link>https://www.rainsberger.ca/blog/thinking-in-astro-from-react/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/thinking-in-astro-from-react/</guid><description>Astro sites allow you to use React, but they aren&apos;t React, themselves. Understanding the differences between React and Astro can help you get started more quickly, so here are some thoughts on how to think like an Astro-naut!
  769.  
  770. </description><pubDate>Fri, 12 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When I first built basic websites, back in nineteen-ninety… &lt;em&gt;mumble mumble&lt;/em&gt;, I figured out enough HTML to make a static page, then link to another page. My first site for the small tutoring company I worked for didn’t even contain css, let alone JavaScript. Just html elements. (But, it did have a table!)&lt;/p&gt;
  771. &lt;div&gt;&lt;h2 id=&quot;back-in-my-day&quot;&gt;Back in my day…&lt;/h2&gt;&lt;/div&gt;
  772. &lt;p&gt;HTML elements, content organized on separate pages, links between them… this was my early introduction to “web development,” such as it was back then. By the time I owned my own tutoring company in 2002, I built a website that included font families, sizes and colours! (Still tables, though.) By 2005, I had discovered places online to look for tiny scripts (&lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;script language=&quot;javascript&quot;&gt;&lt;/code&gt;) that you could include in your HTML for some basic interactivity. But, the underlying structure was &lt;em&gt;the page.&lt;/em&gt; You have an index page, where the browser assumes you want to “start” unless told otherwise, but other content, for the most part, lives on other pages.&lt;/p&gt;
  773. &lt;div&gt;&lt;h2 id=&quot;where-we-went&quot;&gt;Where we went…&lt;/h2&gt;&lt;/div&gt;
  774. &lt;p&gt;Fast forward to learning React in 2020, and (my) introduction to thinking about &lt;em&gt;rendering an app to a page&lt;/em&gt;.&lt;/p&gt;
  775. &lt;p&gt;Sites built with React, yes, &lt;em&gt;do&lt;/em&gt; have that entry HTML index page. But, it doesn’t really feel like a first-class citizen. Nothing is really “on” (or, maybe nothing really “lives in?”) that page in the same way it used to “back in my day.” A React’s index.html page is a container — a single “root” element — for all the good stuff. It’s not even just a single &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;div id=&quot;root&quot;&gt;&amp;#x3C;/div&gt;&lt;/code&gt;, it’s generally a single &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;App /&gt;&lt;/code&gt; rendered in that single &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;div&gt;&lt;/code&gt;. That’s a lot of “single” thinking! It’s easy to picture your React site or app as “a single thing” where you can point to the top of the tree.&lt;/p&gt;
  776. &lt;div&gt;&lt;h2 id=&quot;where-were-going&quot;&gt;Where we’re going…&lt;/h2&gt;&lt;/div&gt;
  777. &lt;p&gt;I find the easiest way to start “thinking in Astro” is to go back to the days of the page. Because in Astro, yes you (must) have an index.html page, but you can &lt;em&gt;also&lt;/em&gt; have an about.html page and contact.html page… and these exist &lt;em&gt;independently of each other&lt;/em&gt;, as equals. You can (and probably will!) make use of an Astro layout so that they share some common features. But, you are building &lt;em&gt;each page&lt;/em&gt; separately, and adding those common elements &lt;em&gt;to it&lt;/em&gt;, not starting from a common, shared entry point.&lt;/p&gt;
  778. &lt;p&gt;So if you’re just starting out with Astro and wondering, “Where does my “app” go?”… it… doesn’t?&lt;/p&gt;
  779. &lt;div&gt;&lt;h2 id=&quot;how-it-changes&quot;&gt;How it changes…&lt;/h2&gt;&lt;/div&gt;
  780. &lt;p&gt;Maybe you have a React Router project (like the first version of my sBird app!) and use “routes” to render different content to the screen under different url paths. Well, get ready to create yourself some individual page files! (I’ll be detailing how I did this for my bird app in an upcoming series of blog posts.)&lt;/p&gt;
  781. &lt;p&gt;Maybe you have a Gatsby blog, and like me, you diligently went through the tutorial on dynamically creating new pages using Gatsby’s Filesystem Route API so that each .md or .mdx blog post has its own page. Well, get ready to… do nothing! Astro respects the almighty page, and &lt;em&gt;assumes&lt;/em&gt; that you’ve got pages, and posts and that you’d like them each to have their own page. As long as you put your files in the expected source folders, That. Just. Happens.&lt;/p&gt;
  782. &lt;div&gt;&lt;h2 id=&quot;back-to-the-future&quot;&gt;Back… to the future!&lt;/h2&gt;&lt;/div&gt;
  783. &lt;p&gt;There’s obviously so much more to say about Astro, how it works, and the tasks it’s trying to help you achieve. And, perhaps most importantly, &lt;strong&gt;where and how React fits in and co-exists with Astro&lt;/strong&gt; (…because it totally does! My site is actually &lt;em&gt;all&lt;/em&gt; kinds of React components all over the place!)&lt;/p&gt;
  784. &lt;p&gt;And, I promise, Astro is not “stuck in the past”! But, as you experiment with and learn more about Astro, especially if you’re coming from React, and trying to fit your existing React into your Astro site, I find that it can help to try “thinking in Astro”… and party like it’s 1999!&lt;/p&gt;
  785. &lt;p&gt;&lt;img src=&quot;https://media.publit.io/file/RJD/200.gif&quot; alt=&quot;The musician Prince on stage singing, Tonight I&amp;#x27;m gonna party like it&amp;#x27;s 1999.&quot;&gt;&lt;/p&gt;</content:encoded><category>react</category><category>astro</category></item><item><title>Getting started with React components in Astro</title><link>https://www.rainsberger.ca/blog/react-astro-first-things/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/react-astro-first-things/</guid><description>Yes, you can write and render your React components in your Astro page. But remember, Astro isn&apos;t React, and you might be getting error messages when you totally know your React component should work. It&apos;s not complicated to establish the Astro-React relationship, but you might not be used to doing these things. . .
  786.  
  787. </description><pubDate>Wed, 13 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h1 id=&quot;react-gut-check&quot;&gt;React Gut Check&lt;/h1&gt;&lt;/div&gt;
  788. &lt;p&gt;Here are the very first, super-basic things to check that might be causing your perfectly-awesome React components to throw Astro errors:&lt;/p&gt;
  789. &lt;div&gt;&lt;h2 id=&quot;1-specify-the-react-renderer-in-astroconfigmjs&quot;&gt;1. Specify the React renderer in astro.config.mjs&lt;/h2&gt;&lt;/div&gt;
  790. &lt;p&gt;Astro can render a variety of components: React, Svelte, Vue, Preact, Solid … but, it first needs to import the appropriate renderer(s) to do so. If you didn’t specify renderers when creating your project, your &lt;code dir=&quot;auto&quot;&gt;astro.config.mjs&lt;/code&gt; may have started with an empty renderers array, or it may have been commented out. It should include all renderers for components you intend to use. Make sure the following is in your config file at the root of your project (example shown with renderers for React and Svelte, but you only need the one(s) you intend to use):&lt;/p&gt;
  791. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;astro.config.mjs&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;renderers: [&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@astrojs/renderer-react&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@astrojs/renderer-svelte&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  792. &lt;div&gt;&lt;h2 id=&quot;2-import-your-react-component-with-its-file-extension&quot;&gt;2. Import your React component &lt;em&gt;with its file extension&lt;/em&gt;&lt;/h2&gt;&lt;/div&gt;
  793. &lt;p&gt;You have made sure to include your React renderer, but your super-happy-awesome React component still causes an error? Perhaps something like “Failed to fetch dynamically imported module”?&lt;/p&gt;
  794. &lt;p&gt;This can be a particular D’oh! moment when first getting used to writing React in Astro, especially if you’re copy-pasting or uploading React files into your Astro project. Your React component may &lt;em&gt;itself&lt;/em&gt; be importing child components, and you aren’t used to writing a file extension for &lt;em&gt;those&lt;/em&gt; imports. But, Astro &lt;em&gt;does&lt;/em&gt; require you to type out the full import path. So, you may have to inspect all your imports carefully to make sure all .js/.jsx file extensions are included.&lt;/p&gt;
  795. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/pages/my-astro-page.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; BaseLayout &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../layouts/BaseLayout.astro&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; MyReactComponent &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;../components/MyReactComponent.jsx&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  796. &lt;div&gt;&lt;h2 id=&quot;3-hydrate-your-react-component-for-interactivity&quot;&gt;3. Hydrate your React component for interactivity&lt;/h2&gt;&lt;/div&gt;
  797. &lt;p&gt;Why do we fall for this one over and over again? Your technically-perfect React component has been imported into your .astro file, extension and all, and it &lt;em&gt;looks&lt;/em&gt; like it’s working. But it… doesn’t work?&lt;/p&gt;
  798. &lt;p&gt;Check to see that you have specified a hydration method with a &lt;code dir=&quot;auto&quot;&gt;client:*&lt;/code&gt; directive!&lt;/p&gt;
  799. &lt;p&gt;If you render &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;MyAmazingReactComponentThatShouldTotallyWork /&gt;&lt;/code&gt; in an Astro page, the way you would in a React component, you’ll only get the static HTML representation of your component, with no interactivity. To include your component’s functionality, be sure to specify one of the available options such as:&lt;/p&gt;
  800. &lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;MyAmazingReactComponentThatShouldTotallyWork client:load /&gt;&lt;/code&gt; (to load instantly)
  801. or
  802. &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;MyAmazingReactComponentThatShouldTotallyWork client:visible /&gt;&lt;/code&gt; (to load only when the component becomes visible on the page. This is handy for something lower on the page that doesn’t need to load until / unless the user scrolls down to it)&lt;/p&gt;
  803. &lt;p&gt;These are the top three items on my checklist when a React component isn’t working, especially if I’ve been writing my React code separately in a different environment, outside of my main Astro project with the intention of adding the files later.&lt;/p&gt;
  804. &lt;p&gt;I mean, sure, there &lt;em&gt;could&lt;/em&gt; be a flaw in my React code, but I can sometimes save myself a whole lot of pain and suffering if I just check these things first!&lt;/p&gt;</content:encoded><category>react</category><category>astro</category></item><item><title>Astro is a learner&apos;s paradise!</title><link>https://www.rainsberger.ca/blog/astro-learners-paradise/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/astro-learners-paradise/</guid><description>One of Astro&apos;s selling points has been that you can bring your own mix-and-match components... but I didn&apos;t really get the power of that as a learner until just now, listening to Fred K. Schott interviewed on devtools.fm
  805.  
  806. </description><pubDate>Thu, 30 Sep 2021 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h1 id=&quot;astro-is-a-learners-paradise&quot;&gt;Astro is a learner’s paradise!&lt;/h1&gt;&lt;/div&gt;
  807. &lt;p&gt;My most recent experiment was to render two identical components, one counter/button written in React (which I know) and one written in Svelte (which I do not know) on the same page. This was originally going to be a post comparing the two, and that post will happen.&lt;/p&gt;
  808. &lt;p&gt;But, while doing my end-of-the-month photo organizing, I finally got around to listening to &lt;a href=&quot;https://twitter.com/FredKSchott&quot;&gt;Fred&lt;/a&gt; being &lt;a href=&quot;https://devtools.fm/episode/14&quot;&gt;interviewed on devtools.fm about Astro&lt;/a&gt;… and THAT’s when it really clicked for me that &lt;strong&gt;Astro is the reason I can so easily play around with these various front-end tools, languages and frameworks as a learner&lt;/strong&gt;.&lt;/p&gt;
  809. &lt;p&gt;When I set out to try writing a Svelte component, it didn’t even &lt;em&gt;occur&lt;/em&gt; to me to go to CodeSandbox and find a Svelte template (which is absolutely what I would have otherwise had to do). Admittedly, I did have to go into my Astro config file and add a Svelte renderer, but Astro’s error message was helpful in pointing that out when I was initially unsuccessful in rendering my Svelte counter.&lt;/p&gt;
  810. &lt;p&gt;&lt;strong&gt;There was zero start-up cost to write my first Svelte component, and Fred explains why (at 36:02):&lt;/strong&gt;&lt;/p&gt;
  811. &lt;blockquote&gt;
  812. &lt;p&gt;“…you’ve heard about this new framework, we are a great way to try it out. In any other project, you have to make a bet, this whole thing is gonna be React, and then that’s your project. Astro’s one of the only ways you can … try it out, this one component. If you don’t like it, pull it out! No big deal! You didn’t just have to re-architect your entire project because you wanted to try a new framework… it’s certainly a great thing for experimentation. There’s no cost to me to bring in a new framework, and that framework doesn’t actually break everything else that I’ve done.”&lt;/p&gt;
  813. &lt;/blockquote&gt;
  814. &lt;p&gt;Here are a couple of other quotations from the interview hosts that I found noteworthy enough to transcribe (before I realized that a transcription was available on their website, of course. SMRT.)&lt;/p&gt;
  815. &lt;blockquote&gt;
  816. &lt;p&gt;“There’s a lot to be said, if you do web development for a living, being able to play with different components and interject them directly into your blog posts. It’s like, ‘Hey, here’s this really cool vue component, and the thing that it does!” without really having to think about your architecture. That’s super powerful.’”&lt;/p&gt;
  817. &lt;/blockquote&gt;
  818. &lt;p&gt;&lt;img src=&quot;https://www.rainsberger.ca/images/birdhrthin.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
  819. &lt;blockquote&gt;
  820. &lt;p&gt;“Just the idea that this can be expanded in the future, so if React falls out of vogue and there’s some new, better thing that comes along, we can jump on that ship and incrementally migrate with little to no cost.”&lt;/p&gt;
  821. &lt;/blockquote&gt;
  822. &lt;p&gt;So, eventually I’ll get around to writing the post to accompany the process of creating my React and Svelte counter buttons in the same page experiment, but for now, I thought it was noteworthy to discuss &lt;em&gt;why&lt;/em&gt; that is such a big deal in the first place:&lt;/p&gt;
  823. &lt;p&gt;I didn’t have to go to CodeSandbox and look for a Svelte template, or find something to fork on GitHub.&lt;/p&gt;
  824. &lt;p&gt;I didn’t have to spin up anything new/different. I just literally added a new component, with a different file extension, into my already-existing, already-working blog.&lt;/p&gt;
  825. &lt;p&gt;I could LEARN Svelte through Astro, if I wanted to.&lt;/p&gt;
  826. &lt;p&gt;This isn’t just a “write in what you feel comfortable in” tool. This thing I’m learning &lt;em&gt;is itself&lt;/em&gt; a learning tool, and code playground, all wrapped into my plain old website!&lt;/p&gt;</content:encoded><category>astro</category><category>blogging</category></item><item><title>Rewriting a React Component as an Astro Component</title><link>https://www.rainsberger.ca/blog/rewrite-react-as-astro/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/rewrite-react-as-astro/</guid><description>I&apos;d been using a lot of components in my Astro blog, but I realized that they were almost all React components, because that&apos;s what I know. So, I wanted to try reproducing some functionality by replacing a React component with a corresponding Astro component.
  827.  
  828. </description><pubDate>Thu, 09 Sep 2021 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h1 id=&quot;rewriting-a-reactjsx-component-as-an-astro-component&quot;&gt;Rewriting a React/JSX Component as an Astro Component&lt;/h1&gt;&lt;/div&gt;
  829. &lt;p&gt;Astro describes their component syntax as “HTML enhanced with JavaScript.” &lt;em&gt;(“Hey, &lt;strong&gt;I’m&lt;/strong&gt; a person who knows HTML and JavaScript…”)&lt;/em&gt;&lt;/p&gt;
  830. &lt;p&gt;From Astro’s docs:&lt;/p&gt;
  831. &lt;blockquote&gt;
  832. &lt;p&gt;Astro component syntax is a superset of HTML … An Astro component represents some snippet of HTML in your project.&lt;/p&gt;
  833. &lt;/blockquote&gt;
  834. &lt;p&gt;Here’s what my test Astro page looked like:&lt;/p&gt;
  835. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/pages/flickr-test.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; BaseLayout &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;../layouts/BaseLayout.astro&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; FlickrPhoto &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;../components/FlickrPhoto.jsx&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// Note: importing a jsx component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;allPhotosResponse&lt;/span&gt;&lt;span&gt; = await &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://www.flickr.com/services/rest/?...&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;allPhotosResult&lt;/span&gt;&lt;span&gt; = await &lt;/span&gt;&lt;span&gt;allPhotosResponse&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;allPhotos&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;allPhotosResult&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;photos&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;photo&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Flickr Import Test Page&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Test of &quot;Get all my public photos&quot; from Flickr&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;allPhotos&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;photo&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;FlickrPhoto&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;photo&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;client&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;BaseLayout&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;    &lt;main&gt;        &lt;h1&gt;Test of &amp;#x22;Get all my public photos&amp;#x22; from Flickr&lt;/h1&gt;        {allPhotos.map((photo) =&gt; (                    ))}    &lt;/main&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  836. &lt;p&gt;This page renders a list of my Flickr images, showing a photo with a link back to Flickr, and captioning with both the image title and the photo ID number.&lt;/p&gt;
  837. &lt;p&gt;… and here’s what my React component looked like:&lt;/p&gt;
  838. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/components/FlickrPhoto.jsx&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; React &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;react&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
  839. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FlickrPhoto&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;picsrc&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://live.staticflickr.com/65535/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;_z.jpg&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;picurl&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://www.flickr.com/photos/sarahrainsberger/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; - &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;picurl&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;picsrc&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;640&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt; /&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;            &lt;p&gt;{title} - {id}&lt;/p&gt;            &lt;a href=&quot;&quot;&gt;&lt;img src=&quot;&quot;&gt;&lt;/a&gt;            )}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  840. &lt;p&gt;To write the new Astro component that performed the same function as the old React component, I used much of the same code, but the structure is slightly different.&lt;/p&gt;
  841. &lt;div&gt;&lt;h3 id=&quot;react-component-structure-vs-astro-component-structure&quot;&gt;React Component Structure vs Astro Component Structure&lt;/h3&gt;&lt;/div&gt;
  842. &lt;p&gt;A React component (at least, a small one like this) is a &lt;strong&gt;function that must be exported.&lt;/strong&gt; This function can take props passed from the Astro page which can then be destructured and used within the function. This function’s &lt;strong&gt;return&lt;/strong&gt; is what generates the HTML to be rendered to the page.&lt;/p&gt;
  843. &lt;p&gt;An Astro component, however, is &lt;strong&gt;HTML with a frontmatter component script inside a “code fence” with full support for JavaScript and TypeScript that will run server-side during build and provides values available to the HTML.&lt;/strong&gt; A function is not explicitly written (nor is it exported), but the pieces of the Astro component do correspond to a JSX function: Astro’s “code fence” is analagous to the part of the function before the render(), and its main body corresponds to function’s render(). So, we can create the same component functionality just with a little slicing and dicing of the code we already have.&lt;/p&gt;
  844. &lt;div&gt;&lt;h3 id=&quot;the-functions-performed-by-the-component-to-be-reproduced&quot;&gt;The functions performed by the component to be reproduced&lt;/h3&gt;&lt;/div&gt;
  845. &lt;p&gt;My Astro page fetches data about my photos from Flickr, and maps over the resulting photos generating a “FlickrPhoto” (my component!) for each one. &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;FlickrPhoto /&gt;&lt;/code&gt; is passed information about each individual photo as a &lt;code dir=&quot;auto&quot;&gt;photoprops&lt;/code&gt; object. The properties of interest (&lt;code dir=&quot;auto&quot;&gt;id&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;title&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;secret&lt;/code&gt;) are first destructured within my FlickrPhoto function, then used as variables throughout to generate an image source link and page url for the photo. Additionally, these variables are used to determine what the page should display, in this case some properties as text, and also the image with a link back to its page on Flickr.&lt;/p&gt;
  846. &lt;div&gt;&lt;h3 id=&quot;reproducing-the-non-rendering-actions-from-a-react-function-in-an-astro-code-fence&quot;&gt;Reproducing the non-rendering actions from a React function in an Astro code fence&lt;/h3&gt;&lt;/div&gt;
  847. &lt;p&gt;The &lt;em&gt;non-rendering&lt;/em&gt; actions my React function performs are:&lt;/p&gt;
  848. &lt;ol&gt;
  849. &lt;li&gt;accept props&lt;/li&gt;
  850. &lt;li&gt;destructure props&lt;/li&gt;
  851. &lt;li&gt;use the destructured properties to create some https links&lt;/li&gt;
  852. &lt;/ol&gt;
  853. &lt;p&gt;These are the actions that now need to occur in my Astro code fence, and here’s what it looks like:&lt;/p&gt;
  854. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;props&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;picsrc&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://live.staticflickr.com/65535/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;_z.jpg&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;picurl&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://www.flickr.com/photos/sarahrainsberger/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  855. &lt;p&gt;So what’s different?&lt;/p&gt;
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868.  
  869.  
  870.  
  871.  
  872.  
  873.  
  874.  
  875.  
  876.  
  877. &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;React Component&lt;/th&gt;&lt;th&gt;Astro Component&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;props passed as the argument of a function&lt;/td&gt;&lt;td&gt;props defined in code fence via Astro.props&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;props object destructured within the function body&lt;/td&gt;&lt;td&gt;props object destructured in the code fence&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;variables defined in the function body&lt;/td&gt;&lt;td&gt;variables defined in the code fence&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
  878. &lt;p&gt;But, notice that other than where/how props are imported for use by the component, the JavaScript-y goodness is identical!&lt;/p&gt;
  879. &lt;div&gt;&lt;h3 id=&quot;reproducing-the-rendering-of-a-react-function-in-an-astro-component-file&quot;&gt;Reproducing the rendering of a React function in an Astro component file&lt;/h3&gt;&lt;/div&gt;
  880. &lt;p&gt;The &lt;em&gt;rendering&lt;/em&gt; actions my React function performs are:&lt;/p&gt;
  881. &lt;ol&gt;
  882. &lt;li&gt;create a &lt;code dir=&quot;auto&quot;&gt;div&lt;/code&gt; for each photo&lt;/li&gt;
  883. &lt;li&gt;display the photo’s title and id number as text&lt;/li&gt;
  884. &lt;li&gt;display an image of the photo with a link back to the photo’s page&lt;/li&gt;
  885. &lt;/ol&gt;
  886. &lt;p&gt;These are the actions that now need to occur in my Astro code, and here’s what it looks like:&lt;/p&gt;
  887. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; - &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;picurl&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt; &gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;picsrc&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;640&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt; /&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;  &lt;p&gt;{title} - {id}&lt;/p&gt;  &lt;a href=&quot;&quot;&gt;&lt;img src=&quot;&quot;&gt;&lt;/a&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  888. &lt;p&gt;So what’s different?&lt;/p&gt;
  889.  
  890.  
  891.  
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906. &lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;React Component&lt;/th&gt;&lt;th&gt;Astro Component&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Content to be rendered occurs within the render() function&lt;/td&gt;&lt;td&gt;Content to be rendered exists on its own, in the main body of the component&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The function needs to be exported so that another file can import it&lt;/td&gt;&lt;td&gt;Astro components do not need to be explicitly exported; they are available to other components simply by importing&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
  907. &lt;p&gt;But, the &lt;code dir=&quot;auto&quot;&gt;div&lt;/code&gt; and all its contents are exactly the same!&lt;/p&gt;
  908. &lt;p&gt;So the entire Astro component that replaces my React component is:&lt;/p&gt;
  909. &lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/components/FlickrPhoto.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;props&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const { &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt; } = &lt;/span&gt;&lt;span&gt;photoprops&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;picsrc&lt;/span&gt;&lt;span&gt;= &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://live.staticflickr.com/65535/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;secret&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;_z.jpg&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const &lt;/span&gt;&lt;span&gt;picurl&lt;/span&gt;&lt;span&gt;= &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;https://www.flickr.com/photos/sarahrainsberger/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; - &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;picurl&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt; &gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;picsrc&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;640&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt; /&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&quot;&gt;  &lt;p&gt;{title} - {id}&lt;/p&gt;  &lt;a href=&quot;&quot;&gt;&lt;img src=&quot;&quot;&gt;&lt;/a&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  910. &lt;div&gt;&lt;h3 id=&quot;using-the-new-astro-component-in-the-page&quot;&gt;Using the new Astro component in the page&lt;/h3&gt;&lt;/div&gt;
  911. &lt;p&gt;To make the switch to using this new Astro component on my page, I had to change the import on my Astro page from .jsx to .astro (because otherwise, my two files had the same name and were in the same location) … and that was the &lt;em&gt;only&lt;/em&gt; change required on the page itself! Yay!&lt;/p&gt;</content:encoded><category>react</category><category>astro</category></item><item><title>Javascript 5-pin bowling simulation in CodePen</title><link>https://www.rainsberger.ca/blog/5-pin-bowling-simulation/</link><guid isPermaLink="true">https://www.rainsberger.ca/blog/5-pin-bowling-simulation/</guid><description>When you code for @jbrains, you get 5-pin bowling coding assignments!
  912.  
  913. </description><pubDate>Wed, 25 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;look-at-me-im-a-pin-setter&quot;&gt;Look at me, I’m a pin setter!&lt;/h2&gt;&lt;/div&gt;
  914. &lt;p&gt;Here’s what kept me busy yesterday… &lt;a href=&quot;https://codepen.io/sarah11918/pen/rNwNEBL&quot;&gt;5-pin Bowling Code Pen&lt;/a&gt;&lt;/p&gt;
  915. &lt;p&gt;(This preview doesn’t happen to show the console output, which is where I print some of the data, but you get all the hot pin action in this embed, and you can click through to see the code.)&lt;/p&gt;
  916. &lt;p data-height=&quot;400&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;rNwNEBL&quot; data-user=&quot;sarah11918&quot;&gt;
  917.  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/sarah11918/pen/rNwNEBL&quot;&gt;
  918.  5-pin bowling&lt;/a&gt; by Sarah Rainsberger (&lt;a href=&quot;https://codepen.io/sarah11918&quot;&gt;@sarah11918&lt;/a&gt;)
  919.  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
  920. &lt;/p&gt;
  921. </content:encoded><category>javascript</category></item></channel></rss>

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.rssboard.org/rss-validator/check.cgi?url=https%3A//www.rainsberger.ca/blog/rss.xml

Software created by Sam Ruby, Mark Pilgrim, Joseph Walton and Phil Ringnalda