<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sophia Brandt</title>
    <description>The latest articles on Forem by Sophia Brandt (@sophiabrandt).</description>
    <link>https://forem.com/sophiabrandt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F97572%2F03968adb-a18e-47a4-8551-e2ba4cc222eb.png</url>
      <title>Forem: Sophia Brandt</title>
      <link>https://forem.com/sophiabrandt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sophiabrandt"/>
    <language>en</language>
    <item>
      <title>TIL: Insert Macros for the Helix Editor</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Wed, 26 Jul 2023 19:30:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/til-insert-macros-for-the-helix-editor-10bb</link>
      <guid>https://forem.com/sophiabrandt/til-insert-macros-for-the-helix-editor-10bb</guid>
      <description>&lt;p&gt;I’ve been using the &lt;strong&gt;&lt;a href="https://helix-editor.com/"&gt;Helix editor&lt;/a&gt;&lt;/strong&gt; for two weeks now as my daily driver in my personal coding projects.&lt;br&gt;&lt;br&gt;
Helix is a modern terminal text editor that’s quite capable as a tool for writing code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Kakoune / Neovim inspired editor, written in Rust.&lt;/p&gt;

&lt;p&gt;Features&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vim-like modal editing&lt;/li&gt;
&lt;li&gt;Multiple selections&lt;/li&gt;
&lt;li&gt;Built-in language server support&lt;/li&gt;
&lt;li&gt;Smart, incremental syntax highlighting and code editing via tree-sitter&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;After some initial bumps in the road due to my Vim muscle memory, I have grown quite fond of Helix. For my pet projects (TypeScript) it works well.&lt;/p&gt;

&lt;p&gt;The language server support is great. It offers me the convenience I am used to from other editors (IntelliJ) - auto-complete functionality, hover information and so forth.&lt;br&gt;&lt;br&gt;
Helix is not a fully-fledged IDE, but it doesn’t aim to be one. It is supposed to be an alternative to Kakoune or Vim/NeoVim.&lt;/p&gt;
&lt;h2&gt;
  
  
  Insert Macros
&lt;/h2&gt;

&lt;p&gt;My NeoVim config sports an “insert macro” for the fat arrow (=&amp;gt;). When I type ‘hsr’ in insert mode, the editor automatically replaces these three characters with a fat arrow (hashrocket).&lt;/p&gt;

&lt;p&gt;Here is how the key mapping looks in Vim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# custom/keymappings.vim
inoremap hsr =&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;And the same config in lua (NeoVim):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim.api.nvim_set_keymap('i', 'hsr', '=&amp;gt;', { silent = true, noremap = true }),

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

&lt;/div&gt;



&lt;p&gt;This can also be achieved in Helix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/.config/helix/config.toml
h = { s = { r = ["normal_mode", ":insert-output echo '=&amp;gt;'", "collapse_selection", "insert_at_line_end"] } }

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://helix-editor.com/"&gt;Helix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.sidebits.tech/vim-insert-mode-tips-tricks/"&gt;Vim insert mode tips &amp;amp; tricks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>helix</category>
      <category>helixeditor</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Keyoxide Proof</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Wed, 09 Nov 2022 14:32:38 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/keyoxide-proof-42o6</link>
      <guid>https://forem.com/sophiabrandt/keyoxide-proof-42o6</guid>
      <description>&lt;p&gt;[Verifying my keyoxide cryptographic key: &lt;a href="https://keyoxide.org/4C38CC1AF264C3DE8D6D97283B31E6D41B517DA5"&gt;https://keyoxide.org/4C38CC1AF264C3DE8D6D97283B31E6D41B517DA5&lt;/a&gt;]&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Notes on “Building a Pragmatic Unit Test Suite”</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Sun, 06 Nov 2022 20:55:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/notes-on-building-a-pragmatic-unit-test-suite-5067</link>
      <guid>https://forem.com/sophiabrandt/notes-on-building-a-pragmatic-unit-test-suite-5067</guid>
      <description>&lt;p&gt;Here are some notes on the course “Building a Pragmatic Unit Test Suite” by Vladimir Khorikov.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goals and Guidelines
&lt;/h2&gt;

&lt;p&gt;Unit tests help with &lt;em&gt;confidence&lt;/em&gt;: you know that changes don't break functionality.&lt;/p&gt;

&lt;p&gt;Not all unit tests are equal.&lt;/p&gt;

&lt;p&gt;Coverage metrics are problematic: you can work around them, for example, by writing assertion-free unit tests.&lt;br&gt;&lt;br&gt;
Coverage metrics are a good negative indicator, but 100% test coverage is impractical.&lt;/p&gt;

&lt;p&gt;Test are code, and you also have to pay a maintenance cost for your tests.&lt;/p&gt;

&lt;p&gt;What makes a unit test valuable?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;carefully choose code to test&lt;/li&gt;
&lt;li&gt;use the most valuable tests only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good unit test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has a high chance of catching a regression error&lt;/li&gt;
&lt;li&gt;has a low chance of producing a false positive&lt;/li&gt;
&lt;li&gt;provides fast feedback&lt;/li&gt;
&lt;li&gt;has low maintenance cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Testing trivial code is not worth the cost.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Decouple tests from implementation details as much as possible.&lt;/p&gt;

&lt;p&gt;Spend most of the time on testing business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Styles of Unit Testing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;output-based verification (functional style)&lt;/li&gt;
&lt;li&gt;state verification&lt;/li&gt;
&lt;li&gt;collaboration verification (uses &lt;em&gt;test doubles&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hexagonal Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rK0qtNLu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Hexagonal_Architecture.svg/768px-Hexagonal_Architecture.svg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rK0qtNLu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Hexagonal_Architecture.svg/768px-Hexagonal_Architecture.svg.png" alt="hexagonal architecture" width="768" height="768"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;image from &lt;a href="https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)"&gt;Wikipedia&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Detail
&lt;/h2&gt;

&lt;p&gt;Public API is the surface area that you can access from outside a class.&lt;/p&gt;

&lt;p&gt;What are the requirements?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;address an immediate goal of the client code&lt;/li&gt;
&lt;li&gt;address that goal completely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Look at the client code: if it uses more than 1 operation to achieve a single goal, the class is leaking implementation details.&lt;/p&gt;

&lt;p&gt;Note: Neighboring classes might be aware of implementation details.&lt;br&gt;&lt;br&gt;
Example: the Root Entity of an &lt;em&gt;Aggregate&lt;/em&gt; (Domain Driven Design) might know about implementation details of the Entities.&lt;/p&gt;

&lt;p&gt;Communication inside a hexagon is implementation detail.&lt;br&gt;&lt;br&gt;
Between hexagons a public API of the hexagon exist (contract).&lt;/p&gt;

&lt;h3&gt;
  
  
  Styles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;functional style: has no state, easy to maintain, offers the best protection against false positive&lt;/li&gt;
&lt;li&gt;state verification: should verify through public API, reasonable maintenance cost&lt;/li&gt;
&lt;li&gt;collaboration verification: within the hexagon lots of false positives; between hexagons more stable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Black-Box Testing Vs. White-Box Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;black-box testing: testing without knowing the internal structure&lt;/li&gt;
&lt;li&gt;white-box testing: testing the internal structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adhere to black-box testing as much as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business Requirements
&lt;/h3&gt;

&lt;p&gt;Does the test verify a business requirement?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;view your code from the end user's perspective&lt;/li&gt;
&lt;li&gt;verify its observable behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Integration Tests
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;test data cleanup: wipe out all data &lt;em&gt;before&lt;/em&gt; test execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unit Testing Anti-Patterns
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;private methods: if needed expose the hidden abstraction by extracting a new concept&lt;/li&gt;
&lt;li&gt;expose state getters: test the observable behavior only&lt;/li&gt;
&lt;li&gt;leaking domain knowledge to tests: use property-paced testing, or verify end result&lt;/li&gt;
&lt;li&gt;code pollution (introduce additional code just to enable unit testing)&lt;/li&gt;
&lt;li&gt;overriding methods in classes-dependencies: violates single-repository-principle, instead split functionality into different pieces&lt;/li&gt;
&lt;li&gt;non-determinism in tests: try to avoid testing async code (separate code into async/sync), use Tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pluralsight.com/courses/pragmatic-unit-testing"&gt;Building a Pragmatic Unit Test Suite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Write Better in Neovim With Languagetool</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Wed, 26 Oct 2022 12:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/write-better-in-neovim-with-languagetool-1b4l</link>
      <guid>https://forem.com/sophiabrandt/write-better-in-neovim-with-languagetool-1b4l</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://languagetool.org/" rel="noopener noreferrer"&gt;LanguageTool&lt;/a&gt;&lt;/strong&gt; is a grammar tool and spell checker with an open-source core.&lt;/p&gt;

&lt;p&gt;I have used &lt;a href="https://www.grammarly.com/" rel="noopener noreferrer"&gt;grammarly&lt;/a&gt; for a while, but the browser extension was crap.&lt;br&gt;&lt;br&gt;
A colleague recommended LanguageTool (LT), and I’ve been a happy user of the browser extension ever since.&lt;/p&gt;

&lt;p&gt;LT has superior support for other languages than English. It also features decent suggestions for improving your grammar. The free tier of LT has been a better experience for me than grammarly.&lt;/p&gt;

&lt;p&gt;Did you know that you can use LT as a language server for NeoVim and other editors?&lt;/p&gt;

&lt;h2&gt;
  
  
  Install ltex-ls
&lt;/h2&gt;

&lt;p&gt;LT has no direct support for the &lt;a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer"&gt;language server protocol&lt;/a&gt;, but fear not – a clever programmer has included the LT server in his LSP implementation.&lt;/p&gt;

&lt;p&gt;The tool is called &lt;strong&gt;&lt;a href="https://valentjn.github.io/ltex/" rel="noopener noreferrer"&gt;ltex-ls&lt;/a&gt;&lt;/strong&gt;, and it’s free software.&lt;/p&gt;

&lt;p&gt;You can find the installation instructions on the &lt;a href="https://valentjn.github.io/ltex/ltex-ls/installation.html" rel="noopener noreferrer"&gt;ltex-ls website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For macOS, you can use &lt;a href="https://brew.sh" rel="noopener noreferrer"&gt;homebrew&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

brew &lt;span class="nb"&gt;install &lt;/span&gt;ltex-ls


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

&lt;/div&gt;

&lt;p&gt;The command installs the server as &lt;code&gt;ltex-ls&lt;/code&gt; in your standard homebrew location and thus adds it to your &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you manually install the program, make sure to add the binary to your &lt;code&gt;$PATH&lt;/code&gt;, for example with &lt;a href="https://fishshell.com/docs/current/cmds/fish_add_path.html" rel="noopener noreferrer"&gt;&lt;code&gt;fish_add_path&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration With nvim-lsp
&lt;/h2&gt;

&lt;p&gt;Check the &lt;a href="https://github.com/neovim/nvim-lspconfig#suggested-configuration" rel="noopener noreferrer"&gt;recommended configuration on the nvim-lsp GitHub&lt;/a&gt; and add the following configuration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;

&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'lspconfig'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;'ltex'&lt;/span&gt;&lt;span class="p"&gt;]({&lt;/span&gt;
 &lt;span class="n"&gt;on_attach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;on_attach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"ltex-ls"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="n"&gt;filetypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"markdown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"text"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;debounce_text_changes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;You should add the server command into the &lt;code&gt;cmd&lt;/code&gt; section. On macOS, &lt;code&gt;ltex-ls&lt;/code&gt; worked fine for me.&lt;/p&gt;

&lt;p&gt;Here you can see how the tool points out possible errors in my text:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.rockyourcode.com%2Flanguagetool-neovim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.rockyourcode.com%2Flanguagetool-neovim.png" alt="neovim languagetool example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Editors
&lt;/h2&gt;

&lt;p&gt;I originally found the instructions for using ltex-lsp on a blog about the &lt;a href="https://helix-editor.com" rel="noopener noreferrer"&gt;Helix Editor&lt;/a&gt;: &lt;a href="https://blog.getreu.net/20220828-tp-note-new8/" rel="noopener noreferrer"&gt;Note talking with Helix, Tp-Note and LanguageTool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the the content of &lt;code&gt;~/.config/helix/languages.toml&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[[language]]
file-types = ["md", "txt"]
indent = { tab-width = 2, unit = " " }
injection-regex = "md|markdown"
language-server = { command = "ltex-ls" }
name = "markdown"
roots = [".git"]
scope = "source.md"



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

&lt;/div&gt;

&lt;p&gt;If you use &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;, you can use the extension &lt;a href="https://github.com/valentjn/vscode-ltex" rel="noopener noreferrer"&gt;vscode-ltex&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://languagetool.org/" rel="noopener noreferrer"&gt;LanguageTool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://valentjn.github.io/ltex/" rel="noopener noreferrer"&gt;ltex-ls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.getreu.net/20220828-tp-note-new8/" rel="noopener noreferrer"&gt;Note talking with Helix, Tp-Note and LanguageTool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>helixeditor</category>
      <category>writing</category>
      <category>tooling</category>
      <category>helix</category>
    </item>
    <item>
      <title>Helix Editor – 90% of Neovim With Kakoune</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Wed, 26 Oct 2022 11:10:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/helix-editor-90-of-neovim-with-kakoune-4n9b</link>
      <guid>https://forem.com/sophiabrandt/helix-editor-90-of-neovim-with-kakoune-4n9b</guid>
      <description>&lt;p&gt;I’ve spend too many hours setting up the recent NeoVim features (since v0.5): &lt;a href="https://tree-sitter.github.io/tree-sitter/" rel="noopener noreferrer"&gt;tree-sitter&lt;/a&gt;, &lt;a href="https://github.com/neovim/nvim-lspconfig" rel="noopener noreferrer"&gt;nvim-lsp&lt;/a&gt;, &lt;a href="https://github.com/hrsh7th/nvim-cmp" rel="noopener noreferrer"&gt;nvim-cmp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;&lt;br&gt;
NeoVim’s parser tool &lt;a href="https://tree-sitter.github.io/tree-sitter/" rel="noopener noreferrer"&gt;tree-sitter&lt;/a&gt; offers a better integration of language servers, syntax highlighting and auto-completion.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Vim and NeoVim are great.&lt;br&gt;&lt;br&gt;
However, I put a lot of effort into customizing these editors to my liking, so that I could comfortably use them for coding.&lt;/p&gt;

&lt;p&gt;In fact, my &lt;a href="https://github.com/sophiabrandt/dotfiles/tree/main/vim" rel="noopener noreferrer"&gt;configuration&lt;/a&gt; has become more complicated over the years.&lt;/p&gt;

&lt;p&gt;Migrating my Vim configuration to take advantage of tree-sitter was an exercise in frustration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Better Than (Neo)Vim?
&lt;/h2&gt;

&lt;p&gt;By chance I stumbled upon a review of &lt;a href="https://matduggan.com/battle-of-the-text-editors/" rel="noopener noreferrer"&gt;Rust text editors&lt;/a&gt; on &lt;a href="https://lobste.rs" rel="noopener noreferrer"&gt;lobste.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The article favorably mentions &lt;strong&gt;&lt;a href="https://helix-editor.com/" rel="noopener noreferrer"&gt;Helix&lt;/a&gt;&lt;/strong&gt;, a modal text editor inspired by Vim and &lt;a href="http://kakoune.org/" rel="noopener noreferrer"&gt;Kakoune&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Other commentators also seemed taken with this new text editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fhelix-editor%2Fhelix%2Fraw%2Fmaster%2Fscreenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fhelix-editor%2Fhelix%2Fraw%2Fmaster%2Fscreenshot.png" alt="helix text editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I gave Helix a try and I am pleasantly surprised.&lt;/p&gt;

&lt;p&gt;Helix is a fully-fledged text editor that comes with wonderful capabilities out of the box.&lt;br&gt;&lt;br&gt;
For example, you get a fuzzy file finder, language server integration, a &lt;a href="https://github.com/tpope/vim-surround" rel="noopener noreferrer"&gt;vim-surround&lt;/a&gt;-like plugin and great editor themes for free.&lt;/p&gt;

&lt;p&gt;In the end, Helix offers almost everything I need from a terminal-based text editor &lt;em&gt;with zero config&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;After wasting hours of my free time on tweaking NeoVim, Helix’s sane defaults and inbuilt features blew me out of the water.&lt;/p&gt;
&lt;h2&gt;
  
  
  Kakoune – Why!?
&lt;/h2&gt;

&lt;p&gt;Helix has one advantage over Vim/NeoVim - multiple cursors. This features makes text editing a smoother experience.&lt;/p&gt;

&lt;p&gt;Multiple cursors come from &lt;a href="http://kakoune.org/" rel="noopener noreferrer"&gt;Kakoune&lt;/a&gt;, a text editor I never heard of.&lt;/p&gt;

&lt;p&gt;Vim’s core editing model revolves around &lt;em&gt;verbs&lt;/em&gt; and &lt;em&gt;(text) objects&lt;/em&gt;. For example, to delete a word, you type &lt;code&gt;dw&lt;/code&gt;, like in a natural language like English.&lt;/p&gt;

&lt;p&gt;Kakoune turns this model on its head: in Kakoune, you always select text objects first, then operate on them with words.&lt;/p&gt;

&lt;p&gt;Helix uses the same model as Kakoune.&lt;br&gt;&lt;br&gt;
The idea is that you always start by making a selection first (that way it’s interactive and you see that you selected the right thing), then you operate on it.&lt;/p&gt;

&lt;p&gt;I’m not sure if I can forego my muscle memory and retrain myself to use the “Kakoune” way. For me, it feels incredibly awkward.&lt;/p&gt;

&lt;p&gt;I am also missing some commands in normal mode.&lt;br&gt;&lt;br&gt;
For example, I can easily move or copy lines to other locations in the file &lt;a href="https://www.rockyourcode.com/til-about-copying-a-range-in-vim/" rel="noopener noreferrer"&gt;without having to make a selection and without leaving normal mode&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
This is a clash with Kakoune’s/Helix’s philosophy.&lt;/p&gt;

&lt;p&gt;What I am missing most is &lt;code&gt;ci&lt;/code&gt; (for &lt;code&gt;change inside&lt;/code&gt;).&lt;br&gt;&lt;br&gt;
I often use this command to change text in brackets (&lt;code&gt;ci{&lt;/code&gt;), single quotes (&lt;code&gt;ci'&lt;/code&gt;) or other text objects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Now What?
&lt;/h2&gt;

&lt;p&gt;Helix is in active development.&lt;br&gt;&lt;br&gt;
But even so, the editor is already usable. Because it is written in Rust, it’s fast and stable.&lt;/p&gt;

&lt;p&gt;The maintainers plan a &lt;a href="https://github.com/helix-editor/helix/issues/122" rel="noopener noreferrer"&gt;plugin system with WebAssembly&lt;/a&gt;, which would be a big milestone for the project.&lt;/p&gt;

&lt;p&gt;All in all, Helix looks like a valid alternative to Vim/NeoVim if you like modal editors.&lt;/p&gt;
&lt;h1&gt;
  
  
  My Configuration
&lt;/h1&gt;

&lt;p&gt;Here is my complete configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;theme = "nord"

[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "underline"

[editor.statusline]
left = ["mode", "diagnostics"]
center = ["file-name"]
right = ["selections", "file-type", "file-encoding", "position-percentage", "position"]

[keys.normal]
g = { a = "code_action", o = "goto_last_accessed_file" }
"ret" = ["move_line_down", "goto_first_nonwhitespace"] # Maps the enter key to move to start of next line
X = "extend_line_above"
D = "delete_char_backward"

[keys.insert]
C-space = "completion"
# Move cursor in insert mode
A-h = "move_char_left"
A-j = "move_line_down"
A-k = "move_line_up"
A-l = "move_char_right"
A-o = "open_below"
A-O = "open_above"

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

&lt;/div&gt;



&lt;p&gt;It adds a default theme, a few convenience key mappings plus some customisation around the status-line and the cursor.&lt;/p&gt;

&lt;p&gt;In comparison, here is &lt;a href="https://github.com/sophiabrandt/dotfiles/blob/main/vim/.vim/plugin/statusline.vim" rel="noopener noreferrer"&gt;my code for the status-line in Vim/NeoVim &lt;em&gt;alone&lt;/em&gt;&lt;/a&gt; – which is (more or less) a three-liner in Helix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://helix-editor.com/" rel="noopener noreferrer"&gt;Helix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kakoune.org/" rel="noopener noreferrer"&gt;Kakoune&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lobste.rs/s/xyexnb/reviewing_some_new_rust_text_editors" rel="noopener noreferrer"&gt;Reviewing some new Rust text editors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>neovim</category>
      <category>kakoune</category>
      <category>helixeditor</category>
      <category>helix</category>
    </item>
    <item>
      <title>My First T3 App</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Tue, 25 Oct 2022 20:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/my-first-t3-app-3kob</link>
      <guid>https://forem.com/sophiabrandt/my-first-t3-app-3kob</guid>
      <description>&lt;p&gt;&lt;a href="https://trpc.io"&gt;tRPC&lt;/a&gt; is the hottest new thing in the TypeScript ecosystem: build end-to-end &lt;strong&gt;type-safe&lt;/strong&gt; APIs without the overhead of GraphQL.&lt;/p&gt;

&lt;p&gt;tRPC is a protocol to expose a function of your backend to your frontend using TypeScript type definitions.&lt;br&gt;&lt;br&gt;
No code generation required. You write both your backend and your frontend with TypeScript and share the types.&lt;/p&gt;

&lt;p&gt;tRPC is framework-agnostic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://create.t3.gg/"&gt;Create-t3-app&lt;/a&gt; is build on top of tRPC. It offers an opinionated starter template that helps with building a complete web application with &lt;a href="https://nextjs.org"&gt;Next.js&lt;/a&gt; and Prisma.&lt;/p&gt;

&lt;p&gt;This blog post chronicles my journey in creating my first T3 app. Let's see how the T3 stack works!&lt;/p&gt;
&lt;h2&gt;
  
  
  Create Application
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dlx create-t3-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The command guides you through the installation process and allows you to choose a few options (trpc, prisma, next-auth, tailwind).&lt;/p&gt;

&lt;p&gt;I am happy to see that the command also works with &lt;a href="https://pnpm.io"&gt;pnpm&lt;/a&gt; out of the box.&lt;/p&gt;

&lt;p&gt;The command bootstraps the application. At the end of the process, there is a hint on what commands to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-t3-app
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm prisma db push
pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project also offers a &lt;code&gt;README&lt;/code&gt; file with minimal information to get you started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prisma
&lt;/h2&gt;

&lt;p&gt;My application should show cat pictures because the internet loves cats.&lt;/p&gt;

&lt;p&gt;Let's adjust the Prisma schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;generator client {
&lt;/span&gt;  provider = "prisma-client-js"
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;datasource db {
&lt;/span&gt;  provider = "sqlite"
  url      = env("DATABASE_URL")
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="gi"&gt;+model Cat {
+  id        String   @id @default(cuid())
+  createdAt DateTime @default(now())
+  updatedAt DateTime @updatedAt
+  imageUrl  String
+}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks like a minimal example for a first application. Run &lt;code&gt;pnpm exec prisma migrate dev --name add_cat_model&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  tRPC Router
&lt;/h2&gt;

&lt;p&gt;My next instinct is to hook up the trpc router. The project comes with an example router in &lt;code&gt;src/server/router/example.ts&lt;/code&gt;. I'll adjust that to be a cat router.&lt;/p&gt;

&lt;p&gt;The router uses &lt;a href="https://github.com/colinhacks/zod"&gt;zod&lt;/a&gt;, a schema-validation library, to build a router.&lt;/p&gt;

&lt;p&gt;The example query has an input parameter of the String type.&lt;br&gt;&lt;br&gt;
For my case, I want a random cat picture, so no input is needed. Can I just delete the input parameter and return a random cat?&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exampleRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;nullish&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nullish&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getAll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;random&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomCats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$queryRaw&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`SELECT id, imageUrl
                                                           FROM Cat
                                                           ORDER BY RANDOM()
                                                           LIMIT 1`&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;randomCats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getAll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use a &lt;a href="https://www.prisma.io/docs/concepts/components/prisma-client/raw-database-access"&gt;raw SQL query&lt;/a&gt; to retrieve a random cat from the database and add a typing for &lt;code&gt;Cat[]&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
That's not pretty and does not give me the advantage of using the schema validator, but Prisma doesn't implement &lt;a href="https://github.com/prisma/prisma/issues/5894"&gt;getting a random record&lt;/a&gt;. So raw SQL it is!&lt;/p&gt;

&lt;p&gt;The raw query returns an array in any case, so we select the first element and return it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Seed Script
&lt;/h2&gt;

&lt;p&gt;Before I try to hook up the frontend, I remember that I don't have any example data in my database.&lt;/p&gt;

&lt;p&gt;Luckily, the Prisma documentation can &lt;a href="https://www.prisma.io/docs/guides/database/seed-database"&gt;help me&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Add a new entry to &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prisma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"seed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node --compiler-options {&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;CommonJS&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;} prisma/seed.ts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new seed script in the &lt;code&gt;prisma&lt;/code&gt; folder (&lt;code&gt;prisma/seed.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/dist/compiled/@edge-runtime/primitives/fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://aws.random.cat/meow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// map array of responses into an array of response.json() to read their content&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
    &lt;span class="c1"&gt;// insert all responses as imageUrl&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I fetch ten image URLs from an API that offers random cat images and insert them into the database. Quite ugly, but it works.&lt;/p&gt;

&lt;p&gt;In my terminal, I run type the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;prisma db seed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hook Up the Client
&lt;/h2&gt;

&lt;p&gt;Finally, we can try to show this data on the browser.&lt;/p&gt;

&lt;p&gt;After ripping out the example router and replacing it with my cat router, I check &lt;code&gt;src/pages/index.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It has some boilerplate which I adjust to my needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;trpc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/trpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;trpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cat.random&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;placeItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;T3 Cats&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"T3 cats"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Generated by create-t3-app"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Create &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;T3&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; App
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
                &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`random cat &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fixed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was surprisingly easy, especially if you are familiar with Prisma.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Impressions
&lt;/h2&gt;

&lt;p&gt;The starter template does a good job on guiding you through the process.&lt;/p&gt;

&lt;p&gt;The examples are enough to paint a broad picture on how trpc with Next.js works. Familiarity with prisma is assumed.&lt;/p&gt;

&lt;p&gt;You might need to consult the Prisma documentation, trpc is almost self-declaratory, Prisma is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://trpc.io"&gt;tRPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://create.t3.gg/"&gt;Create T3 App&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>trpc</category>
      <category>typescript</category>
      <category>t3stack</category>
      <category>learninginpublic</category>
    </item>
    <item>
      <title>Setting Up a Modern Preact Application With Typescript, Vite and Vitest</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Sun, 16 Oct 2022 12:50:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/setting-up-a-modern-preact-application-with-typescript-vite-and-vitest-10m0</link>
      <guid>https://forem.com/sophiabrandt/setting-up-a-modern-preact-application-with-typescript-vite-and-vitest-10m0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Wiring up a TypeScript environment with Preact, Vite and Vitest and vitest-dom&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have heard good things about Vite and Vitest. When I gave them a test-drive, I stumbled over some minor annoyances in getting the whole suite running.&lt;/p&gt;

&lt;p&gt;I'm writing down the steps I took, maybe they help you.&lt;/p&gt;

&lt;p&gt;The article is basically a re-write of &lt;a href="https://miyauchi.dev/posts/vite-preact-typescript/"&gt;a blog post by Tomoki Miyaci&lt;/a&gt; adjusted to my needs.&lt;/p&gt;

&lt;p&gt;Tooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;Vitest (with vitest-dom)&lt;/li&gt;
&lt;li&gt;Preact&lt;/li&gt;
&lt;li&gt;Prettier&lt;/li&gt;
&lt;li&gt;ESLint&lt;/li&gt;
&lt;li&gt;husky &amp;amp; lint-staged&lt;/li&gt;
&lt;li&gt;commitlint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All my commands use &lt;a href="https://pnpm.io"&gt;pnpm&lt;/a&gt;, feel free to replace them with npm or yarn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vite
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create vite &amp;lt;project-name&amp;gt; &lt;span class="nt"&gt;--template&lt;/span&gt; preact-ts
&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;project-name&amp;gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ESLint &amp;amp; prettier
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm i &lt;span class="nt"&gt;-D&lt;/span&gt; eslint eslint-config-prettier &lt;span class="se"&gt;\&lt;/span&gt;
          prettier &lt;span class="se"&gt;\&lt;/span&gt;
          @typescript-eslint/parser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file called &lt;code&gt;.eslintrc&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"browser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"es2021"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"eslint:recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"preact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@typescript-eslint/parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parserOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ecmaFeatures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"jsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ecmaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ignorePatterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"*.d.ts"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One wrinkle was the Jest settings option. I know I wanted to use Vite, but eslint needs to know the Jest version for some of its tests.&lt;/p&gt;

&lt;p&gt;Here is my Prettier configuration (&lt;code&gt;.prettierrc&lt;/code&gt;), adjust to your needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trailingComma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"semi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"singleQuote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's adjust &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint:fix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint --fix --ext .ts,tsx --ignore-path .gitignore ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prettier:write"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier -u -w --ignore-path .gitignore &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;*.{ts,tsx,css,html}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  husky &amp;amp; lint-staged
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://www.npmjs.com/package/lint-staged"&gt;lint-staged&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; lint-staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;.lintstagedrc.json&lt;/code&gt; file in your project root folder.&lt;br&gt;&lt;br&gt;
Here you can add the commands that lint-staged should run on staging your files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"*.{ts,tsx}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"pnpm run lint:fix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pnpm run prettier:write"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"*.{html,css,js,json,md}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pnpm run prettier:write"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We run ESLint and prettier on TypeScript files in sequential order. For other files, prettier suffices.&lt;/p&gt;

&lt;p&gt;Now we need &lt;a href="https://typicode.github.io/husky/#/"&gt;husky&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We initialize it with a script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dlx husky-init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will setup the tool and create the necessary files and hooks.&lt;/p&gt;

&lt;p&gt;The default hook runs before committing the files to the staging area.&lt;br&gt;&lt;br&gt;
You can find it under &lt;code&gt;.husky/pre-commit&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;lint-staged
&lt;span class="c"&gt;## if you want to run your tests before commiting,&lt;/span&gt;
&lt;span class="c"&gt;## uncomment next line&lt;/span&gt;
&lt;span class="c"&gt;# pnpm exec vitest run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  commitlint
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;commitlint checks if your commit messages meet the &lt;a href="https://conventionalcommits.org/"&gt;conventional commit&lt;/a&gt; format.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;chore: run tests on travis ci&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I personally find it quite useful to enforce a uniform commit style.&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/conventional-changelog/commitlint/"&gt;commitlint&lt;/a&gt; pairs well with husky.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; @commitlint/&lt;span class="o"&gt;{&lt;/span&gt;config-conventional,cli&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add a configuration file (&lt;code&gt;.commitlintrc.json&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"extends"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@commitlint/config-conventional"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need a hook for husky. Run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dlx husky add &lt;span class="se"&gt;\&lt;/span&gt;
  .husky/commit-msg &lt;span class="s1"&gt;'pnpm exec commitlint --edit'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Vitest
&lt;/h2&gt;

&lt;p&gt;Installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; vitest vitest-dom happy-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/chaance/vitest-dom"&gt;vitest-dom&lt;/a&gt; extends the standard Jest matchers with convenient methods like &lt;code&gt;.toBeDisabled&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Now you can write tests that assert on the state of the DOM.&lt;br&gt;&lt;br&gt;
The package is a fork of &lt;a href="https://github.com/testing-library/jest-dom"&gt;@testing-library/jest-dom&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Configuring vitest with the &lt;code&gt;.vite.config.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;reference types="vitest" /&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fileURLToPath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;preact&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@preact/preset-vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// https://vitejs.dev/config/&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;define&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;import.meta.vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;preact&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;happy-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setupFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./__test__/test-setup.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;includeSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.{ts,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;mockReset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;restoreMocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code section &lt;code&gt;import.meta.vitest&lt;/code&gt; allows you to &lt;a href="https://vitest.dev/guide/in-source.html"&gt;run tests within your source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For my test setup I've made a separate &lt;code&gt;__test__&lt;/code&gt; folder with a file called &lt;code&gt;test-setup.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest-dom/extend-expect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;domMatchers&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest-dom/matchers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domMatchers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I add the &lt;code&gt;vitest-dom&lt;/code&gt; extra matchers. You can add more setup logic if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://miyauchi.dev/posts/vite-preact-typescript/"&gt;Building a Typescript Environment for Preact with Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laurieontech.com/posts/husky/"&gt;Diving Into Husky and lint-staged&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>preact</category>
      <category>typescript</category>
      <category>vite</category>
      <category>vitest</category>
    </item>
    <item>
      <title>Notes on ”The Counterintuitive Secret to Shipping Better Articles Faster”</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Tue, 22 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/notes-on-the-counterintuitive-secret-to-shipping-better-articles-faster-1d3j</link>
      <guid>https://forem.com/sophiabrandt/notes-on-the-counterintuitive-secret-to-shipping-better-articles-faster-1d3j</guid>
      <description>&lt;p&gt;In this ~1 hour video developer advocate &lt;a href="https://samjulien.com"&gt;Sam Julien&lt;/a&gt; shares his tips for shipping faster:&lt;a href="https://youtube.com/watch?v=DIG8GGg-PXw"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W9IBhHT8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.ytimg.com/vi/DIG8GGg-PXw/0.jpg" alt="The Counterintuitive Secret to Shipping Better Articles Faster - Sam Julien at Hashnode Bootcamp III"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;p&gt;You’ll need a &lt;em&gt;system&lt;/em&gt; that enables you to &lt;em&gt;consistently&lt;/em&gt; produce results on which you can get feedback on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Action + Speed + Feedback = Growth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to Create Consistently?
&lt;/h2&gt;

&lt;p&gt;The problem:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The “Ultimate Guide” Trap&lt;/strong&gt; : Trying to write a big, all-encompassing article leads to exhaustion and &lt;em&gt;burn-out&lt;/em&gt;. You stop writing for months.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Developer Content Creator Cycle
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Overwhelming to know what to create&lt;/li&gt;
&lt;li&gt;Difficult to cross things off the list (unfinished drafts)&lt;/li&gt;
&lt;li&gt;Never-ending cycle&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Explorer’s Mindset
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t think of content (or any other skill you’re building) as a dictionary to memorize.&lt;br&gt;&lt;br&gt;
Instead: think like an explorer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The secret lies in &lt;strong&gt;Consistent Small Wins&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Comfort is the enemy of growth.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(But self-care, too!)&lt;/p&gt;

&lt;p&gt;Sam does not encourage the “hustle mindset”.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Grow
&lt;/h2&gt;

&lt;p&gt;Do &lt;em&gt;challenging&lt;/em&gt; things &lt;em&gt;quickly&lt;/em&gt; and &lt;em&gt;get feedback&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;production-focused (article, video)&lt;/li&gt;
&lt;li&gt;trackable&lt;/li&gt;
&lt;li&gt;measurable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;does it work?&lt;/li&gt;
&lt;li&gt;learning in groups&lt;/li&gt;
&lt;li&gt;learning in public&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building a Content System
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Systems trump Motivation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build a small but complete system.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Draft
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;gathering notes&lt;/li&gt;
&lt;li&gt;creating an outline&lt;/li&gt;
&lt;li&gt;first draft&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Create
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;writing/recording&lt;/li&gt;
&lt;li&gt;adding images&lt;/li&gt;
&lt;li&gt;code samples&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Publish
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;publish on your site&lt;/li&gt;
&lt;li&gt;adding social images&lt;/li&gt;
&lt;li&gt;cross-posting&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Promote
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Twitter threads&lt;/li&gt;
&lt;li&gt;forums &amp;amp; chat groups&lt;/li&gt;
&lt;li&gt;talks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Garden
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update over time&lt;/li&gt;
&lt;li&gt;maintain &amp;amp; correct&lt;/li&gt;
&lt;li&gt;cross-link&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creation Phase (Step 1 to 3)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Tools
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Scratch pad
&lt;/h5&gt;

&lt;p&gt;Eliminate the distraction of figuring out where to jot something down.&lt;/p&gt;

&lt;p&gt;Look for: speed, ease of use, ability to export.&lt;/p&gt;

&lt;p&gt;Google Keep, Drafts app, etc.&lt;/p&gt;

&lt;h5&gt;
  
  
  Knowledge Base
&lt;/h5&gt;

&lt;p&gt;Slow burn your drafts and link your ideas together.&lt;/p&gt;

&lt;p&gt;Look for: cross-linking, collections, multimedia.&lt;/p&gt;

&lt;p&gt;Evernote, Obsidian, Roam, Notion.so, etc.&lt;/p&gt;

&lt;h5&gt;
  
  
  Task Manager
&lt;/h5&gt;

&lt;p&gt;Ship things faster by determining the next action and context for a project.&lt;/p&gt;

&lt;p&gt;Look for: works with your brain, ability to add context/tags&lt;/p&gt;

&lt;p&gt;OmniFocus, Google Keep, etc.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tips for Creating Content
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;In the beginning, move fast to define your process (do tiny expirements).&lt;/li&gt;
&lt;li&gt;Start with what you know.&lt;/li&gt;
&lt;li&gt;Stuck? Try the TIL format.&lt;/li&gt;
&lt;li&gt;Don’t over-engineer too quickly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  TIL Format
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Intro: 2 or 3 sentences describing the problem.&lt;/li&gt;
&lt;li&gt;Body: describe the solution and how you got there.&lt;/li&gt;
&lt;li&gt;Final Solution: Finished code for copy&amp;amp;paste.&lt;/li&gt;
&lt;li&gt;Conclusion: 1 or 2 sentences re-capping the problem and solution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Post-Publication Phase (Step 3 to 5)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Every piece of content has a price tag (promotion &amp;amp; maintenance).&lt;/li&gt;
&lt;li&gt;Provide direct value on each platform (don’t dump your stuff).&lt;/li&gt;
&lt;li&gt;Be patient.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=DIG8GGg-PXw"&gt;The Counterintuitive Secret to Shipping Better Articles Faster - Sam Julien at Hashnode Bootcamp III&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.samjulien.com/ship-better-articles-faster-talk"&gt;Talk Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;image credit for the cover image: &lt;a href="https://unsplash.com/photos/CpsTAUPoScw"&gt;Andy Li&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>writing</category>
    </item>
    <item>
      <title>Notes on “How to Write Online Workshop” by David Perell</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Mon, 21 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/notes-on-how-to-write-online-workshop-by-david-perell-4acp</link>
      <guid>https://forem.com/sophiabrandt/notes-on-how-to-write-online-workshop-by-david-perell-4acp</guid>
      <description>&lt;p&gt;In &lt;a href="https://www.youtube.com/watch?v=1MNS21b6O_s"&gt;this ~1 hour video&lt;/a&gt; David Perell explains his method for writing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/watch?v=1MNS21b6O_s"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h8ZSj8AE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.ytimg.com/vi/1MNS21b6O_s/sddefault.jpg" alt="How to Write Online Workshop"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Capture Habit
&lt;/h2&gt;

&lt;p&gt;You need a &lt;strong&gt;note-taking system&lt;/strong&gt; for generating better ideas.&lt;/p&gt;

&lt;p&gt;What ideas should you save?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PILE&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;personal&lt;/li&gt;
&lt;li&gt;inspiring&lt;/li&gt;
&lt;li&gt;easily lost (losable)&lt;/li&gt;
&lt;li&gt;effective (useful)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sources: ebooks, online articles – use a service like &lt;a href="https://readwise.io/"&gt;readwise&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Capture your ideas while you read.&lt;/p&gt;

&lt;p&gt;Capture things while they are fresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Modern writing isn’t &lt;strong&gt;created&lt;/strong&gt;. It’s &lt;strong&gt;assembled&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You have to cull your writing from vast amounts of notes.&lt;/p&gt;

&lt;p&gt;Writing can be a collaborate progress. Ask for feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Content Triangle
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_u2aw6ue--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0cumi15b6y5d6dp7fvk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_u2aw6ue--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0cumi15b6y5d6dp7fvk1.png" alt="content triangle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;image from &lt;a href="https://www.notion.so/David-Perell-How-to-Write-Online-Workshop-Notes-by-bronsonchang-6cfaff84afd84b6592db2eb4461b3e40#06b051b6395e450fbe49bce53dd2fb9c"&gt;Bronson Chang's notes&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;conversations -&amp;gt; share -&amp;gt; feedback -&amp;gt; create content -&amp;gt; distribute&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2-minute-drill&lt;/strong&gt; : &lt;em&gt;explain&lt;/em&gt; your idea in 2 minutes or less by &lt;em&gt;talking&lt;/em&gt;. Humans are better at talking than reading. After that, you can distill the audio to write your article.&lt;/p&gt;

&lt;p&gt;You don’t need to be 100% original.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve Your Writing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CLEAR&lt;/strong&gt; sentences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a rhythm&lt;/li&gt;
&lt;li&gt;Link your sentences&lt;/li&gt;
&lt;li&gt;Eliminate anything that’s confusing&lt;/li&gt;
&lt;li&gt;Add colorful details&lt;/li&gt;
&lt;li&gt;Remove unnecessary words&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t just write &lt;strong&gt;words&lt;/strong&gt;. Write &lt;strong&gt;music&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sweet spot: words people know, but don’t say.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zJBbnSi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2bam3dyga1bku20j1uc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zJBbnSi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2bam3dyga1bku20j1uc.png" alt="words to use"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;image from &lt;a href="https://www.notion.so/David-Perell-How-to-Write-Online-Workshop-Notes-by-bronsonchang-6cfaff84afd84b6592db2eb4461b3e40#06b051b6395e450fbe49bce53dd2fb9c"&gt;Bronson Chang's notes&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Telling a Story
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Roller-Coaster&lt;/strong&gt; : start with a setup (tension rises), conflict, resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sWzTC5gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ab1tg6reohg8j9lelyk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sWzTC5gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ab1tg6reohg8j9lelyk7.png" alt="story roller coaster"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;image from &lt;a href="https://www.notion.so/David-Perell-How-to-Write-Online-Workshop-Notes-by-bronsonchang-6cfaff84afd84b6592db2eb4461b3e40#06b051b6395e450fbe49bce53dd2fb9c"&gt;Bronson Chang's notes&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn to Write FAST
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FAST&lt;/strong&gt; Writing: write first, research second. Write in the course of your life.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find&lt;/li&gt;
&lt;li&gt;Assemble&lt;/li&gt;
&lt;li&gt;Speak&lt;/li&gt;
&lt;li&gt;Teach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use your note-taking system, structure ideas by talking, record yourself, set a timer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audience
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Grow your audience on public platforms. Build relationships on private ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Create value on public platforms.&lt;/li&gt;
&lt;li&gt;Send audience to private platforms.&lt;/li&gt;
&lt;li&gt;store value with your email list.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Build a Personal Monopoly
&lt;/h2&gt;

&lt;p&gt;Define your personal monopoly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;specific (the more narrow the niche, the better)&lt;/li&gt;
&lt;li&gt;unusual (skills or knowledge not often found together)&lt;/li&gt;
&lt;li&gt;complementary (skills that reinforce and amplify each other)&lt;/li&gt;
&lt;li&gt;experimental (skills gained through experience).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aim for &lt;strong&gt;niche fame&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get going. Then get good.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Writing and Thinking
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;When writing is thinking, re-writing is re-thinking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you put words on paper, you free up you mind which allows you to see things that you didn’t realize before.&lt;/p&gt;

&lt;p&gt;When you write, you give yourself opportunity to go over ideas over and over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imposter Syndrome
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/1MNS21b6O_s?t=4089"&gt;You are an imposter&lt;/a&gt;, because you are trying to do things out of your comfort zone.&lt;/p&gt;

&lt;p&gt;But &lt;em&gt;everyone is an imposter&lt;/em&gt;. David Perell didn’t know how to run a writing school before he tried. Jeff Bezos didn’t know how to run a trillion-dollar business like Amazon.&lt;/p&gt;

&lt;p&gt;When you realize that everybody is an imposter, you realize that nobody is an imposter.&lt;/p&gt;

&lt;p&gt;You have an obligation to share your ideas. This is how our society advances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=1MNS21b6O_s"&gt;How to Write Online Workshop (David Perell)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.notion.so/David-Perell-How-to-Write-Online-Workshop-Notes-by-bronsonchang-6cfaff84afd84b6592db2eb4461b3e40"&gt;Notes on the talk by Bronson Chang&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>writing</category>
    </item>
    <item>
      <title>Notes on ”How to Build a Career in Tech”</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Sat, 19 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/notes-on-how-to-build-a-career-in-tech-12k3</link>
      <guid>https://forem.com/sophiabrandt/notes-on-how-to-build-a-career-in-tech-12k3</guid>
      <description>&lt;p&gt;Kurt Kemple is a self-taught programmer who learned to code when incarcerated. In his &lt;a href="https://www.youtube.com/watch?v=4fq8QlpEMec" rel="noopener noreferrer"&gt;talk with Jason Lengstorf&lt;/a&gt; he shares his experiences.&lt;/p&gt;

&lt;p&gt;Here are my notes from the ~1 hour &lt;a href="https://www.youtube.com/watch?v=4fq8QlpEMec" rel="noopener noreferrer"&gt;video&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtube.com/watch?v=4fq8QlpEMec" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ytimg.com%2Fvi%2F4fq8QlpEMec%2Fsddefault.jpg" alt="How to Build a Career in Tech: Kurt Kemple Connects the Dots"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Technical skills are &lt;strong&gt;a small part of your day to day job&lt;/strong&gt;. Kurt learned how to &lt;em&gt;prioritize, commmunicate with others&lt;/em&gt; and how to &lt;em&gt;organize the work&lt;/em&gt; from his previous experience in construction work and as a line cook. &lt;em&gt;Break a big task into small pieces.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Empathy and understanding&lt;/strong&gt; : “Your perspective of the world is not the center of everything, it’s not the default. Lots of people have experiences that are different from yours.”&lt;/p&gt;

&lt;p&gt;Know the stakeholders. Understand what they are invested in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to learn?&lt;/strong&gt; Kurt learns best by doing. He breaks new skills into manageable chunks, and practices them step by step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to break into tech&lt;/strong&gt; : Until you have your first role, you need &lt;em&gt;something&lt;/em&gt; for your resume — either certificates or a great portfolio. You also want to &lt;em&gt;highlight&lt;/em&gt; the skills you want to get hired for.&lt;/p&gt;

&lt;p&gt;One of the best ways to break into tech is to &lt;strong&gt;build a community&lt;/strong&gt;. Learn in public.&lt;br&gt;&lt;br&gt;
Often, job opportunities come from your network.&lt;/p&gt;

&lt;p&gt;Resume tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/4fq8QlpEMec?t=1494" rel="noopener noreferrer"&gt;two column layout (1 page)&lt;/a&gt;: on the top left the most important info, below that the most important experience (certificate, a project), on the right side put the second most important info&lt;/li&gt;
&lt;li&gt;make different resumes for different jobs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Remote work&lt;/strong&gt; : traditionally, the advice for junior developers was to aim for an on-site job, but that’s not possible due to the pandemic.&lt;br&gt;&lt;br&gt;
Ideally, your future company either has a track record for remote work or already on-boarded junior developers.&lt;/p&gt;

&lt;p&gt;Find the people in your job that are happy to answer your questions, and ask them — a lot. Communicate early, communicate often. Optimize for feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Focus on the &lt;em&gt;whys&lt;/em&gt;, not &lt;em&gt;hows&lt;/em&gt;.&lt;/strong&gt; Everyone can pick up the newest and hottest tech stack and learn how to use it. Rather aim to understand why to use a technology.&lt;/p&gt;

&lt;p&gt;Jason Lengstorf, the interviewer, also explains that he doesn’t expect juniors to know a lot, but he wants to get the sense that the junior can find out (“self-starter”). Be confident in yourself, be confident in your ability to learn and grow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be aware of burnout.&lt;/strong&gt; Don’t start a new job and deliver 110%. This becomes your baseline, and soon you’ll be expected to clock in 130%.&lt;br&gt;&lt;br&gt;
If possible, dedicate 70-80% to productivity on the job, and around 20-30% to learning and growing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you learn to program when you don’t know enough about computers?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Try to get a basic understanding of how computers and the internet work, how to use the keyboard effectively. If you don’t know anything about computers, you’re trying to learn two things at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=4fq8QlpEMec" rel="noopener noreferrer"&gt;How to Build a Career in Tech: Kurt Kemple Connects the Dots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>codenewbie</category>
      <category>firstyearincode</category>
    </item>
    <item>
      <title>Notes on ”Advice for Your First Dev Role”</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Mon, 14 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/notes-on-advice-for-your-first-dev-role-41l2</link>
      <guid>https://forem.com/sophiabrandt/notes-on-advice-for-your-first-dev-role-41l2</guid>
      <description>&lt;p&gt;&lt;a href="https://virtualcoffee.io/"&gt;Virtual Coffee&lt;/a&gt; is a remote community for developers that aim to support each other.&lt;br&gt;&lt;br&gt;
They offer "brown bags" which are talks and discussions about a specific topic.&lt;/p&gt;

&lt;p&gt;Here are my notes from &lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=cwTFHDgDDeY"&gt;Advice for your first dev role&lt;/a&gt;&lt;/strong&gt; by Bryan Healey:&lt;/p&gt;

&lt;p&gt;Remember that there will be a &lt;strong&gt;ramp-up period&lt;/strong&gt;. You should take the time to talk to other engineers in your team.&lt;br&gt;&lt;br&gt;
Learn about the tooling stack as soon as possible.&lt;br&gt;&lt;br&gt;
Talk to your manager regularly.&lt;/p&gt;

&lt;p&gt;Keep in mind what you want to achieve in a year, 5 years, etc. Be proactive. Don't wait for tasks to come to you — &lt;em&gt;gradually&lt;/em&gt; ask for more complex tasks. Take ownership.&lt;/p&gt;

&lt;p&gt;Many juniors try to jump in and contribute at scale. That hinders them from seeking help, and &lt;strong&gt;opening a dialog&lt;/strong&gt;. Having a "set of fresh eyes" is valuable for a company.&lt;/p&gt;

&lt;p&gt;Bryan looks for &lt;strong&gt;continuous contributions on an escalating scale&lt;/strong&gt;. He doesn't expect a junior to contribute major features right away.  &lt;/p&gt;

&lt;p&gt;Good engineers should be &lt;strong&gt;comfortable with asking questions&lt;/strong&gt; as its part of the process.&lt;br&gt;&lt;br&gt;
A functional team will collaborate and discuss, so your questions should be welcomed, too.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When&lt;/em&gt; should you ask questions? As a beginner, don't spend too much time on trouble-shooting. Nobody gains much when you try to solve a problem yourself that could be solved faster by asking for help.&lt;br&gt;&lt;br&gt;
Rule of thumb: don't spend more than 30 minutes banging your head against the wall.&lt;/p&gt;

&lt;p&gt;When you start a new job, there is a "grace period" where everyone expects you to ask questions. Build trust by doing your due diligence (take notes, learn, listen for feedback, etc.).&lt;/p&gt;

&lt;p&gt;Also remember that seniors developers can learn from &lt;em&gt;you&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Bryan hires junior developers for their personality, creativity, problem-solving, not for their technical skills. He looks for people that can push the team. He doesn't care about failure, not delivering things.&lt;br&gt;&lt;br&gt;
Don't be quiet, be part of the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=cwTFHDgDDeY"&gt;Advice for your first dev role – Bryan Healey – Virtual Coffee Brownbag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.healeyengineering.com/consultants/Bryan-Healey"&gt;Bryan Healey's website&lt;/a&gt; and &lt;a href="https://twitter.com/Bryan_Healey"&gt;Twitter account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://virtualcoffee.io/"&gt;Virtual Coffee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;image credit: &lt;a href="https://unsplash.com/photos/SYTO3xs06fU"&gt;Marvin Meyer&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>codenewbie</category>
      <category>firstyearincode</category>
    </item>
    <item>
      <title>Notes on “How to Become a Better Developer With Nacho Iacovino“</title>
      <dc:creator>Sophia Brandt</dc:creator>
      <pubDate>Sun, 13 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/sophiabrandt/notes-on-how-to-become-a-better-developer-with-nacho-iacovino-2bmi</link>
      <guid>https://forem.com/sophiabrandt/notes-on-how-to-become-a-better-developer-with-nacho-iacovino-2bmi</guid>
      <description>&lt;p&gt;Notes from the Twitch stream with Francesco Ciulla and Nacho Iacovino (1 hour 17 mins):&lt;br&gt;
&lt;a href="https://youtube.com/watch?v=AbdcoJHVutk"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vqZkgr3T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.ytimg.com/vi/AbdcoJHVutk/sddefault.jpg" alt="How to become a better Developer | with Nacho Iacovino"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nacho Iacovino is a self-taught developer from Spain who grew his Twitter account in a short time.&lt;/p&gt;

&lt;p&gt;Here are some tips that he shared.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coding interviews&lt;/strong&gt;: He learned from each interview. Even if you can't answer a question, you can go home, research, and then you can answer the question on the next interview. It's a process.&lt;br&gt;&lt;br&gt;
You also need to interview the company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketing/Followers&lt;/strong&gt;: Nacho made some useful Twitter threads and pinged the influential Twitter accounts for feedback (no spam, no selling, add value), hit a niche (Tailwind CSS).&lt;br&gt;&lt;br&gt;
&lt;em&gt;Engage with bigger account.&lt;/em&gt; Add value to other people's tweets. Use common sense.&lt;br&gt;&lt;br&gt;
Choose one platform and be consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Becoming a better developer&lt;/strong&gt;: He quit JavaScript twice before he managed to become a developer full-time. &lt;em&gt;Be consistent.&lt;/em&gt; You might not have 6 hours a day to learn to code, but at least do a little bit every day.&lt;br&gt;&lt;br&gt;
Find the best way that works for you (video, tutorials, books).&lt;br&gt;&lt;br&gt;
Don't copy a tutorial verbatim, try to experiment, embrace breaking the application and find out how to fix it. Challenge yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Portfolio&lt;/strong&gt;: Show what you're capable of. Udemy project clones are dimes and dozens, make it your own. Make it easy for others to contact you.&lt;br&gt;&lt;br&gt;
Show the newest work first. Be concise. Say where you're based, so it's easy to see if the company can hire you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn in Public&lt;/strong&gt;: Nacho shared what he learned publicly on Twitter. People were reaching out to him, because they knew what he learned.&lt;br&gt;&lt;br&gt;
Be your own teacher. What you write down you can use later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtube.com/watch?v=AbdcoJHVutk"&gt;How to become a better Developer | with Nacho Iacovino&lt;/a&gt; on
Francesco Ciulla's &lt;a href="https://www.youtube.com/channel/UCBRxDSTfr2aJVODDh4WG_7g"&gt;YouTube channel&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>codenewbie</category>
    </item>
  </channel>
</rss>
