<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>ramigs.dev</title><description>Frontend engineering, AI-assisted development, and the tools I use day to day — from quick TILs to longer deep dives.</description><link>https://ramigs.dev/</link><item><title>How to setup Python for local development on macOS</title><link>https://ramigs.dev/blog/how-to-setup-python-for-local-development-on-macos/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-setup-python-for-local-development-on-macos/</guid><description>Setting up a clean Python dev environment on macOS with uv and VSCode, for anyone coming from Node.js tooling.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’re coming from a Node.js background, Python’s tooling has historically felt scattered, &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;venv&lt;/code&gt;, &lt;code&gt;pyenv&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;, each solving one piece of the puzzle. In 2026, that’s consolidated around &lt;code&gt;uv&lt;/code&gt;, a single Rust-based tool from Astral that replaces most of the old stack. This post walks through setting up a clean Python dev environment on macOS with &lt;code&gt;uv&lt;/code&gt; + VSCode.&lt;/p&gt;
&lt;h2 id=&quot;why-uv&quot;&gt;Why uv?&lt;/h2&gt;
&lt;p&gt;If you know Node, here’s the rough mapping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pyenv&lt;/code&gt; ≈ &lt;code&gt;nvm&lt;/code&gt; (Python version management)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;venv&lt;/code&gt; ≈ &lt;code&gt;node_modules&lt;/code&gt; (per-project dependency isolation)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip&lt;/code&gt; ≈ &lt;code&gt;npm&lt;/code&gt; (package installer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; consolidates all three into one fast binary, closer to how &lt;code&gt;npm&lt;/code&gt; just handles everything without you thinking about it. It auto-detects the Python version per project and manages the virtual environment for you, so you never have to activate anything manually.&lt;/p&gt;
&lt;h2 id=&quot;1-install-uv&quot;&gt;1. Install uv&lt;/h2&gt;
&lt;p&gt;Via Homebrew:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;uv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;brew install uv&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Or via the official install script:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-LsSf&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;https://astral.sh/uv/install.sh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -LsSf https://astral.sh/uv/install.sh | sh&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Verify it worked:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--version&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;uv --version&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;2-create-a-new-project&quot;&gt;2. Create a new project&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; can scaffold the folder for you:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;uv init my-projectcd my-project&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This generates &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;.python-version&lt;/code&gt;, a &lt;code&gt;src/&lt;/code&gt; layout, &lt;code&gt;.gitignore&lt;/code&gt;, and initializes git, all in one step.&lt;/p&gt;
&lt;h2 id=&quot;3-run-the-project&quot;&gt;3. Run the project&lt;/h2&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&amp;lt;project-name&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;uv run &lt;project-name&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; automatically creates the &lt;code&gt;.venv&lt;/code&gt;, installs dependencies, and picks the right Python version, without you having to activate anything manually. You can also drop into a REPL scoped to the project’s environment:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;uv&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;python&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;uv run python&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;4-set-up-vscode&quot;&gt;4. Set up VSCode&lt;/h2&gt;
&lt;p&gt;Install these extensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; (Microsoft) — core language support, IntelliSense&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Debugger&lt;/strong&gt; (Microsoft) — usually installs automatically alongside Python&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Environments&lt;/strong&gt; (Microsoft) — usually installs automatically alongside Python, unifies environment discovery across &lt;code&gt;venv&lt;/code&gt;, &lt;code&gt;uv&lt;/code&gt;, &lt;code&gt;conda&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ruff&lt;/strong&gt; — fast linting and formatting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then make sure VSCode is pointing at the right interpreter:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Cmd+Shift+P&lt;/code&gt; → &lt;strong&gt;Python: Select Interpreter&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;./.venv/bin/python&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Confirm it shows in the bottom-right status bar&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;5-configure-ruff-as-your-formatter&quot;&gt;5. Configure Ruff as your formatter&lt;/h2&gt;
&lt;p&gt;Add to your user &lt;code&gt;settings.json&lt;/code&gt; (applies to every project by default):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.formatOnSave&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;[python]&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.defaultFormatter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;charliermarsh.ruff&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;editor.formatOnSave&amp;quot;: true,  &amp;quot;[python]&amp;quot;: {    &amp;quot;editor.defaultFormatter&amp;quot;: &amp;quot;charliermarsh.ruff&amp;quot;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Test it by writing deliberately messy code and saving. Ruff should auto-format it, and unused imports should get flagged by both Ruff and Pylance.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;With this setup, a new Python project goes from zero to running, linted, formatted, and debuggable in VSCode in just a few minutes, without juggling &lt;code&gt;pyenv&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt;, and &lt;code&gt;venv&lt;/code&gt; separately. The workflow will feel familiar if you’re used to &lt;code&gt;npm&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;uv init&lt;/code&gt; ≈ &lt;code&gt;npm init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uv add&lt;/code&gt; ≈ &lt;code&gt;npm install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uv run&lt;/code&gt; ≈ &lt;code&gt;npm run&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Building a small MCP server to learn the protocol hands-on</title><link>https://ramigs.dev/blog/building-a-small-mcp-server/</link><guid isPermaLink="true">https://ramigs.dev/blog/building-a-small-mcp-server/</guid><description>Notes from payments-toolkit-mcp, a minimal MCP server I built to learn the protocol: tool/resource registration, the dual content/structuredContent response shape, and the stdout gotcha that trips up every stdio server.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After writing about &lt;a href=&quot;https://ramigs.dev/blog/what-is-mcp/&quot;&gt;what MCP actually is&lt;/a&gt;, the obvious next
step was building one. &lt;a href=&quot;https://github.com/ramigs/payments-toolkit-mcp&quot;&gt;&lt;code&gt;payments-toolkit-mcp&lt;/code&gt;&lt;/a&gt; is a small MCP server that
exposes payment-data validation as MCP tools: Luhn checksum validation, card
network detection, and IBAN validation. It also exposes a static resource
listing supported card networks and their prefix ranges.&lt;/p&gt;
&lt;h2 id=&quot;composition-not-configuration&quot;&gt;Composition, not configuration&lt;/h2&gt;
&lt;p&gt;The whole server is built from the official &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;, and
&lt;code&gt;src/index.ts&lt;/code&gt; is just composition. It creates a server, registers each
capability, and connects a transport:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;McpServer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;name: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;payments-toolkit-mcp&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;version: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;1.0.0&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerValidateCardNumberTool&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(server);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerDetectCardTypeTool&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(server);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerValidateIbanTool&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(server);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerCardNetworksResource&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(server);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;transport&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;StdioServerTransport&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; server.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(transport);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const server = new McpServer({  name: &amp;#x27;payments-toolkit-mcp&amp;#x27;,  version: &amp;#x27;1.0.0&amp;#x27;,});registerValidateCardNumberTool(server);registerDetectCardTypeTool(server);registerValidateIbanTool(server);registerCardNetworksResource(server);const transport = new StdioServerTransport();await server.connect(transport);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Each tool lives in its own file under &lt;code&gt;src/tools/&lt;/code&gt;, and each one only knows
how to register itself onto a server it’s handed. It doesn’t own the
server or the transport. The validation logic itself (&lt;code&gt;isValidLuhn&lt;/code&gt;, the IBAN
mod-97 check, the IIN/BIN prefix table) lives in &lt;code&gt;src/lib/&lt;/code&gt;, completely
unaware that MCP exists. That split made the MCP-specific code trivial to
write, since it’s never more than a schema and a thin wrapper around a
function that already works and is easy to test on its own.&lt;/p&gt;
&lt;h2 id=&quot;a-tool-is-a-schema-plus-a-handler&quot;&gt;A tool is a schema plus a handler&lt;/h2&gt;
&lt;p&gt;Registering a tool means giving it a name, a Zod input/output schema, and a
handler:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;server.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerTool&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;validate_card_number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;title: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Validate Card Number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;description:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Checks whether a card number passes the Luhn checksum algorithm. &apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Accepts digits only (spaces/dashes should be stripped by the caller).&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;inputSchema: { cardNumber: cardNumberSchema },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;outputSchema: { valid: z.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;cardNumber&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;valid&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;isValidLuhn&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(cardNumber);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;content: [{ type: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, text: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({ valid }) }],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;structuredContent: { valid },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;server.registerTool(  &amp;#x27;validate_card_number&amp;#x27;,  {    title: &amp;#x27;Validate Card Number&amp;#x27;,    description:      &amp;#x27;Checks whether a card number passes the Luhn checksum algorithm. &amp;#x27; +      &amp;#x27;Accepts digits only (spaces/dashes should be stripped by the caller).&amp;#x27;,    inputSchema: { cardNumber: cardNumberSchema },    outputSchema: { valid: z.boolean() },  },  async ({ cardNumber }) =&gt; {    const valid = isValidLuhn(cardNumber);    return {      content: [{ type: &amp;#x27;text&amp;#x27;, text: JSON.stringify({ valid }) }],      structuredContent: { valid },    };  },);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The model reads &lt;code&gt;description&lt;/code&gt; to decide whether to call the tool. The input
schema does its own filtering: &lt;code&gt;cardNumberSchema&lt;/code&gt; enforces digits-only and
a sane length range, so malformed input never reaches &lt;code&gt;isValidLuhn&lt;/code&gt; in the
first place.&lt;/p&gt;
&lt;p&gt;The two-shape response (&lt;code&gt;content&lt;/code&gt; and &lt;code&gt;structuredContent&lt;/code&gt;) surprised me
initially. &lt;code&gt;content&lt;/code&gt; is the older, universal shape: a list of blocks a
client can render regardless of what it understands. &lt;code&gt;structuredContent&lt;/code&gt; is
the newer, typed one, matched against &lt;code&gt;outputSchema&lt;/code&gt; so a client can consume
it programmatically instead of parsing text. Returning both is redundant on
paper, but it’s what keeps the tool usable by clients that only implement one
side.&lt;/p&gt;
&lt;h2 id=&quot;resources-are-the-read-only-counterpart&quot;&gt;Resources are the read-only counterpart&lt;/h2&gt;
&lt;p&gt;Tools are actions; resources are just data a client can fetch by URI. The one
resource here, &lt;code&gt;card_networks&lt;/code&gt;, is a static JSON table of card networks and
their prefix ranges. It’s the same table &lt;code&gt;detect_card_type&lt;/code&gt; matches against
internally, exposed separately so a client can read it directly instead of
inferring it from tool calls:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;server.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerResource&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;card_networks&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;payments-toolkit://card-networks&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;title: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Card Networks&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;description:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Supported card networks and the IIN/BIN prefix ranges used to identify them.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;mimeType: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;application/json&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;contents: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;uri: uri.href,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;mimeType: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;application/json&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;text: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(data, &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;server.registerResource(  &amp;#x27;card_networks&amp;#x27;,  &amp;#x27;payments-toolkit://card-networks&amp;#x27;,  {    title: &amp;#x27;Card Networks&amp;#x27;,    description:      &amp;#x27;Supported card networks and the IIN/BIN prefix ranges used to identify them.&amp;#x27;,    mimeType: &amp;#x27;application/json&amp;#x27;,  },  async (uri) =&gt; ({    contents: [      {        uri: uri.href,        mimeType: &amp;#x27;application/json&amp;#x27;,        text: JSON.stringify(data, null, 2),      },    ],  }),);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Custom URI scheme (&lt;code&gt;payments-toolkit://...&lt;/code&gt;), a MIME type, and a handler that
returns &lt;code&gt;contents&lt;/code&gt;. It’s structurally almost identical to a tool registration,
which made resources feel like a small addition once tools already clicked
rather than a separate concept to learn.&lt;/p&gt;
&lt;h2 id=&quot;prompts-are-the-user-invoked-primitive&quot;&gt;Prompts are the user-invoked primitive&lt;/h2&gt;
&lt;p&gt;Tools and resources cover two of MCP’s three primitives. The third is a
prompt: a reusable template the server hands the client instead of the
client writing it per integration. The one prompt here, &lt;code&gt;check_payment_details&lt;/code&gt;,
takes optional &lt;code&gt;cardNumber&lt;/code&gt;/&lt;code&gt;iban&lt;/code&gt; arguments and returns a message telling the
model which tools to call and how to format the summary. The server never
calls the tools itself, it just hands back text:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;server.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;registerPrompt&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;check_payment_details&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;title: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Check Payment Details&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;description:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Validates a card number and/or IBAN using the available tools and &apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;reports the results in a standard summary format.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;argsSchema: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;cardNumber: z.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Card number to validate&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;iban: z.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;IBAN to validate&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;cardNumber&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;iban&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;messages: [{ role: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, content: { type: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, text: &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/* ... */&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; } }],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;server.registerPrompt(  &amp;#x27;check_payment_details&amp;#x27;,  {    title: &amp;#x27;Check Payment Details&amp;#x27;,    description:      &amp;#x27;Validates a card number and/or IBAN using the available tools and &amp;#x27; +      &amp;#x27;reports the results in a standard summary format.&amp;#x27;,    argsSchema: {      cardNumber: z.string().optional().describe(&amp;#x27;Card number to validate&amp;#x27;),      iban: z.string().optional().describe(&amp;#x27;IBAN to validate&amp;#x27;),    },  },  ({ cardNumber, iban }) =&gt; ({    messages: [{ role: &amp;#x27;user&amp;#x27;, content: { type: &amp;#x27;text&amp;#x27;, text: /* ... */ } }],  }),);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;argsSchema&lt;/code&gt; is a flat shape of strings only, not arbitrary Zod like a tool’s
&lt;code&gt;inputSchema&lt;/code&gt;. The MCP spec has clients render prompt arguments as plain text
fields. That restriction lines up with how prompts get invoked: not chosen by
the model like a tool, but triggered explicitly by the user, surfaced as a
slash command in Claude Code
(&lt;code&gt;/mcp__payments-toolkit-mcp__check_payment_details&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&quot;the-gotcha-stdout-is-not-yours&quot;&gt;The gotcha: stdout is not yours&lt;/h2&gt;
&lt;p&gt;This is the one mistake the &lt;a href=&quot;https://github.com/ramigs/payments-toolkit-mcp&quot;&gt;README&lt;/a&gt; specifically calls out, and it’s the
kind of thing you’d only discover by hitting it: over the stdio transport,
stdout is the JSON-RPC wire. A stray &lt;code&gt;console.log&lt;/code&gt; doesn’t just clutter logs; it
injects malformed data into the protocol stream and breaks the client’s parser.
Every bit of debug output in this server goes through &lt;code&gt;console.error&lt;/code&gt; instead,
since stderr is left alone. This explains why MCP server boilerplate almost
always reaches for a logger or &lt;code&gt;console.error&lt;/code&gt; by convention rather than
&lt;code&gt;console.log&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;inspecting-and-connecting&quot;&gt;Inspecting and connecting&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@modelcontextprotocol/inspector&lt;/code&gt; gives a local web UI to call tools and read
resources directly, without wiring up a client first. That’s useful for
confirming schemas and responses actually round-trip before pointing a real
host at the server. Once that works, connecting it to Claude Code is a
single command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;claude&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;mcp&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;payments-toolkit-mcp&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/path/to/payments-toolkit-mcp/dist/index.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;claude mcp add payments-toolkit-mcp -- node /path/to/payments-toolkit-mcp/dist/index.js&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;/mcp&lt;/code&gt; inside a session then confirms the connection: seeing
&lt;code&gt;payments-toolkit-mcp · ✔ connected&lt;/code&gt; means the handshake worked and the
tools were discovered. That registration defaults to local scope, tied to
the project directory &lt;code&gt;claude mcp add&lt;/code&gt; was run from, so a different project
needs its own &lt;code&gt;claude mcp add&lt;/code&gt; (or &lt;code&gt;--scope user&lt;/code&gt; to make the server
available everywhere).&lt;/p&gt;
&lt;h2 id=&quot;adding-the-http-transport&quot;&gt;Adding the HTTP transport&lt;/h2&gt;
&lt;p&gt;Stdio only works because Claude Code spawns the server itself and owns the
subprocess. A server meant to be shared across multiple clients needs to run
over HTTP instead, via &lt;code&gt;StreamableHTTPServerTransport&lt;/code&gt;. Supporting both meant
splitting &lt;code&gt;index.ts&lt;/code&gt;: tool/resource registration moved into a
&lt;code&gt;createServer()&lt;/code&gt; factory, and each transport got its own module, picked at
startup by a &lt;code&gt;--http&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;The part that isn’t obvious going in: an &lt;code&gt;McpServer&lt;/code&gt; can only be
&lt;code&gt;connect()&lt;/code&gt;-ed to one transport, so serving multiple HTTP clients from one
long-running process means a fresh &lt;code&gt;McpServer&lt;/code&gt; + &lt;code&gt;StreamableHTTPServerTransport&lt;/code&gt;
pair per session, created on the &lt;code&gt;initialize&lt;/code&gt; request and keyed by the
&lt;code&gt;Mcp-Session-Id&lt;/code&gt; header on every request after that:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;transport) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;isInitializeRequest&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(req.body)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;res.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/* ... */&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;transport &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;StreamableHTTPServerTransport&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;sessionIdGenerator&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: () &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;randomUUID&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;onsessioninitialized&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;newSessionId&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;transports.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(newSessionId, transport&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;createServer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; server.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(transport);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if (!transport) {  if (!isInitializeRequest(req.body)) {    res.status(400).json({/* ... */});    return;  }  transport = new StreamableHTTPServerTransport({    sessionIdGenerator: () =&gt; randomUUID(),    onsessioninitialized: (newSessionId) =&gt; {      transports.set(newSessionId, transport!);    },  });  const server = createServer();  await server.connect(transport);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Requests without a session ID that aren’t &lt;code&gt;initialize&lt;/code&gt; get a 400.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] diagram-design</title><link>https://ramigs.dev/blog/diagram-design/</link><guid isPermaLink="true">https://ramigs.dev/blog/diagram-design/</guid><description>diagram-design: an agent plugin that generates on-brand editorial diagrams as self-contained HTML/SVG, using your own site colors and typography instead of generic rounded boxes</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about &lt;a href=&quot;https://github.com/cathrynlavery/diagram-design&quot;&gt;&lt;code&gt;diagram-design&lt;/code&gt;&lt;/a&gt;, a
Claude Code plugin (also works with Codex, Factory Droid, and Pi) that bundles
an agent skill for generating diagrams — architecture, flowcharts, sequences,
Gantt charts, and dozens of other types — as self-contained HTML and SVG files.&lt;/p&gt;
&lt;p&gt;The problem it solves is one I’ve run into before: ask an AI assistant for a
diagram and you get back a generic rounded-box-and-arrow illustration that looks
nothing like anything else on the page it’s meant to sit in. &lt;code&gt;diagram-design&lt;/code&gt;
fixes that by onboarding your site’s actual design tokens — colors, typography,
spacing — in about a minute, then using them for every diagram it generates
afterward. The output is plain HTML with embedded SVG: no build step, no
external dependencies, and it exports cleanly to PNG or SVG when you just need
the image.&lt;/p&gt;
&lt;p&gt;The architecture diagram in &lt;a href=&quot;https://ramigs.dev/blog/what-is-mcp/&quot;&gt;today’s MCP post&lt;/a&gt; is a good
showcase of what it can do — same fonts, same color tokens as the rest of this
site, not a generic diagram pasted in from somewhere else:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Architecture diagram of MCP showing an AI model connected to two MCP clients, each maintaining a 1:1 connection to its own MCP server over stdio or Streamable HTTP. The database server reaches PostgreSQL; the GitHub server reaches the GitHub API.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;880&quot; height=&quot;568&quot; src=&quot;https://ramigs.dev/_astro/2026-08-20-mcp-architecture.BpJ0d18d_DsRxa.svg&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>What is the Model Context Protocol (MCP)?</title><link>https://ramigs.dev/blog/what-is-mcp/</link><guid isPermaLink="true">https://ramigs.dev/blog/what-is-mcp/</guid><description>A short primer on MCP — the host/client/server split, why each client keeps a 1:1 connection to a server, and the two transports (stdio and Streamable HTTP) that connect them.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;MCP (Model Context Protocol) standardizes how an AI model reaches outside
itself — to a database, an API, a filesystem, whatever. Before it, every
integration was bespoke: a custom tool definition and glue code per app, per
model, per data source. MCP replaces that with one protocol both sides
implement once. The usual analogy is USB-C: everyone agreeing on the same
connector is what makes it useful.&lt;/p&gt;
&lt;h2 id=&quot;host-client-server&quot;&gt;Host, client, server&lt;/h2&gt;
&lt;p&gt;MCP defines three roles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host&lt;/strong&gt; — the AI application itself: Claude, an IDE, an agent. It embeds
the model and decides when to reach outside it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client&lt;/strong&gt; — lives inside the host, one per server. It speaks MCP on one
side and hands results back to the model on the other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server&lt;/strong&gt; — a small process that exposes capabilities over MCP: tools to
call, resources to read, prompts to reuse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each client maintains a single, dedicated connection to exactly one server. Want
to talk to both a database and GitHub, that’s two clients running side by side
inside the same host — not one client juggling two connections.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Architecture diagram of MCP showing an AI model connected to two MCP clients, each maintaining a 1:1 connection to its own MCP server over stdio or Streamable HTTP. The database server reaches PostgreSQL; the GitHub server reaches the GitHub API.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;880&quot; height=&quot;568&quot; src=&quot;https://ramigs.dev/_astro/2026-08-20-mcp-architecture.BpJ0d18d_DsRxa.svg&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;two-transports&quot;&gt;Two transports&lt;/h2&gt;
&lt;p&gt;MCP doesn’t care whether the server is a process on your machine or an API
across the network — the same request/response shape works either way. What
changes is the transport underneath:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;stdio&lt;/strong&gt; — for a server running locally. The host spawns it as a
subprocess and talks over its stdin/stdout. No network involved, so it’s
the default for anything reading local files or hitting a local database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Streamable HTTP&lt;/strong&gt; — for a remote server. The client POSTs
JSON-RPC requests to a single MCP endpoint; the server can respond
directly or upgrade that same connection to a Server-Sent Events stream
when it needs to push multiple messages back. This is what a hosted,
shared MCP server (GitHub’s, for example) uses today.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;It wasn’t always one endpoint. The original transport — &lt;strong&gt;HTTP+SSE&lt;/strong&gt; —
split the two directions across separate endpoints: the client POSTed to
one URL, and a server-initiated GET on a second URL opened the SSE stream
for everything coming back. The spec deprecated that split in favor of
Streamable HTTP’s single endpoint back in March 2025, though some older
servers still speak it for backwards compatibility.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-a-server-actually-exposes&quot;&gt;What a server actually exposes&lt;/h2&gt;
&lt;p&gt;Every server advertises the same three primitive types, regardless of
transport:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt; — functions the model can invoke (&lt;code&gt;create_issue&lt;/code&gt;, &lt;code&gt;run_query&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt; — data it can read (a file, a row, a config value).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompts&lt;/strong&gt; — reusable prompt templates the server hands the host, rather
than the host hand-rolling them per integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That fixed vocabulary is what makes MCP a protocol rather than just a
convention: a client doesn’t need to know anything about a server ahead of
time beyond “speak MCP” — it discovers what’s actually on offer at connection
time.&lt;/p&gt;
</content:encoded></item><item><title>How online card payments actually work</title><link>https://ramigs.dev/blog/how-online-card-payments-work/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-online-card-payments-work/</guid><description>A step-by-step walkthrough of an online card payment, from checkout and tokenization through 3DS, authorization, capture, and settlement.</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Tapping “pay” looks instant from the checkout page, but it kicks off a chain
of handoffs between the merchant, a payment provider, an acquiring bank, a
card network, and an issuing bank — most of it happening before any money
actually moves. Here’s the flow broken into its logical steps.&lt;/p&gt;
&lt;h2 id=&quot;1-card-data-capture&quot;&gt;1. Card data capture&lt;/h2&gt;
&lt;p&gt;The customer enters card details (PAN, expiry, CVV) on the merchant’s site. To
avoid full PCI DSS scope, this is usually done via hosted fields/iframes or an
SDK so raw card data never touches the merchant’s own servers.&lt;/p&gt;
&lt;h2 id=&quot;2-tokenization&quot;&gt;2. Tokenization&lt;/h2&gt;
&lt;p&gt;The card data is sent directly from the browser/app to the payment provider
or a tokenization vault, which returns a token (or sometimes a “network
token” issued by Visa/Mastercard directly) representing the card. The
merchant stores/uses this token instead of the PAN going forward.&lt;/p&gt;
&lt;h2 id=&quot;3-3d-secure-3ds-authentication&quot;&gt;3. 3D Secure (3DS) authentication&lt;/h2&gt;
&lt;p&gt;Before authorization (or sometimes as part of it), the transaction may go
through 3DS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Device fingerprinting / risk data collection&lt;/strong&gt; — browser/device data is
silently collected first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Risk-based decision (frictionless vs. challenge)&lt;/strong&gt; — the issuer’s ACS
(Access Control Server) decides, based on risk scoring and exemption rules
(e.g. PSD2 SCA exemptions), whether to challenge the customer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Challenge flow (if triggered)&lt;/strong&gt; — customer verifies via OTP, banking app
push notification, biometrics, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authentication result&lt;/strong&gt; — a cryptographic proof (CAVV) and ECI value are
returned, which shifts liability for fraud from merchant to issuer if
successful.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-authorization&quot;&gt;4. Authorization&lt;/h2&gt;
&lt;p&gt;The transaction (token + 3DS result, if any) is sent to the acquirer, which
routes it through the card network (Visa/Mastercard/etc.) to the issuing
bank. The issuer checks funds/credit limit, fraud signals, and approves or
declines. This step returns an authorization code and reserves the funds —
but doesn’t move money yet.&lt;/p&gt;
&lt;h2 id=&quot;5-capture&quot;&gt;5. Capture&lt;/h2&gt;
&lt;p&gt;The merchant “captures” the authorized amount — sometimes immediately
(common for e-commerce), sometimes later (common for things like hotel
bookings or shipping-dependent orders). Capture can also be partial.&lt;/p&gt;
&lt;h2 id=&quot;6-clearing--settlement&quot;&gt;6. Clearing &amp;amp; settlement&lt;/h2&gt;
&lt;p&gt;Batches of captured transactions are sent from acquirer to card network to
issuer for clearing. Funds actually move between banks here — this is where
the merchant’s bank account gets credited, typically 1-3 business days later
depending on the processor.&lt;/p&gt;
&lt;h2 id=&quot;7-reconciliation&quot;&gt;7. Reconciliation&lt;/h2&gt;
&lt;p&gt;The merchant matches transactions, fees, and payouts against their own order
records — often surfaced via webhooks/reports from the payment provider
(settlement reports, fee breakdowns, chargebacks, refunds).&lt;/p&gt;
&lt;h2 id=&quot;how-much-of-this-you-actually-build&quot;&gt;How much of this you actually build&lt;/h2&gt;
&lt;p&gt;Which of these steps a merchant implements directly — versus just calls into
— depends heavily on the integration style:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hosted/redirect checkout&lt;/strong&gt; (e.g. Stripe Checkout, PayPal redirect) —
almost the entire flow is abstracted away. The merchant redirects the
customer out and gets a webhook back with a pass/fail result, with no
visibility into tokenization, 3DS UX, or network routing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDK/Elements-based&lt;/strong&gt; (e.g. Stripe Elements, Adyen Components, Braintree
Drop-in) — the common middle ground. Card capture is embedded via hosted
fields, and tokenization plus 3DS are triggered by a single SDK call that
handles the challenge modal internally. The merchant orchestrates &lt;em&gt;when&lt;/em&gt;
things happen, not &lt;em&gt;how&lt;/em&gt;. Capture is usually the one step still in the
merchant’s hands directly — auto-capture vs. a separate API call made
later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct/custom integration&lt;/strong&gt; (e.g. an API-only acquirer integration, or a
direct 3DS Server implementation) — the merchant implements each step
itself, potentially handling raw card data (full PCI DSS scope) and
building its own 3DS challenge flow against the EMV 3DS spec. More
control, but real compliance and engineering burden shifts onto the
merchant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reconciliation (step 7) stays on the merchant regardless of tier — it’s
inherently about matching provider data against internal order records.
Clearing and settlement (step 6), on the other hand, are never something a
merchant implements; that happens entirely between acquirer, network, and
issuer.&lt;/p&gt;
&lt;h2 id=&quot;additional-flows-layered-on-top&quot;&gt;Additional flows layered on top&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Refunds&lt;/strong&gt; — reverse part or all of a captured transaction, processed
similarly through acquirer → network → issuer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chargebacks/disputes&lt;/strong&gt; — issuer-initiated reversal when a cardholder
disputes a charge, with a defined evidence/response window for the
merchant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webhooks/async notifications&lt;/strong&gt; — most providers notify the merchant
asynchronously for state changes, which matters most for redirect-based
3DS challenges or delayed authorization methods.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] Local Overrides in Chromium DevTools</title><link>https://ramigs.dev/blog/devtools-local-overrides/</link><guid isPermaLink="true">https://ramigs.dev/blog/devtools-local-overrides/</guid><description>How to make persistent local edits to a live site&apos;s files in DevTools, without touching the server or a build pipeline</description><pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about Local Overrides in Chromium-based DevTools.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is&quot;&gt;What it is&lt;/h2&gt;
&lt;p&gt;A feature that lets you make persistent edits to a website’s files — HTML,
CSS, JS, images, even network responses — directly in DevTools, and have
those edits survive page reloads, without actually changing anything on the
server.&lt;/p&gt;
&lt;h2 id=&quot;why-its-useful&quot;&gt;Why it’s useful&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Test CSS/JS tweaks against a live or staged site without touching source
code or a build pipeline&lt;/li&gt;
&lt;li&gt;Debug production issues by patching a minified file and confirming a fix
works before committing it&lt;/li&gt;
&lt;li&gt;Mock API responses by overriding XHR/fetch requests — handy for edge cases
or working around a backend that isn’t ready yet&lt;/li&gt;
&lt;li&gt;Changes persist across reloads, unlike ordinary Elements-panel edits which
reset on refresh&lt;/li&gt;
&lt;li&gt;Good for quick client demos or prototyping tweaks on a live site&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-set-it-up&quot;&gt;How to set it up&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Open DevTools and go to the &lt;strong&gt;Sources&lt;/strong&gt; panel&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Overrides&lt;/strong&gt; tab in the sidebar&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;“Select folder for overrides”&lt;/strong&gt; and pick a local folder&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Allow&lt;/strong&gt; when DevTools asks for permission to read/write it&lt;/li&gt;
&lt;li&gt;Edit a file directly in the &lt;strong&gt;Sources&lt;/strong&gt; panel (or CSS in the &lt;strong&gt;Styles&lt;/strong&gt;
pane, if that CSS lives in an actual &lt;code&gt;.css&lt;/code&gt; file) — DevTools saves the
change into your chosen folder automatically&lt;/li&gt;
&lt;li&gt;A small purple dot marks files with an active override; review them
anytime from the &lt;strong&gt;Overrides&lt;/strong&gt; tab. Uncheck &lt;strong&gt;Enable Local Overrides&lt;/strong&gt; to
temporarily disable them, or click &lt;strong&gt;Clear&lt;/strong&gt; to delete all override files
for good&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also kick this off from the &lt;strong&gt;Network&lt;/strong&gt; panel: right-click any
request and choose &lt;strong&gt;“Override content”&lt;/strong&gt; or &lt;strong&gt;“Override headers”&lt;/strong&gt; — useful
for mocking a specific API response or patching response headers (e.g.
CORS) without hunting for the file in Sources first.&lt;/p&gt;
&lt;h2 id=&quot;caveats&quot;&gt;Caveats&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Elements-panel edits don’t count.&lt;/strong&gt; Editing the DOM via “Edit as HTML”
in the Elements panel is &lt;em&gt;not&lt;/em&gt; saved as an override — DevTools explicitly
doesn’t track DOM tree changes there. Overrides only capture edits made in
the Sources panel, or CSS edits in the Styles pane when the CSS comes from
an external stylesheet (not inline in the HTML).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevTools has to stay open.&lt;/strong&gt; The override only serves while DevTools is
attached to that tab — close it, and the next load falls back to the real
file from the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overrides are scoped per-origin, so once set up, they keep applying to that
site (while DevTools is open) until you clear them or uncheck &lt;strong&gt;Enable
Local Overrides&lt;/strong&gt;.&lt;/p&gt;
</content:encoded></item><item><title>What are micro-frontends?</title><link>https://ramigs.dev/blog/what-are-micro-frontends/</link><guid isPermaLink="true">https://ramigs.dev/blog/what-are-micro-frontends/</guid><description>A from-zero explainer on micro-frontends: what they are, how the pieces get composed, and the tradeoffs that make them worth it only at a certain scale.</description><pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A single frontend codebase works fine until several teams need to ship to the
same product surface at the same time. Past that point, everyone is merging
into the same build, one team’s broken deploy blocks everyone else’s release,
and the app keeps growing in a direction no single team fully owns anymore.&lt;/p&gt;
&lt;p&gt;Micro-frontends are one answer to that problem.&lt;/p&gt;
&lt;h2 id=&quot;what-a-micro-frontend-actually-is&quot;&gt;What a micro-frontend actually is&lt;/h2&gt;
&lt;p&gt;A micro-frontend architecture splits the UI into &lt;strong&gt;independently built&lt;/strong&gt; and
&lt;strong&gt;independently deployed&lt;/strong&gt; pieces, each usually owned by a different team, then
composes them into one cohesive app for the end user.&lt;/p&gt;
&lt;p&gt;Think of it like a food court: independent vendors, each running their own
stand, their own staff, their own hours — but customers walk through one
entrance and experience it as a single food court. A vendor can swap in or
out without the building itself changing, which is close to what happens when
pieces are composed live, in the browser, at runtime.&lt;/p&gt;
&lt;h2 id=&quot;how-the-pieces-come-together&quot;&gt;How the pieces come together&lt;/h2&gt;
&lt;p&gt;Composition can happen at build time (stitched together before it ships) or
at runtime (assembled live, in the browser). Runtime composition is the more
common approach today, and it’s largely practical thanks to &lt;strong&gt;Module
Federation&lt;/strong&gt; — originally a Webpack feature, now also available in Vite
through plugins — a mechanism that lets independently built bundles load and
share code from each other in the browser, without a shared build step.&lt;/p&gt;
&lt;p&gt;That’s worth separating clearly: micro-frontend is the architectural pattern;
Module Federation is one tool that makes that pattern easier to pull off. The
pattern itself doesn’t require it — iframes and web components are older,
simpler ways to achieve the same composition, just with different tradeoffs.&lt;/p&gt;
&lt;h2 id=&quot;what-you-gain&quot;&gt;What you gain&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Independent deploys.&lt;/strong&gt; Each team ships on its own schedule, without
coordinating a shared release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack freedom.&lt;/strong&gt; Each piece can, in principle, use its own framework or
version, decoupled from what everyone else is running.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smaller blast radius.&lt;/strong&gt; A bad deploy from one team affects its own piece,
not the whole app.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-it-costs&quot;&gt;What it costs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version drift.&lt;/strong&gt; Host and remote pieces can disagree on shared
dependencies if versions aren’t coordinated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Duplicated weight.&lt;/strong&gt; Without careful sharing, the same dependency can ship
multiple times across pieces, bloating what the user downloads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UX consistency gets harder.&lt;/strong&gt; Independently built pieces can drift apart
in look and feel without deliberate effort to keep them aligned.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More moving parts.&lt;/strong&gt; Multiple pipelines, multiple deploy targets, and more
coordination overhead than a single codebase ever needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;is-it-worth-it&quot;&gt;Is it worth it?&lt;/h2&gt;
&lt;p&gt;Only once the problem it solves actually exists. If one team already owns the
whole frontend, none of the coordination pain above is happening yet — so
there’s nothing to gain and only the costs to pay. Micro-frontends earn their
keep at the point where multiple teams shipping to the same app has become the
actual bottleneck, not before.&lt;/p&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;A micro-frontend isn’t a tool or a library — it’s an architectural choice to
trade a simpler codebase for independent team ownership and release cadence.
Module Federation is one of the mechanisms that makes that trade practical,
not the thing itself. Whether it’s worth making comes down to one question: is
“multiple teams stepping on each other” your actual problem yet?&lt;/p&gt;
</content:encoded></item><item><title>Three layers of accessibility checks (and what each one caught)</title><link>https://ramigs.dev/blog/three-layers-of-accessibility-checks/</link><guid isPermaLink="true">https://ramigs.dev/blog/three-layers-of-accessibility-checks/</guid><description>How I approached accessibility on this rebuilt site — static linting, an automated axe-core audit, and manual keyboard testing — and the real, distinct bugs each layer caught that the others missed.</description><pubDate>Thu, 06 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Rebuilding this site on Astro was a good excuse to actually take accessibility
seriously, instead of treating it as an afterthought. I ended up combining three
different checks — static analysis, a runtime audit, and manual testing — and
what stuck with me is that there was no overlap between them: each layer caught
something the other two had no way of seeing.&lt;/p&gt;
&lt;h2 id=&quot;layer-1-static-linting&quot;&gt;Layer 1: static linting&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;cheapest&lt;/em&gt; layer, catching issues before code even runs. This project mixes
&lt;code&gt;.astro&lt;/code&gt; and &lt;code&gt;.vue&lt;/code&gt; files, and JSX-style accessibility linting doesn’t
understand Vue templates at all — so two separate ESLint plugins were needed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ota-meshi.github.io/eslint-plugin-astro/&quot;&gt;&lt;code&gt;eslint-plugin-astro&lt;/code&gt;&lt;/a&gt;’s
&lt;code&gt;jsx-a11y-recommended&lt;/code&gt; config, for &lt;code&gt;.astro&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vue-a11y.github.io/eslint-plugin-vuejs-accessibility/&quot;&gt;&lt;code&gt;eslint-plugin-vuejs-accessibility&lt;/code&gt;&lt;/a&gt;,
for &lt;code&gt;.vue&lt;/code&gt; files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;.astro&lt;/code&gt; side had a real gotcha: &lt;code&gt;jsx-a11y-recommended&lt;/code&gt; doesn’t ship its own
rules, it just re-exports &lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt;’s. That package is an
&lt;em&gt;optional&lt;/em&gt; peer dependency — without it installed, the config resolves to a
no-op, silently. A deliberate test file (&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with no &lt;code&gt;alt&lt;/code&gt;, a &lt;code&gt;&amp;lt;div onclick&amp;gt;&lt;/code&gt;) produced zero errors, which is exactly the kind of gap you don’t
notice until it’s too late. Installing &lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt; explicitly fixed
it.&lt;/p&gt;
&lt;p&gt;Once it was actually linting, running it against the real codebase surfaced 9
findings — 8 of them false positives, all the same shape:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;list&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;ul role=&amp;quot;list&amp;quot;&gt;...&lt;/ul&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The rule flags &lt;code&gt;role=&quot;list&quot;&lt;/code&gt; on a &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; as redundant, since a &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; already
has list semantics. Except this project’s reset stylesheet does &lt;code&gt;list-style: none&lt;/code&gt; everywhere, and removing bullets also strips the implicit list role in
Safari/VoiceOver — a well-known modern-reset gotcha. The explicit &lt;code&gt;role=&quot;list&quot;&lt;/code&gt;
puts the semantics back. Removing it, as the linter effectively suggested, would
have reintroduced a real bug. Rather than scattering a disable comment across
all 8 sites, the fix went into the rule config itself — &lt;code&gt;no-redundant-roles&lt;/code&gt;
takes a per-tag allowlist of roles to treat as non-redundant:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// eslint.config.mjs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;astro/jsx-a11y/no-redundant-roles&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;error&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{ ul: [&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;list&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;], ol: [&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;list&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;] },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// eslint.config.mjs&amp;#x27;astro/jsx-a11y/no-redundant-roles&amp;#x27;: [  &amp;#x27;error&amp;#x27;,  { ul: [&amp;#x27;list&amp;#x27;], ol: [&amp;#x27;list&amp;#x27;] },],&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;One rule-level exception instead of eight scattered ones, and it stays correct
for any &lt;code&gt;&amp;lt;ul role=&quot;list&quot;&amp;gt;&lt;/code&gt; added later too.&lt;/p&gt;
&lt;p&gt;The 9th finding was real: a placeholder &lt;code&gt;&amp;lt;a href=&quot;#&quot;&amp;gt;link&amp;lt;/a&amp;gt;&lt;/code&gt; left over from
early style-guide work — on &lt;code&gt;/style-guide&lt;/code&gt; itself, a dev-only route that never
ships to production — fixed by pointing it at an actual destination.&lt;/p&gt;
&lt;p&gt;In the end, none of Layer 1’s findings were actually critical — unsurprising,
since the AI tooling used to build the site had already been instructed to write
accessible markup along the way, so linting mostly confirmed that rather than
catching real breakage. Its real value is forward-looking rather than
retrospective — configured once, it now runs on every future change
automatically, catching regressions before they ever reach production.&lt;/p&gt;
&lt;h2 id=&quot;layer-2-runtime-audit&quot;&gt;Layer 2: runtime audit&lt;/h2&gt;
&lt;p&gt;Static linting only sees markup as written — it can’t tell you what actually
gets rendered in the browser.&lt;/p&gt;
&lt;p&gt;For that, I ran &lt;code&gt;axe-core&lt;/code&gt; (the same engine behind Lighthouse’s accessibility
score) via Puppeteer, against the real built and previewed site — not dev mode —
across 7 representative pages: home, about, blog index, three different post
types, and 404.&lt;/p&gt;
&lt;p&gt;Two distinct, real issues turned up — one present on every page, the other
specific to the homepage:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; landmark.&lt;/strong&gt; Page content lived in a plain
&lt;code&gt;&amp;lt;div class=&quot;page-content&quot;&amp;gt;&lt;/code&gt;. Screen reader users had no way to jump straight
to it. One-line fix:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line highlight del&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;div class=&quot;page-content&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;main class=&quot;page-content&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;div class=&amp;quot;page-content&amp;quot;&gt;&lt;main class=&amp;quot;page-content&amp;quot;&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Zero styling impact — the CSS targets the class, not the tag.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Missing &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; on the homepage.&lt;/strong&gt; The homepage’s intro section never had one —
just paragraphs, no heading. Fixed with a visually-hidden &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; — the page
keeps its intended visual design, but has a real, correctly-worded heading for
anyone not looking at it.&lt;/p&gt;
&lt;p&gt;Re-running the audit after both fixes: zero issues, across all 7 pages.&lt;/p&gt;
&lt;h2 id=&quot;layer-3-manual-keyboard-testing&quot;&gt;Layer 3: manual keyboard testing&lt;/h2&gt;
&lt;p&gt;This is the layer neither of the first two can substitute for, and it’s where
the most interesting bugs turned up — all missed by every automated check I had
configured, some because they only exist once a real person interacts with the
page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No visible focus indicator on a filter control.&lt;/strong&gt; The blog index has an
All/TIL/Articles filter built from three visually-hidden radio inputs (a
zero-JavaScript filter using CSS &lt;code&gt;:has()&lt;/code&gt;). Tab reached it fine, arrow keys
moved between options fine, native radio semantics were all correct — but there
was &lt;strong&gt;no visible focus ring anywhere in that interaction&lt;/strong&gt;. The label was only
styled for &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:has(:checked)&lt;/code&gt;; nothing for focus, so the native ring
rendered around the 1px-clipped input itself, invisible regardless. A real WCAG
2.4.7 (Focus Visible) failure — screen reader users were unaffected, since focus
and state are still announced correctly, but a sighted keyboard user had no way
to tell where they were:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.type-filter&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:has&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:focus-visible&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;outline&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;--focus-ring&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;outline-offset&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;--focus-ring-offset&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;.type-filter label:has(:focus-visible) {  outline: var(--focus-ring);  outline-offset: var(--focus-ring-offset);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is exactly the class of bug static and automated tooling tend to miss — it
requires observing actual rendered focus state, not just DOM/ARIA structure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wrong tab order on the scroll-to-top button.&lt;/strong&gt; It sat as the very last element
in the DOM, after the entire footer — so reaching it meant tabbing through the
whole page first, defeating its entire purpose as a shortcut. Worse, the button
becomes visible as soon as you scroll past one viewport — but Tab still wouldn’t
reach it until cycling through everything else on the page, so it was
&lt;strong&gt;visible&lt;/strong&gt; long before it was actually focusable. Fixed by moving it right
after the header, before &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; — safe to do since it’s &lt;code&gt;position: fixed&lt;/code&gt;, so
DOM order has zero effect on where it renders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No warning before opening a new tab.&lt;/strong&gt; External links (GitHub, LinkedIn) open
in a new tab with no signal to screen reader users. Not a WCAG AA requirement —
more of an AAA-level nicety — but trivial enough to add:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;aria&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{href.startsWith(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;http&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) ? &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;`${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;} (opens in new tab)`&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; : label}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aria-label={href.startsWith(&amp;#x27;http&amp;#x27;) ? &amp;#x60;${label} (opens in new tab)&amp;#x60; : label}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Added along the way:&lt;/strong&gt; a “skip to main content” link — genuinely missing, not
a bug fix. First Tab stop on every page, invisible until it receives keyboard
focus, jumping straight into &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;whats-still-left&quot;&gt;What’s still left&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Manual VoiceOver testing&lt;/strong&gt; still needs to be done. The rotor navigation and
VO-key combinations have a learning curve, and I don’t know them well enough yet
to test properly — that’ll be done in a future iteration.&lt;/p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The takeaway&lt;/h2&gt;
&lt;p&gt;Three types of check, three different bug classes, no overlap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Linting&lt;/strong&gt; guards against regressions going forward — here it mostly
confirmed already-accessible markup, but it’ll catch real mistakes the next
time someone (human or AI) writes one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated auditing&lt;/strong&gt; catches structural issues linting can’t see, because it
needs a real rendered page to check against.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manual testing&lt;/strong&gt; catches interaction bugs neither can see at all, because
they only exist once a real person moves through the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of them substitutes for the others. If I’d stopped after the linter came
back clean, the invisible-focus-ring bug and the scroll-button tab order would
still be live today.&lt;/p&gt;
</content:encoded></item><item><title>Claude Agent Skills: when a prompt deserves to be promoted</title><link>https://ramigs.dev/blog/claude-code-agent-skills/</link><guid isPermaLink="true">https://ramigs.dev/blog/claude-code-agent-skills/</guid><description>What Claude Agent Skills are, the 3-YESes test for deciding when to create one, their anatomy and progressive disclosure model, and the security considerations of installing someone else&apos;s skill.</description><pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Credit / Source: Learned via &lt;a href=&quot;https://fullcycle.com.br/&quot;&gt;Full Cycle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-a-skill-is&quot;&gt;What a skill is&lt;/h2&gt;
&lt;p&gt;Do you find yourself explaining the same ‘how’ to the model, time after time?
That’s a skill waiting to be born.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;skill&lt;/strong&gt; is reusable procedural knowledge, loaded on demand. It’s not a
one-off prompt, and it’s not code (a function) — it’s a folder with
instructions, versioned in the repo.&lt;/p&gt;
&lt;p&gt;It sits alongside &lt;code&gt;CLAUDE.md&lt;/code&gt;/&lt;code&gt;AGENTS.md&lt;/code&gt; and &lt;a href=&quot;https://ramigs.dev/blog/agents-and-subagents-in-claude-code/&quot;&gt;custom
subagents&lt;/a&gt;, but answers a
different question: not “what should the agent always know” (that’s
&lt;code&gt;CLAUDE.md&lt;/code&gt;) and not “who should handle this task” (that’s a subagent), but
“how do I do this specific procedure, correctly, every time.”&lt;/p&gt;
&lt;h2 id=&quot;when-to-create-one&quot;&gt;When to create one&lt;/h2&gt;
&lt;p&gt;The single triage question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is this procedural knowledge &lt;strong&gt;reusable&lt;/strong&gt; and &lt;strong&gt;stable&lt;/strong&gt; enough to be worth
a versioned file?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that’s not clear-cut, the &lt;strong&gt;3-YESes test&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reuse&lt;/strong&gt; — is it repetitive? (across multiple prompts, days, projects)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-obvious procedure&lt;/strong&gt; — is there a “how” the model doesn’t get right on
its own?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stability&lt;/strong&gt; — does the rule hold for days/weeks/months?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-is-not-a-skill-common-triage-mistakes&quot;&gt;What is not a skill (common triage mistakes)&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ask&lt;/th&gt;
&lt;th&gt;Belongs in&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;“Always answer in English”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; (global preference)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Status of the last deploy, right now”&lt;/td&gt;
&lt;td&gt;MCP / tool (live state)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Fix this parser bug”&lt;/td&gt;
&lt;td&gt;A one-off prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Rule of thumb: one skill per responsibility, built on top of a shared base — not
one skill per project trying to do everything.&lt;/p&gt;
&lt;h2 id=&quot;anatomy-a-folder--skillmd&quot;&gt;Anatomy: a folder + SKILL.md&lt;/h2&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;my-skill/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;SKILL.md      -&amp;gt; the only required file (frontmatter + body)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;reference/    -&amp;gt; extra context, loaded on demand&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;scripts/      -&amp;gt; deterministic execution&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;eval/         -&amp;gt; tests for the skill&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;my-skill/  SKILL.md      -&gt; the only required file (frontmatter + body)  reference/    -&gt; extra context, loaded on demand  scripts/      -&gt; deterministic execution  eval/         -&gt; tests for the skill&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The frontmatter (YAML at the top) has exactly two required fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt; — the skill’s identity, matching the folder name.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;description&lt;/code&gt;&lt;/strong&gt; — the dispatch classifier. Third person, concrete
triggers, and a “do NOT use for…” clause to keep it from over-firing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Useful optional fields: &lt;code&gt;allowed-tools&lt;/code&gt;, &lt;code&gt;disable-model-invocation&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;progressive-disclosure&quot;&gt;Progressive disclosure&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;When it loads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt; + &lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Always, near-zero cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SKILL.md&lt;/code&gt; body&lt;/td&gt;
&lt;td&gt;Only on a match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reference/&lt;/code&gt; + &lt;code&gt;scripts/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;On demand&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That structure is what lets it scale: the permanent cost is Level 1 only,
which is why you can have dozens of skills installed at once. Not every skill
needs to climb through all three levels.&lt;/p&gt;
&lt;h2 id=&quot;six-principles&quot;&gt;Six principles&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The description is everything&lt;/strong&gt; — concrete triggers, plus an explicit
“do NOT use for” clause.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One responsibility&lt;/strong&gt; — “review,” “test,” and “scaffold” are three
separate skills, not one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Push weight to Level 3&lt;/strong&gt; — keep the body short, put the rest in
&lt;code&gt;reference/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Script beats prose&lt;/strong&gt; — anything deterministic becomes a script, not a
paragraph of instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You’re running someone else’s code&lt;/strong&gt; — treat it like installing software
(see below).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lean and versioned&lt;/strong&gt; — it lives in git, changes go through a PR.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;security-treat-it-like-installing-software&quot;&gt;Security: treat it like installing software&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Only pull skills from sources you trust.&lt;/li&gt;
&lt;li&gt;Audit &lt;code&gt;SKILL.md&lt;/code&gt; and any &lt;code&gt;scripts/&lt;/code&gt; for unexpected network calls or access
outside the skill’s stated scope.&lt;/li&gt;
&lt;li&gt;Sources that fetch URLs can come back with malicious instructions embedded
in the response — prompt injection through the returned content.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allowed-tools&lt;/code&gt; is an extra layer of defense: only the listed tools are
available to the skill, regardless of what its instructions ask for.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>100 posts, a new stack: migrating ramigs.dev to Astro</title><link>https://ramigs.dev/blog/100-posts-migrating-to-astro/</link><guid isPermaLink="true">https://ramigs.dev/blog/100-posts-migrating-to-astro/</guid><description>Reflecting on 100 posts and a full rebuild of ramigs.dev — from Eleventy to Astro, what changed, and what stayed the same.</description><pubDate>Tue, 04 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;🎉 This happens to be post number 100 — nice timing, landing right as this
site’s migration to a new stack wraps up!&lt;/p&gt;
&lt;h2 id=&quot;old-stack-new-stack&quot;&gt;Old stack, new stack&lt;/h2&gt;
&lt;p&gt;The site launched in 2019 on Eleventy, with Gulp and Webpack handling the build.
It served me well for years, but it hadn’t aged well — still pinned to Node
v12, long since end-of-life and twelve(!) major versions behind where the new
stack landed.&lt;/p&gt;
&lt;p&gt;A few shots of the old site, for posterity:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Old ramigs.dev homepage, built with Eleventy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1280&quot; height=&quot;900&quot; src=&quot;https://ramigs.dev/_astro/2026-08-04-old-site-homepage.CESlVany_Z21E1y3.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Old ramigs.dev blog index page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1280&quot; height=&quot;900&quot; src=&quot;https://ramigs.dev/_astro/2026-08-04-old-site-blog-index.C7wfIVRb_2lo6mC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The new version moves to Astro, with Vue for the few interactive pieces,
TypeScript throughout, and pnpm managing all of it.&lt;/p&gt;
&lt;h2 id=&quot;what-was-accomplished&quot;&gt;What was accomplished&lt;/h2&gt;
&lt;p&gt;All 99 previous posts migrated with the exact same URLs, so nothing that already
pointed here breaks.&lt;/p&gt;
&lt;p&gt;The whole design system was rebuilt from scratch — tokens, dark mode, typography
— and the homepage and About page got updated content.&lt;/p&gt;
&lt;p&gt;I also went through a proper accessibility pass (keyboard navigation, focus
order, screen reader support via semantic HTML and ARIA) and a performance pass
driven by actual Lighthouse data.&lt;/p&gt;
&lt;h2 id=&quot;whats-new&quot;&gt;What’s new&lt;/h2&gt;
&lt;p&gt;A few things worth calling out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dark/light mode, remembers your choice, otherwise follows your system&lt;/li&gt;
&lt;li&gt;An RSS feed&lt;/li&gt;
&lt;li&gt;Reading-time estimates on every post&lt;/li&gt;
&lt;li&gt;Jump-to-year navigation on the blog index&lt;/li&gt;
&lt;li&gt;A TIL/Articles filter on the blog index — built with zero JavaScript, just CSS
&lt;code&gt;:has()&lt;/code&gt; selectors&lt;/li&gt;
&lt;li&gt;A skip-to-content link, for keyboard navigation&lt;/li&gt;
&lt;li&gt;A scroll-to-top button&lt;/li&gt;
&lt;li&gt;Properly themed code syntax highlighting for both light and dark mode&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;a-note-on-the-process&quot;&gt;A note on the process&lt;/h2&gt;
&lt;p&gt;Most of this migration was done with the help of Claude Code, using a single,
persistent &lt;code&gt;PLAN.md&lt;/code&gt; file as shared context across sessions — a living document
that evolved with the work, tracking decisions and what had actually been
verified. It let each session pick up exactly where the last one left off, and
doubled as a chance to learn Claude Code more in depth, not just to get the
project completed.&lt;/p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;The old site served me well for seven years, and there was nothing wrong with it
— Eleventy did exactly what a personal blog needs.&lt;/p&gt;
&lt;p&gt;But it was time for a real update. I’ve learned a lot since then, but hadn’t
really had the chance to apply it in my personal site. Plenty has changed in
this space since 2019 too — CSS especially, with things like cascade layers and
&lt;code&gt;:has()&lt;/code&gt; making entire categories of JavaScript unnecessary.&lt;/p&gt;
&lt;p&gt;If anything, this whole project reaffirmed that static sites are still a great
fit for this use case: fast, simple, cheap to host, and — maybe the best part —
the ability to just push to git and have the whole thing rebuild and deploy
automatically is still gold.&lt;/p&gt;
</content:encoded></item><item><title>CSS Cascade Layers: ending specificity wars</title><link>https://ramigs.dev/blog/css-cascade-layers/</link><guid isPermaLink="true">https://ramigs.dev/blog/css-cascade-layers/</guid><description>How @layer gives explicit control over the CSS cascade, letting us rank groups of styles independently of selector specificity</description><pubDate>Sun, 02 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CSS Cascade Layers (the &lt;code&gt;@layer&lt;/code&gt; at-rule) solve a long-standing pain point:
&lt;strong&gt;specificity wars&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Before layers, overriding a third-party library’s highly-specific selector meant
writing something even more specific, or reaching for &lt;code&gt;!important&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Layers let us group styles into buckets and rank those buckets directly,
independent of selector specificity.&lt;/p&gt;
&lt;h2 id=&quot;declaration-order-decides-priority&quot;&gt;Declaration order decides priority&lt;/h2&gt;
&lt;p&gt;Layers declared later win, no matter how specific the selectors are inside
earlier layers:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; reset, base, components;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; reset {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; components {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/* wins: &apos;components&apos; is declared last */&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@layer reset, base, components;@layer reset {  p {    margin: 0;  }}@layer components {  p {    margin: 20px;  } /* wins: &amp;#x27;components&amp;#x27; is declared last */}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Even &lt;code&gt;#my-id p&lt;/code&gt; inside &lt;code&gt;reset&lt;/code&gt; would lose to the plain &lt;code&gt;p&lt;/code&gt; in &lt;code&gt;components&lt;/code&gt; —
the whole layer sits higher in the cascade.&lt;/p&gt;
&lt;p&gt;Specificity still works as normal &lt;em&gt;inside&lt;/em&gt; a layer; layers only decide which
bucket beats another bucket.&lt;/p&gt;
&lt;h2 id=&quot;unlayered-css-always-wins&quot;&gt;Unlayered CSS always wins&lt;/h2&gt;
&lt;p&gt;To avoid breaking existing stylesheets, any rule outside of an &lt;code&gt;@layer&lt;/code&gt; block
beats layered CSS, regardless of order:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; components {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.btn&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;background-color&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;blue&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.btn&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;background-color&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;red&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/* always wins, unlayered */&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@layer components {  .btn {    background-color: blue;  }}.btn {  background-color: red;} /* always wins, unlayered */&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;(&lt;code&gt;!important&lt;/code&gt; flips this: important rules inside layers beat important
unlayered rules, so component libraries can still force safety overrides.)&lt;/p&gt;
&lt;h2 id=&quot;common-patterns&quot;&gt;Common patterns&lt;/h2&gt;
&lt;p&gt;Declare the layer order upfront, then fill layers in anywhere in the file (or
across files):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; theme, layout, components;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; components {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.card&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@layer theme, layout, components;@layer components {  .card {    padding: 1rem;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Wrap third-party CSS on import so it never fights with our own styles:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;framework.css&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; layer(framework);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;theme.css&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; layer(theme);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@import &amp;quot;framework.css&amp;quot; layer(framework);@import &amp;quot;theme.css&amp;quot; layer(theme);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Layers can also nest, via dot notation:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@layer&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; framework.layout {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.container&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;max-width&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1200&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@layer framework.layout {  .container {    max-width: 1200px;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;why-bother&quot;&gt;Why bother&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;No more &lt;code&gt;!important&lt;/code&gt; hacks to beat a framework’s specificity.&lt;/li&gt;
&lt;li&gt;A clear, explicit architecture: reset, base, layout, components, each its
own tier.&lt;/li&gt;
&lt;li&gt;Supported natively in all modern browsers — no build step required.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Node.js Corepack: one shim for npm, pnpm and yarn</title><link>https://ramigs.dev/blog/node-corepack/</link><guid isPermaLink="true">https://ramigs.dev/blog/node-corepack/</guid><description>What Corepack does, why corepack enable is still a manual step, and how nvm&apos;s default-packages file can automate it once Corepack becomes a separate npm package in Node.js 25+</description><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Different projects pin different package managers, and different versions of
them. One repo wants &lt;code&gt;pnpm@9&lt;/code&gt;, another wants &lt;code&gt;yarn@3&lt;/code&gt;, a third is happy with
whatever &lt;code&gt;npm&lt;/code&gt; shipped with your Node.js install.&lt;/p&gt;
&lt;p&gt;That means either installing every package manager globally and hoping the right
version is active, or running one-off &lt;code&gt;npx pnpm@9 install&lt;/code&gt; style commands to
sidestep your global install.&lt;/p&gt;
&lt;h2 id=&quot;what-corepack-does&quot;&gt;What Corepack does&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nodejs/corepack&quot;&gt;Corepack&lt;/a&gt; is a shim shipped alongside
Node.js that sits in front of &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pnpm&lt;/code&gt;, and &lt;code&gt;yarn&lt;/code&gt;. Instead of installing a
package manager globally, a project declares which one it needs via the
&lt;code&gt;packageManager&lt;/code&gt; field in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;packageManager&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;pnpm@9.12.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;packageManager&amp;quot;: &amp;quot;pnpm@9.12.0&amp;quot;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When you run &lt;code&gt;pnpm install&lt;/code&gt; inside that project, Corepack reads that field,
downloads and caches the exact &lt;code&gt;pnpm@9.12.0&lt;/code&gt; binary if it isn’t already
available locally, and transparently forwards the command to it.&lt;/p&gt;
&lt;p&gt;Move to a different project pinned to &lt;code&gt;yarn@3.6.0&lt;/code&gt; and the same thing happens
for &lt;code&gt;yarn&lt;/code&gt;, no reinstalling anything by hand. It solves the “works on my
machine” class of problem where two projects quietly expect two different
package manager versions.&lt;/p&gt;
&lt;h2 id=&quot;enabling-is-still-a-manual-step&quot;&gt;Enabling is still a manual step&lt;/h2&gt;
&lt;p&gt;Corepack ships with Node.js (from 14.19 up to, but not including, 25), but it
doesn’t do anything out of the box — it’s disabled by default. You need to run
&lt;code&gt;corepack enable&lt;/code&gt; once, so it can place its &lt;code&gt;pnpm&lt;/code&gt;/&lt;code&gt;yarn&lt;/code&gt; shims on your &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The catch if you’re using &lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;nvm&lt;/a&gt;: each Node.js
version nvm installs is its own self-contained directory, so &lt;code&gt;corepack enable&lt;/code&gt;
isn’t something you do once globally — it needs to be re-run every time you
install a new Node.js version.&lt;/p&gt;
&lt;h2 id=&quot;whats-changing-in-nodejs-25&quot;&gt;What’s changing in Node.js 25+&lt;/h2&gt;
&lt;p&gt;The Node.js Technical Steering Committee &lt;a href=&quot;https://socket.dev/blog/node-js-tsc-votes-to-stop-distributing-corepack&quot;&gt;voted to stop bundling
Corepack&lt;/a&gt;
with Node.js starting in v25. It isn’t being deprecated — it stays maintained —
but it’s no longer preinstalled. From v25 onward you install it yourself as a
regular npm package:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-g&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;corepack&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;corepack&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;enable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -g corepackcorepack enable&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Node 24 and earlier keep shipping it as before, so nothing changes until you
move to 25+.&lt;/p&gt;
&lt;h2 id=&quot;automating-its-installation-on-nvm&quot;&gt;Automating its installation on nvm&lt;/h2&gt;
&lt;p&gt;Since Corepack will soon be “just another package” to install, this is a good
fit for nvm’s &lt;a href=&quot;https://github.com/nvm-sh/nvm#default-global-packages-from-file-while-installing&quot;&gt;default-packages
file&lt;/a&gt;:
any package listed there gets installed automatically every time you &lt;code&gt;nvm install&lt;/code&gt; a new Node.js version. Add it once:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;corepack&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$NVM_DIR&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/default-packages&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo &amp;quot;corepack&amp;quot; &gt;&gt; &amp;quot;$NVM_DIR/default-packages&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;and every future Node.js version nvm installs will already have Corepack
installed, without needing to remember to run &lt;code&gt;npm install -g corepack&lt;/code&gt; by hand.&lt;/p&gt;
&lt;p&gt;You’ll still need to run &lt;code&gt;corepack enable&lt;/code&gt; for that version (the file only
automates the &lt;em&gt;install&lt;/em&gt; step, not enabling the shims), but that removes half the
friction of picking up a new Node.js version.&lt;/p&gt;
&lt;p&gt;This is the same trick covered in an &lt;a href=&quot;https://ramigs.dev/blog/manage-yarn-via-nvm/&quot;&gt;older TIL about managing yarn versions via
nvm&lt;/a&gt; — same file, same idea, just pointed at
Corepack instead of a single package manager.&lt;/p&gt;
</content:encoded></item><item><title>CLAUDE.md and AGENTS.md: correct the system, not the output</title><link>https://ramigs.dev/blog/claude-md-and-agents-md/</link><guid isPermaLink="true">https://ramigs.dev/blog/claude-md-and-agents-md/</guid><description>Why CLAUDE.md and AGENTS.md exist, what actually belongs in them, progressive disclosure, and how to keep them in sync across different AI coding tools.</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;AI coding agents don’t carry any memory of your codebase from one session to the
next. Every session starts cold — no idea how to run your tests, no notion of
the convention you insisted on last week, no memory of the mistake you already
corrected once before.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; and &lt;code&gt;AGENTS.md&lt;/code&gt; exist to close that gap: project-level files that
get read automatically before the agent does anything else, so it shows up
already knowing what it would otherwise need to be told again.&lt;/p&gt;
&lt;p&gt;That also makes them different from regular documentation. Documentation is
written for humans. These files are read by a model, every single session, and
cost context whether they’re useful or not — so the discipline isn’t writing
them, it’s keeping them focused enough to deserve that permanent seat in every
request.&lt;/p&gt;
&lt;h2 id=&quot;claudemd-vs-agentsmd&quot;&gt;CLAUDE.md vs AGENTS.md&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; is Claude Code’s native format — it’s loaded automatically at the
start of every session. It isn’t documentation; it’s short, precise instructions
the agent needs before it starts working.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; is an open standard adopted by many coding agents, but Claude Code
doesn’t read it natively.&lt;/p&gt;
&lt;h2 id=&quot;progressive-disclosure&quot;&gt;Progressive disclosure&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; doesn’t all load at once. A root-level &lt;code&gt;CLAUDE.md&lt;/code&gt; loads at the
start of the session. A &lt;code&gt;CLAUDE.md&lt;/code&gt; inside &lt;code&gt;backend/&lt;/code&gt; only loads once Claude is
actually working in that folder. Other docs aren’t preloaded at all — they’re
read on demand, when something actually points Claude to them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; guides the agent automatically; everything else should load only
when necessary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;what-actually-belongs-in-it&quot;&gt;What actually belongs in it&lt;/h2&gt;
&lt;p&gt;Short, precise, and useful the moment a task starts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Environment&lt;/strong&gt; — how to start/stop things, which env vars matter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests&lt;/strong&gt; — the commands to run and what counts as passing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conventions&lt;/strong&gt; — objective patterns, not style opinions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gotchas&lt;/strong&gt; — known errors and common pitfalls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Useful links&lt;/strong&gt; — paths to docs for specifics, not the specifics themselves.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;managing-claudemd-vs-agentsmd&quot;&gt;Managing CLAUDE.md vs AGENTS.md&lt;/h2&gt;
&lt;p&gt;Every AI coding tool looks for its own instruction file: Claude Code reads
&lt;code&gt;CLAUDE.md&lt;/code&gt;, Codex CLI (and others) read &lt;code&gt;AGENTS.md&lt;/code&gt;, Gemini CLI reads
&lt;code&gt;GEMINI.md&lt;/code&gt;, Cursor uses &lt;code&gt;.cursorrules&lt;/code&gt;. Maintain them separately and they
drift — someone updates one and forgets the rest.&lt;/p&gt;
&lt;h3 id=&quot;symlink&quot;&gt;Symlink&lt;/h3&gt;
&lt;p&gt;The simplest fix:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-s&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;AGENTS.md&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;CLAUDE.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ln -s AGENTS.md CLAUDE.md&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The files become byte-for-byte identical — one source of truth, no extra
tooling. It works fine on Mac/Linux, but needs Admin rights or Developer Mode
on Windows, and since both files must match exactly, there’s no room for
tool-specific instructions.&lt;/p&gt;
&lt;h3 id=&quot;import&quot;&gt;@import&lt;/h3&gt;
&lt;p&gt;The more flexible option. Put the shared instructions in &lt;code&gt;AGENTS.md&lt;/code&gt;, then make
&lt;code&gt;CLAUDE.md&lt;/code&gt; a one-liner that imports it, with any Claude-only rules appended
below:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;@AGENTS.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--0fw:bold;--1:#79B8FF;--1fw:bold&quot;&gt;## Claude Code specific&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Use plan mode for changes under &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;`src/payment/`&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@AGENTS.md## Claude Code specificUse plan mode for changes under &amp;#x60;src/payment/&amp;#x60;.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This works cross-platform with no symlink permissions to worry about, and lets
you layer tool-specific instructions on top of one shared base.&lt;/p&gt;
&lt;p&gt;Three things to watch for: &lt;code&gt;@file.md&lt;/code&gt; pulls in the file’s &lt;em&gt;entire&lt;/em&gt; content
(avoid it for large docs — link instead and let the agent read on demand),
imports inside fenced code blocks aren’t resolved, and imported headings aren’t
renested under the section that references them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; symlink if you want strictly identical files and don’t need
Windows support; &lt;code&gt;@import&lt;/code&gt; if you want one shared source plus room for
Claude-specific additions.&lt;/p&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;An agent that makes the same mistake twice isn’t a model problem — it’s a
missing line in &lt;code&gt;CLAUDE.md&lt;/code&gt;. Treat it less like a README and more like a place
to encode every correction you don’t want to give twice.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] vite-plugin-checker</title><link>https://ramigs.dev/blog/vite-plugin-checker/</link><guid isPermaLink="true">https://ramigs.dev/blog/vite-plugin-checker/</guid><description>vite-plugin-checker: surfacing TypeScript/ESLint errors in the terminal and as a browser overlay during Vite dev</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about
&lt;a href=&quot;https://github.com/fi3ework/vite-plugin-checker&quot;&gt;&lt;code&gt;vite-plugin-checker&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vite’s dev server transpiles files on the fly without type-checking them, so a
broken type can slip right through and only get caught later, at build time or
in CI. &lt;code&gt;vite-plugin-checker&lt;/code&gt; closes that gap.&lt;/p&gt;
&lt;p&gt;Once added to &lt;code&gt;vite.config.ts&lt;/code&gt;, it runs your configured checkers (TypeScript,
vue-tsc, ESLint, Stylelint…) in a separate process alongside the dev server,
and surfaces errors in two places while you’re developing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The terminal running &lt;code&gt;vite&lt;/code&gt;, right next to the dev server’s own logs.&lt;/li&gt;
&lt;li&gt;A browser overlay, so the error shows up on the page you’re already looking
at, instead of staying buried in a terminal you might not have open.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example config:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; checker &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;vite-plugin-checker&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;defineConfig&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;plugins: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;checker&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;typescript: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;eslint: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;lintCommand: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;eslint &quot;./src/**/*.{ts,tsx}&quot;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import checker from &amp;quot;vite-plugin-checker&amp;quot;;export default defineConfig({  plugins: [    checker({      typescript: true,      eslint: {        lintCommand: &amp;#x27;eslint &amp;quot;./src/**/*.{ts,tsx}&amp;quot;&amp;#x27;,      },    }),  ],});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Nice for catching type and lint errors immediately during development, instead
of waiting for a build or CI run to point them out.&lt;/p&gt;
</content:encoded></item><item><title>How agents and subagents work in Claude Code</title><link>https://ramigs.dev/blog/agents-and-subagents-in-claude-code/</link><guid isPermaLink="true">https://ramigs.dev/blog/agents-and-subagents-in-claude-code/</guid><description>Breaking down what an &apos;agent&apos; actually is in Claude Code: harness vs agent vs model, built-in vs custom agents, and how subagents delegate with isolated context.</description><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Credit / Source: Learned via &lt;a href=&quot;https://fullcycle.com.br/&quot;&gt;Full Cycle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;“Agent” gets thrown around loosely, but in Claude Code it maps to a fairly
precise structure. Here’s how the pieces actually fit together.&lt;/p&gt;
&lt;h2 id=&quot;anatomy-of-an-agent&quot;&gt;Anatomy of an agent&lt;/h2&gt;
&lt;p&gt;Claude Code is the &lt;strong&gt;harness&lt;/strong&gt;: it defines the environment, provides tools, and
exposes the mechanism for instantiating agents. It doesn’t decide which agent
runs, though — that call is made by the agent itself (the model), based on the
task at hand.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;agent&lt;/strong&gt; is made up of three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User instructions&lt;/strong&gt; — what you actually asked for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predefined behavior&lt;/strong&gt; — its scope and its own baked-in instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Its own context window&lt;/strong&gt; — separate token budget, filling up as it works.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The agent calls the &lt;strong&gt;model&lt;/strong&gt;, gets results back, and uses &lt;strong&gt;tools/environment&lt;/strong&gt;
(terminal, files, web, a database) to act on them.&lt;/p&gt;
&lt;p&gt;There are two ways an agent comes into existence:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Built-in agents&lt;/strong&gt;, already shipped with the harness — &lt;code&gt;Explore&lt;/code&gt;, &lt;code&gt;Plan&lt;/code&gt;,
&lt;code&gt;general-purpose&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom agents&lt;/strong&gt;, defined by you in &lt;code&gt;.claude/agents/my-agent.md&lt;/code&gt;. You write
the behavior and specialty; Claude Code creates, registers, and provides the
environment for it. The file is Markdown with YAML frontmatter (&lt;code&gt;name&lt;/code&gt;,
&lt;code&gt;description&lt;/code&gt;, optionally &lt;code&gt;tools&lt;/code&gt; and &lt;code&gt;model&lt;/code&gt;) followed by the subagent’s
system prompt in the body — and it can live at the project level
(&lt;code&gt;.claude/agents/&lt;/code&gt;, shared with your team) or the user level
(&lt;code&gt;~/.claude/agents/&lt;/code&gt;, available across all your projects).&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;The harness defines the environment. The agent follows instructions, uses its
own context, and calls the model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;subagents-delegation-with-isolated-context&quot;&gt;Subagents: delegation with isolated context&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;subagent&lt;/strong&gt; is a specialized agent, instantiated by the main agent, to
execute one specific task.&lt;/p&gt;
&lt;p&gt;The main agent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;receives the user’s goal,&lt;/li&gt;
&lt;li&gt;decides whether to delegate,&lt;/li&gt;
&lt;li&gt;sends a specific task to a subagent (or several, &lt;strong&gt;in parallel&lt;/strong&gt;),&lt;/li&gt;
&lt;li&gt;consolidates the results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which subagent gets picked isn’t hardcoded, either: Claude matches the task
against each subagent’s own &lt;code&gt;description&lt;/code&gt; field and delegates accordingly.&lt;/p&gt;
&lt;p&gt;Each subagent gets a task, a prompt from the main agent, its own tools, and —
critically — &lt;strong&gt;its own context window&lt;/strong&gt;. It doesn’t share the main agent’s
context, and the main agent doesn’t automatically see the subagent’s internal
history back — only the &lt;strong&gt;result, or a useful summary&lt;/strong&gt;, lands in its context
window. The full transcript isn’t gone; it’s just parked outside the main thread
unless you go pull it back up.&lt;/p&gt;
&lt;h2 id=&quot;why-the-isolation-matters&quot;&gt;Why the isolation matters&lt;/h2&gt;
&lt;p&gt;This isn’t an implementation detail — it’s the whole point.&lt;/p&gt;
&lt;p&gt;The main agent’s context stays clean no matter how much a subagent had to dig
around to get an answer. All that exploration cost is paid out of the subagent’s
own budget, not the main thread’s.&lt;/p&gt;
&lt;p&gt;Multiple subagents can run &lt;strong&gt;in parallel&lt;/strong&gt;, each burning its own tokens
independently, instead of serializing everything through one context window.&lt;/p&gt;
&lt;p&gt;A custom subagent lets you pre-bake scope and behavior for a repeated kind of
task (e.g. “review this diff,” “explore this codebase”) so you’re not
re-explaining it every time.&lt;/p&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;An “agent” in Claude Code isn’t the model — it’s instructions + behavior + its
own context window, wrapped around a model, using tools. Once that clicks,
subagents stop looking like magic and start looking like what they are: regular
agents, delegated a task, with a wall around their context so the main thread
doesn’t have to pay for their scratch work.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] git worktree</title><link>https://ramigs.dev/blog/git-worktree/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-worktree/</guid><description>How git worktree lets you check out multiple branches at once, and why it&apos;s not just a manual folder copy</description><pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about &lt;code&gt;git worktree&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It’s funny how a tool you use every single day can still surprise you. Git has
so many commands tucked away that never come up in the day-to-day &lt;code&gt;add&lt;/code&gt;,
&lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt; loop, and you only stumble onto them when you hit the
exact problem they were built for. In my case, that problem was wanting to work
on two branches of the same project, side by side, without stashing or juggling
a second clone.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Say I’m on &lt;code&gt;main&lt;/code&gt; and need to try out a migration on a separate branch, without
losing my current working directory. The instinct is to just copy the folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-r&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ramigs.dev&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ramigs.dev-migration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ramigs.dev-migration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-b&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;migration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cp -r ramigs.dev ramigs.dev-migrationcd ramigs.dev-migrationgit checkout -b migration&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That works, but it’s not quite right.&lt;/p&gt;
&lt;h2 id=&quot;enter-git-worktree&quot;&gt;Enter &lt;code&gt;git worktree&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git worktree add &amp;lt;path&amp;gt; -b &amp;lt;branch-name&amp;gt;&lt;/code&gt; is a single git command that does
this for you. A few things that make it different from copying the folder
yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It creates the new folder and checks out the new branch in one step — no
manual &lt;code&gt;cp&lt;/code&gt; then &lt;code&gt;git checkout&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The new folder does &lt;strong&gt;not&lt;/strong&gt; duplicate &lt;code&gt;.git&lt;/code&gt; — it’s a lightweight linked
working tree that shares the same object database/history with the original
repo. Only a small &lt;code&gt;.git&lt;/code&gt; file (a pointer) lives in the new folder, not the
whole history again.&lt;/li&gt;
&lt;li&gt;Things git doesn’t track — &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt; — won’t be copied either, so
you’d run &lt;code&gt;npm install&lt;/code&gt; fresh there.&lt;/li&gt;
&lt;li&gt;Git prevents the same branch from being checked out in two worktrees at once,
so &lt;code&gt;main&lt;/code&gt; in one folder and &lt;code&gt;migration&lt;/code&gt; in another can coexist safely with no
conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the command would look something like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;worktree&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;../ramigs.dev-migration&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-b&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;migration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git worktree add ../ramigs.dev-migration -b migration&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Run from the original repo, and that’s the entire setup step. Two folders, two
branches, one shared history, no copy-pasting required.&lt;/p&gt;
&lt;h2 id=&quot;cleaning-up-with-git-worktree-remove&quot;&gt;Cleaning up with &lt;code&gt;git worktree remove&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Once the migration branch was merged into &lt;code&gt;main&lt;/code&gt; — or if I’d decided to
abandon it instead — my instinct was to just &lt;code&gt;rm -rf&lt;/code&gt; the folder, same as I
would with a manual copy. That mostly works, but it
leaves git confused: the original repo still has an entry under
&lt;code&gt;.git/worktrees/&lt;/code&gt; pointing at a directory that no longer exists, and git won’t
let you delete the branch that folder had checked out until that reference is
cleared.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git worktree remove &amp;lt;path&amp;gt;&lt;/code&gt; is the proper way to tear it down:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;worktree&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;../ramigs.dev-migration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git worktree remove ../ramigs.dev-migration&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This removes both the working directory and the administrative metadata in
one step, so the original repo has no dangling references left behind. If the
worktree has uncommitted changes, git refuses to remove it unless you pass
&lt;code&gt;--force&lt;/code&gt; — a small safety net against losing work you forgot about.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git worktree list&lt;/code&gt; is worth running before and after, just to see what
worktrees are currently registered. And if you ever do end up manually
deleting a worktree folder instead of using &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;git worktree prune&lt;/code&gt;
cleans up the stale metadata afterwards.&lt;/p&gt;
&lt;p&gt;Doing the setup with &lt;code&gt;git worktree add&lt;/code&gt; and skipping the matching
&lt;code&gt;git worktree remove&lt;/code&gt; is the same mistake as the &lt;code&gt;cp -r&lt;/code&gt; approach from
earlier — it looks done, but it leaves git’s bookkeeping out of sync with
what’s actually on disk.&lt;/p&gt;
&lt;h2 id=&quot;worktrees-for-ai-agents&quot;&gt;Worktrees for AI agents&lt;/h2&gt;
&lt;p&gt;Worktrees aren’t just a convenience for a human juggling two branches, they’re
a good fit for AI coding agents too. An agent working in the same checkout
you’re using is one accidental &lt;code&gt;git checkout&lt;/code&gt; away from yanking the branch out from under you, or clobbering
uncommitted changes it didn’t know were “yours”. Give it its own worktree
instead, and it gets a real working directory and its own checked-out branch,
isolated from whatever you’re doing in the original, but still sharing the
same object database, so nothing has to be cloned or synced separately.&lt;/p&gt;
&lt;p&gt;That isolation is what makes it interesting for running multiple agents
side by side — each on its own branch, in its own worktree, unable to step on
each other. It’s the kind of building block that matters if you’re setting
agents to iterate somewhat independently, which ties into &lt;strong&gt;Loop
engineering&lt;/strong&gt;, something I want to dig into more in the near future.&lt;/p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The takeaway&lt;/h2&gt;
&lt;p&gt;I’ve been using git for almost a decade and still found a command I didn’t
even know I needed, and how useful it can be. That’s the fun part of tools
like this — they’re deep enough that you never really stop learning them.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] AI Context Windows and Tokens</title><link>https://ramigs.dev/blog/ai-context-windows-and-tokens/</link><guid isPermaLink="true">https://ramigs.dev/blog/ai-context-windows-and-tokens/</guid><description>A breakdown of the 8 pillars of AI-assisted software development, centered around optimizing your core dev workflow.</description><pubDate>Fri, 24 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Credit / Source: Learned via &lt;a href=&quot;https://fullcycle.com.br/&quot;&gt;Full Cycle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;TIL that an AI’s &lt;strong&gt;Context Window&lt;/strong&gt; isn’t measured by the number of messages or files
you send, but by a hard limit on total &lt;strong&gt;tokens&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Think of the Context Window as the LLM’s temporary desk space.&lt;/p&gt;
&lt;p&gt;The maximum amount of text (in tokens) the model can fit on that desk at one
single moment is its context window.&lt;/p&gt;
&lt;p&gt;Every piece of data takes up space on the same limited track:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompt&lt;/li&gt;
&lt;li&gt;History&lt;/li&gt;
&lt;li&gt;Open Files&lt;/li&gt;
&lt;li&gt;Code Snippets&lt;/li&gt;
&lt;li&gt;Tool Results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every single item listed above consumes tokens. Once that total hits the hard
limit, the model has to adapt.&lt;/p&gt;
&lt;h2 id=&quot;what-happens-when-the-window-fills-up&quot;&gt;What happens when the window fills up?&lt;/h2&gt;
&lt;p&gt;When your session runs out of token budget, the system usually handles it in one
of two ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Sliding Window (Overwrite):&lt;/strong&gt; The oldest tokens (like your initial prompt
or early chat history) are dropped off the back to make room for new input.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compact &amp;amp; Summarize:&lt;/strong&gt; The system takes early messages and creates a
condensed summary to preserve essential facts using far fewer tokens.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-big-takeaway&quot;&gt;The big takeaway&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Limits are strictly about tokens, not files or messages.&lt;/strong&gt; Keep your context
clean to ensure the model holds onto the information that actually matters!&lt;/p&gt;
</content:encoded></item><item><title>[TIL] The 9 pillars of AI-assisted software development</title><link>https://ramigs.dev/blog/pillars-of-ai-assisted-software-development/</link><guid isPermaLink="true">https://ramigs.dev/blog/pillars-of-ai-assisted-software-development/</guid><description>A breakdown of the 8 pillars of AI-assisted software development, centered around optimizing your core dev workflow.</description><pubDate>Fri, 24 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Credit / Source: Learned via &lt;a href=&quot;https://fullcycle.com.br/&quot;&gt;Full Cycle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;TIL that modern AI-assisted development isn’t just about using a smart chatbot
to autocomplete code. It actually relies on an interconnected ecosystem of &lt;strong&gt;8
supporting pillars&lt;/strong&gt;, all centered around one core concept: &lt;strong&gt;Workflow&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here is a quick breakdown of how these components work together:&lt;/p&gt;
&lt;h2 id=&quot;the-core-workflow&quot;&gt;The core: Workflow&lt;/h2&gt;
&lt;p&gt;At the center of it all is your &lt;strong&gt;Workflow&lt;/strong&gt;. The 8 supporting pillars exist to
enable, automate, and streamline how you plan, write, test, and ship code.&lt;/p&gt;
&lt;h2 id=&quot;the-8-supporting-pillars&quot;&gt;The 8 supporting pillars&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tools (IDEs, CLIs):&lt;/strong&gt; The interfaces you interact with daily (VS Code,
terminal CLI tools) where AI capabilities live.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agents:&lt;/strong&gt; Autonomous or semi-autonomous AI actors capable of executing
multi-step tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Models:&lt;/strong&gt; The underlying LLMs (like Claude, GPT, or Llama) driving the
intelligence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation &amp;amp; Artifacts:&lt;/strong&gt; Project specs, PRDs, context files, and design
artifacts that ground the AI in your specific codebase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skills:&lt;/strong&gt; Specific capabilities, rules, or system instructions assigned to
AI tools to perform precise jobs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory:&lt;/strong&gt; Contextual history (chat logs, persistent project knowledge,
vector databases) so the AI retains context mid-project.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environments (Local, Remote, GitHub):&lt;/strong&gt; Where execution actually
happens—whether you’re running code locally, in a remote container, or via
CI/CD pipelines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP Servers (Model Context Protocol):&lt;/strong&gt; Standardized protocol layers
connecting LLMs to external data sources, databases, and APIs.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;-key-takeaway&quot;&gt;💡 Key takeaway&lt;/h2&gt;
&lt;p&gt;If you want to maximize developer productivity with AI, &lt;strong&gt;don’t focus solely on
the models&lt;/strong&gt;. Look at the whole ecosystem—from memory and environment setups to
context protocols (MCP)—to build a seamless developer experience.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Prompting techniques (how AI models actually &quot;think&quot;)</title><link>https://ramigs.dev/blog/ai-prompting-techniques/</link><guid isPermaLink="true">https://ramigs.dev/blog/ai-prompting-techniques/</guid><description>A quick guide to the 5 core AI prompting techniques and how they help LLMs solve complex tasks.</description><pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I learned that getting a Large Language Model (LLM) to give a accurate,
high-quality answer isn’t just about &lt;em&gt;what&lt;/em&gt; you ask—it’s about &lt;em&gt;how you
structure its thinking process&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Researchers have developed structured &lt;strong&gt;prompting techniques&lt;/strong&gt; to help models
plan, reason step-by-step, and even interact with external tools.&lt;/p&gt;
&lt;p&gt;Here is a quick breakdown of 5 essential prompting techniques every AI developer
should know.&lt;/p&gt;
&lt;h2 id=&quot;1-zero-shot-prompting&quot;&gt;1. Zero-Shot Prompting&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Pitch:&lt;/strong&gt; Just ask directly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; You give the model a task or question without providing
prior examples or explicit step-by-step reasoning instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Simple facts, standard classification, translation, and everyday
Q&amp;amp;A where the model’s base training is sufficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-chain-of-thought-cot&quot;&gt;2. Chain-of-Thought (CoT)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Pitch:&lt;/strong&gt; “Show your work step-by-step.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; You instruct the model to break down its internal reasoning
before arriving at the final answer (often by adding &lt;code&gt;&quot;Let&apos;s think step by step&quot;&lt;/code&gt; or providing examples that demonstrate intermediate steps).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; LLMs generate text token-by-token. Giving them explicit
“thinking space” allows them to compute intermediate steps instead of guessing
prematurely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Math problems, writing and debugging complex code logic, and
multi-step reasoning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-tree-of-thoughts-tot&quot;&gt;3. Tree of Thoughts (ToT)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Pitch:&lt;/strong&gt; Explore multiple decision paths, evaluate possibilities, and
backtrack when stuck.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; An extension of Chain-of-Thought where the model explores a
tree structure of intermediate “thoughts.” At each step, it generates multiple
candidate ideas, evaluates them, and uses search algorithms to pick the best
path or backtrack if it hits a dead end.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Strategic planning, complex puzzle solving, chess-like game
logic, and multi-branch creative brainstorming.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-skeleton-of-thought-sot&quot;&gt;4. Skeleton-of-Thought (SoT)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Pitch:&lt;/strong&gt; Create an outline first, then expand each point in parallel for
maximum speed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; Designed specifically to reduce latency in long-form
generation. The model first outputs a concise structure or outline (the
“skeleton”). Then, each section of the skeleton is populated concurrently
(typically via parallel API requests).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Long-form blog posts, scaffolding full codebases/project
architectures, and rapid document generation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-react-reason--act&quot;&gt;5. ReAct (Reason + Act)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Pitch:&lt;/strong&gt; Think, execute an external action, observe the result, and
repeat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How it works:&lt;/strong&gt; Combines reasoning traces with dynamic tool usage in an
iterative loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Autonomous agents, AI coding assistants that run tests and
terminal commands, and external API integrations.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] The 4 layers of modern AI tools (Prompt, Context, Harness, Loop)</title><link>https://ramigs.dev/blog/four-layers-modern-ai-tools/</link><guid isPermaLink="true">https://ramigs.dev/blog/four-layers-modern-ai-tools/</guid><description>Understanding how AI tools work from a developer&apos;s perspective: the four layers of Prompt, Context, Harness, and Loop engineering</description><pubDate>Wed, 22 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When we start integrating AI tools into our daily development workflow, we often
think it’s all about writing better prompts. But as we dig deeper, we realize
Prompt Engineering is only layer one.&lt;/p&gt;
&lt;p&gt;Today I learned that understanding how modern AI tools work comes down to four
distinct layers:&lt;/p&gt;
&lt;h2 id=&quot;1-prompt-engineering&quot;&gt;1. Prompt engineering&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;What I tell the model.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is the foundation: crafting clear system instructions, setting explicit
boundaries, formatting outputs, and providing few-shot examples. It governs the
immediate reasoning and output of the model.&lt;/p&gt;
&lt;h2 id=&quot;2-context-engineering&quot;&gt;2. Context engineering&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;What the model “knows” at each step.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;LLMs are only as good as the information in their context window. Context
engineering is the art of dynamically injecting relevant data into the
prompt—via Retrieval-Augmented Generation (RAG), search outputs, memory stores,
or trimmed conversation histories—without exceeding token limits or causing
“lost in the middle” phenomena.&lt;/p&gt;
&lt;h2 id=&quot;3-harness-engineering&quot;&gt;3. Harness engineering&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The environment, mechanisms, and controls with which the agent operates.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The harness (or scaffold) is the runtime environment that wraps the LLM. It
manages API retries, handles tool integration (calling functions or web tools),
enforces structured output schemas, and manages fallback behavior if the model
hallucinates or fails.&lt;/p&gt;
&lt;h2 id=&quot;4-loop-engineering&quot;&gt;4. Loop engineering&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;How the system self-corrects and iterates.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Loop engineering moves past one-shot answers by putting the LLM inside an
iterative feedback loop. It gives the model the ability to run trial-and-error
workflows—evaluating its own work, using tool feedback, and revising its steps
until it meets the final goal.&lt;/p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The takeaway&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Layer&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Focus Area&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Instructions, examples, format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RAG, memory, conversation history, injected state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Harness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tool routing, permissions, validations, safety rails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Loop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-turn reasoning, self-correction, agentic workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Even if we’re not developing AI systems ourselves, knowing these layers helps us
work more effectively with AI-assisted development tools—we’ll better understand
their capabilities, limitations, and how to get the best results from them.&lt;/p&gt;
</content:encoded></item><item><title>Smoothing Nuxt 2 to Nuxt 4 Migration with vue-declassify</title><link>https://ramigs.dev/blog/smoothing-nuxt-2-to-nuxt-4-migration-with-vue-declassify/</link><guid isPermaLink="true">https://ramigs.dev/blog/smoothing-nuxt-2-to-nuxt-4-migration-with-vue-declassify/</guid><description>How vue-declassify is helping me prepare a Nuxt migration.</description><pubDate>Sun, 02 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Migrating a Nuxt 2 app to Nuxt 4 can be a daunting process, especially if your
codebase relies heavily on class-style Vue components. I’m right in the middle
of this kind of migration for a client, so these challenges are hitting close to
home.&lt;/p&gt;
&lt;p&gt;Before tackling the actual migration, I was looking for ways to do as much as
possible in the current version. That’s when I found a fantastic tool that makes
the transition much smoother:
&lt;a href=&quot;https://github.com/misha/vue-declassify&quot;&gt;vue-declassify&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vue-declassify&lt;/code&gt; automates the conversion of class-style components into their
equivalent object-style format, removing the usage of property decorators. This
is a crucial first step, as Nuxt 4 and Vue 3 favor object-style and composition
API patterns. By using this tool, I was able to prepare my codebase for the
migration while still running Nuxt 2, reducing risk and manual effort.&lt;/p&gt;
&lt;p&gt;The quality of &lt;code&gt;vue-declassify&lt;/code&gt; is impressive. It manages the conversion process
with accuracy, even for complex components, and the output is clean and
readable. Although it needs a couple of tweaks for some scenarios, it’s still a
fantastic tool.&lt;/p&gt;
&lt;p&gt;If you’re planning a similar migration, I highly recommend giving it a try—it
saves time and helps ensure a smoother upgrade path.&lt;/p&gt;
</content:encoded></item><item><title>Transitioning to AI-assisted software development</title><link>https://ramigs.dev/blog/transitioning-to-ai-assisted-software-development/</link><guid isPermaLink="true">https://ramigs.dev/blog/transitioning-to-ai-assisted-software-development/</guid><description>How I began integrating AI tools into my workflow</description><pubDate>Sun, 02 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the last couple of months, I’ve (finally) decided to take the leap and
start using AI tools to assist my day-to-day software development work.&lt;/p&gt;
&lt;p&gt;What began as basic prompts in Gemini—I find myself nowadays turning to Google
and Stack Overflow less and less—has now evolved into using GitHub Copilot
directly in VSCode. These tools have already made a noticeable impact, helping
me with code explanations, code generation, refactoring, and brainstorming new
ideas.&lt;/p&gt;
&lt;p&gt;Initially, I was not only a bit skeptical about relying on AI for programming
tasks, but I also wanted to let these tools mature and avoid getting caught up
in the initial hype.&lt;/p&gt;
&lt;p&gt;As I started experimenting, I found that these tools could quickly answer
questions, suggest code snippets, and automate repetitive tasks. This increased
my productivity and freed up more time for creative problem-solving and deeper
learning.&lt;/p&gt;
&lt;p&gt;Using Copilot Agent mode in VSCode has been truly impressive—there’s so much it
can do, and it does many things exceptionally well. I feel like I’ve only begun
to explore its capabilities, and I’m continually surprised by how well it
understands my intent.&lt;/p&gt;
&lt;p&gt;Today, AI is a regular part of my toolkit. I use it to generate boilerplate
code, refactoring code, review pull requests, and even write documentation. The
key is to treat AI as a helpful assistant—one that accelerates my work but still
requires my judgment and expertise.&lt;/p&gt;
&lt;p&gt;PS: AI assisted me in writing this post about AI. I promise it didn’t get too
meta! 🤖&lt;/p&gt;
</content:encoded></item><item><title>Vue.js: notes on Slots</title><link>https://ramigs.dev/blog/vue-notes-on-slots/</link><guid isPermaLink="true">https://ramigs.dev/blog/vue-notes-on-slots/</guid><description>Notes on Vue.js Slots</description><pubDate>Wed, 25 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Vue slots allow us to create generic components, by passing template content
(custom markup) to child components.&lt;/p&gt;
&lt;p&gt;Let’s say we have a &lt;code&gt;MyButton&lt;/code&gt; component which we’d like to make generic. We can
set a slot inside its template:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;button&gt;  &lt;slot&gt;&lt;/slot&gt;&lt;/button&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We can then pass custom content to &lt;code&gt;MyButton&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Submit&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;MyButton&gt;Submit&lt;/MyButton&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The HTML node &lt;code&gt;Submit&lt;/code&gt; replaces the tag &lt;code&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt; when the component gets
rendered.&lt;/p&gt;
&lt;p&gt;Optionally, we can specify some fallback content, to be rendered when the parent
does not provide content for a slot:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;slot&amp;gt;Click me&amp;lt;/slot&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;button&gt;  &lt;slot&gt;Click me&lt;/slot&gt;&lt;/button&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’re not limited to text, we can also pass any valid template content:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;strong&amp;gt;S&amp;lt;/strong&amp;gt;ubmit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;MyButton&gt;  &lt;strong&gt;S&lt;/strong&gt;ubmit&lt;/MyButton&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Since we didn’t explicitly name the slot above, it will implicitly become the
default slot, named &lt;code&gt;default&lt;/code&gt;. The following achieves the same result as the
above:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;template v-slot:default&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;strong&amp;gt;S&amp;lt;/strong&amp;gt;ubmit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;MyButton&gt;  &lt;template v-slot:default&gt;    &lt;strong&gt;S&lt;/strong&gt;ubmit  &lt;/template&gt;&lt;/MyButton&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Instead of &lt;code&gt;v-slot:&lt;/code&gt;, we can use the shorthand &lt;code&gt;#&lt;/code&gt;, as in &lt;code&gt;&amp;lt;template #default&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Named slots start to become useful when we want our component to provide more
than one slot:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;slot name=&quot;emoji&quot;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;slot&amp;gt;Click me&amp;lt;/slot&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;button&gt;  &lt;slot name=&amp;quot;emoji&amp;quot;&gt;&lt;/slot&gt;  &lt;slot&gt;Click me&lt;/slot&gt;&lt;/button&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;template v-slot:emoji&amp;gt;👍&amp;lt;/template&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;template v-slot:default&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;strong&amp;gt;S&amp;lt;/strong&amp;gt;ubmit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;MyButton&gt;  &lt;template v-slot:emoji&gt;👍&lt;/template&gt;  &lt;template v-slot:default&gt;    &lt;strong&gt;S&lt;/strong&gt;ubmit  &lt;/template&gt;&lt;/MyButton&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Sometimes we may have some state inside our child component that we’d need the
parent to be aware of (to render the content of a slot). We can use scoped slots
to achieve that:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mouseenter&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;hover &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mouseleave&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;hover &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;slot name=&quot;emoji&quot; :hover=&quot;hover&quot;&amp;gt;&amp;lt;/slot&amp;gt; &amp;lt;slot&amp;gt;Submit&amp;lt;/slot&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;button @mouseenter=&amp;quot;hover = true&amp;quot; @mouseleave=&amp;quot;hover = false&amp;quot;&gt;  &lt;slot name=&amp;quot;emoji&amp;quot; :hover=&amp;quot;hover&amp;quot;&gt;&lt;/slot&gt; &lt;slot&gt;Submit&lt;/slot&gt;&lt;/button&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;template #emoji=&quot;{ hover }&quot;&amp;gt;{{ hover ? &apos;👍&apos; : &apos;👎&apos; }}&amp;lt;/template&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;MyButton&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;MyButton&gt;  &lt;template #emoji=&amp;quot;{ hover }&amp;quot;&gt;{{ hover ? &amp;#x27;👍&amp;#x27; : &amp;#x27;👎&amp;#x27; }}&lt;/template&gt;&lt;/MyButton&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL]: Ventoy: bootable USB drive with multiple ISOs</title><link>https://ramigs.dev/blog/ventoy-bootable-usb-drive-with-multiple-isos/</link><guid isPermaLink="true">https://ramigs.dev/blog/ventoy-bootable-usb-drive-with-multiple-isos/</guid><description>Ventoy: open source tool to create bootable USB sticks with multiple ISOs</description><pubDate>Fri, 06 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about &lt;a href=&quot;https://www.ventoy.net/&quot;&gt;Ventoy&lt;/a&gt;, an amazing open source tool which
allows to create bootable USB drives with multiple ISOs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Ventoy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;768&quot; src=&quot;https://ramigs.dev/_astro/ventoy.B-mJqI7O_uwCRb.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;No need anymore to format the USB drive every time I need to install a new
operating system. The same USB stick can store more than one ISO.&lt;/p&gt;
&lt;p&gt;I’m currently storing GParted, Fedora, and Ubuntu images in the same USB stick.
When I boot from it, I just need to select the desired image from the menu.&lt;/p&gt;
&lt;p&gt;To add a new ISO, one simply needs to drag and drop the respective file to the
USB stick.&lt;/p&gt;
</content:encoded></item><item><title>Raspberry Pi 4 + Ubuntu: how to control the Case Fan</title><link>https://ramigs.dev/blog/raspberry-pi-4-ubuntu-how-to-control-the-case-fan/</link><guid isPermaLink="true">https://ramigs.dev/blog/raspberry-pi-4-ubuntu-how-to-control-the-case-fan/</guid><description>How to control the Raspberry Pi 4 fan on Ubuntu Server</description><pubDate>Mon, 02 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve recently bought a &lt;a href=&quot;https://www.raspberrypi.com/products/raspberry-pi-4-model-b/&quot;&gt;Raspberry Pi 4 Model
B&lt;/a&gt;, together with
its official &lt;a href=&quot;https://www.raspberrypi.com/products/raspberry-pi-4-case/&quot;&gt;Case&lt;/a&gt;
and &lt;a href=&quot;https://www.raspberrypi.com/products/raspberry-pi-4-case-fan/&quot;&gt;Case Fan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Raspberry 4 Case Fan&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;800&quot; src=&quot;https://ramigs.dev/_astro/raspberry-case-fan.CV0wk5Y6_ZsQxkC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;After installing Ubuntu Server, noticed that the fan was always running
non-stop. The fan has an annoying noise, and it should only run when needed,
i.e., when the Pi’s temperature rises above a certain threshold.&lt;/p&gt;
&lt;p&gt;Contrary to Raspberry OS, where the fan is disabled by default (and can be
configured from the UI via Preferences -&amp;gt; Raspberry Pi Configuration -&amp;gt;
Performance), Ubuntu Server requires an extra configuration step to be performed
from the command line.&lt;/p&gt;
&lt;p&gt;After the installation is finished, make sure the system is up-to-date:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;apt&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;apt&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;full-upgrade&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo apt updatesudo apt full-upgrade&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Based on my experiments, this step seems to really be needed, maybe because it
installs some Raspberry Pi required drivers/firmware (?).&lt;/p&gt;
&lt;p&gt;Finally, edit the file &lt;code&gt;/boot/firmware/config.txt&lt;/code&gt; and add the following at the
end of the file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;[all]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;dtoverlay&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;gpio-fan,&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;gpiopin&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;14,&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;temp&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;60000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[all]dtoverlay=gpio-fan,gpiopin=14,temp=60000&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A reboot is needed for changes to take effect.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;temp&lt;/code&gt; is the temperature at which the fan turns on. By default, on Raspberry OS
it’s set to 80º Celsius, but I’ve decided to set it to 60º Celsius.&lt;/p&gt;
&lt;p&gt;To confirm everything is working as expected (the fan is not running non-stop
anymore and turns on and off based on the Pi’s temperature) I used
&lt;a href=&quot;https://github.com/nschloe/stressberry&quot;&gt;&lt;code&gt;stressberry&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Dynamically importing JSON in JavaScript</title><link>https://ramigs.dev/blog/dynamically-importing-json-in-javascript/</link><guid isPermaLink="true">https://ramigs.dev/blog/dynamically-importing-json-in-javascript/</guid><description>Dynamic JSON import</description><pubDate>Fri, 08 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible to dynamically import a JSON file in JavaScript:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;team.json&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)).default;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const json = (await import(&amp;quot;team.json&amp;quot;)).default;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;import&lt;/code&gt; returns a promise, so async/await can be used. We then need to access
property &lt;code&gt;default&lt;/code&gt;, since &lt;code&gt;import&lt;/code&gt; only supports default export.&lt;/p&gt;
&lt;p&gt;Find out more about &lt;code&gt;import()&lt;/code&gt;
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Vue: v-model on custom components</title><link>https://ramigs.dev/blog/vue-v-model-on-custom-components/</link><guid isPermaLink="true">https://ramigs.dev/blog/vue-v-model-on-custom-components/</guid><description>Vue.js: Understanding the usage of v-model in custom components</description><pubDate>Sat, 02 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In Vue.js we use &lt;code&gt;v-model&lt;/code&gt; to achieve two-way data biding.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;v-model&lt;/code&gt; on form inputs is probably its most well-known use case, where
we want to keep the state of the input and some JavaScript state in sync.&lt;/p&gt;
&lt;p&gt;However, &lt;code&gt;v-model&lt;/code&gt; can also be used on custom components.&lt;/p&gt;
&lt;p&gt;Let’s say we have a parent component and a child component. We have the state in
the parent component but we want the child component to be able to update it.&lt;/p&gt;
&lt;h2 id=&quot;before-vue-34&quot;&gt;Before Vue 3.4&lt;/h2&gt;
&lt;p&gt;We would do something like this in the parent component:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;const selectedColor = ref(&apos;yellow&apos;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;ChildComponent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;selectedColor&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const selectedColor = ref(&amp;#x27;yellow&amp;#x27;)&lt;ChildComponent v-model=&amp;quot;selectedColor&amp;quot; /&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In the child component we would set a prop named &lt;code&gt;modelValue&lt;/code&gt; and emit the event
&lt;code&gt;update:modelValue&lt;/code&gt; (with its respective new value) when we wanted
&lt;code&gt;selectedColor&lt;/code&gt; to be updated:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;defineProps&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;modelValue&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;emit&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;defineEmits&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;update:modelValue&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;updateColor&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;emit&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;update:modelValue&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, color);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const props = defineProps([&amp;quot;modelValue&amp;quot;]);const emit = defineEmits([&amp;quot;update:modelValue&amp;quot;]);const updateColor = (color) =&gt; {  emit(&amp;quot;update:modelValue&amp;quot;, color);};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The prop and event names must be exactly those for &lt;code&gt;v-model&lt;/code&gt; to work
as expected.&lt;/p&gt;
&lt;h2 id=&quot;since-vue-34&quot;&gt;Since Vue 3.4&lt;/h2&gt;
&lt;p&gt;Starting from Vue 3.4, there’s a more convenient, less verbose way to achieve
the same result. We can use the &lt;code&gt;defineModel()&lt;/code&gt; macro.&lt;/p&gt;
&lt;p&gt;The parent component remains the same. In the child component no need for the
prop and the emit. &lt;code&gt;defineModel()&lt;/code&gt; does it all behind-the-scenes, and we can
just update the value directly in the child component:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;selectedColor&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;defineModel&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;updateColor&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;selectedColor.value &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; color;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const selectedColor = defineModel();const updateColor = (color) =&gt; {  selectedColor.value = color;};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>TypeScript: conditionally type a property based on another property</title><link>https://ramigs.dev/blog/typescript-conditionally-type-a-property-based-on-another-property/</link><guid isPermaLink="true">https://ramigs.dev/blog/typescript-conditionally-type-a-property-based-on-another-property/</guid><description>TypeScript: using a discriminated union to conditionally type a property based on another property</description><pubDate>Sat, 26 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s say we want to model a workout plan in TypeScript.&lt;/p&gt;
&lt;p&gt;A workout plan has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;id, name, creation date, updated date&lt;/li&gt;
&lt;li&gt;type (cardio or strength training)&lt;/li&gt;
&lt;li&gt;a list of exercises&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Depending on the workout type, the list of exercises should be typed
accordingly, i.e., a cardio exercise has distance and duration, while a strength
training exercise has number of sets, number of reps, and weight.&lt;/p&gt;
&lt;p&gt;How can we achieve that?&lt;/p&gt;
&lt;p&gt;The following is one way to do it. First, we set a base type &lt;strong&gt;without&lt;/strong&gt; type
and list of exercises:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;WorkoutPlanBase&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;number&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;workoutName&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;created_at&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Date&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;updated_at&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Date&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type WorkoutPlanBase = {  id: number  workoutName: string  created_at: Date  updated_at: Date}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then, we define our workout plan type using an intersection (to &lt;em&gt;extend&lt;/em&gt; from
the base type) and a &lt;strong&gt;discriminated union&lt;/strong&gt; (where we use the literal type for
&lt;code&gt;workoutType&lt;/code&gt; to specify the respective two possible types for &lt;code&gt;exercises&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;WorkoutPlan&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;WorkoutPlanBase&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;workoutType&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;strength&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;exercises&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;StrengthTrainingExercise&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;[] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;workoutType&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;cardio&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;exercises&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;CardioExercise&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;[] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type WorkoutPlan = WorkoutPlanBase &amp;amp;  (    | { workoutType: &amp;quot;strength&amp;quot;, exercises: StrengthTrainingExercise[] }    | { workoutType: &amp;quot;cardio&amp;quot;, exercises: CardioExercise[] }  );&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://hashnode.blainegarrett.com/typescript-conditional-scenarios#scenario-4-exclusive-or-within-a-type&quot;&gt;This
example&lt;/a&gt;
from Blaine Garret’s article was very helpful for my understanding.&lt;/p&gt;
</content:encoded></item><item><title>TypeScript: union members as object properties</title><link>https://ramigs.dev/blog/typescript-union-members-as-object-properties/</link><guid isPermaLink="true">https://ramigs.dev/blog/typescript-union-members-as-object-properties/</guid><description>TypeScript: how to type an object that has as properties all members of a string union type</description><pubDate>Wed, 09 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s say we have the following string union type to define all the possible
values of a status:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Status&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Completed&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Pending&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Canceled&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type Status = &amp;quot;Completed&amp;quot; | &amp;quot;Pending&amp;quot; | &amp;quot;Canceled&amp;quot;;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We also have another string union type to define all the possible colors of a
badge component:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;BadgeColor&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;green&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;yellow&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type BadgeColor = &amp;quot;green&amp;quot; | &amp;quot;yellow&amp;quot; | &amp;quot;red&amp;quot;;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We have the following object to map statuses with badge colors:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;statusColors&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Completed: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;green&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Pending: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;yellow&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Canceled: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const statusColors = {  Completed: &amp;quot;green&amp;quot;,  Pending: &amp;quot;yellow&amp;quot;,  Canceled: &amp;quot;red&amp;quot;,};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’d like to type this object to make sure we will never forget to update it, in
case we add or remove a status value. TypeScript should throw an error to let us
know.&lt;/p&gt;
&lt;p&gt;How can we achieve that?&lt;/p&gt;
&lt;p&gt;We can annotate the object as follows combining an index signature with the
JavaScript &lt;code&gt;in&lt;/code&gt; operator:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;statusColors&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Status&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;BadgeColor&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Completed: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;green&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Pending: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;yellow&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Canceled: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const statusColors: { [key in Status]: BadgeColor } = {  Completed: &amp;quot;green&amp;quot;,  Pending: &amp;quot;yellow&amp;quot;,  Canceled: &amp;quot;red&amp;quot;,};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, if we add a new status &lt;code&gt;Unknown&lt;/code&gt; to the &lt;code&gt;Status&lt;/code&gt; union type, TypeScript
complains:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Property &apos;Unknown&apos; is missing in type &apos;{ Completed: &quot;green&quot;; Pending: &quot;yellow&quot;; Canceled: &quot;red&quot;; }&apos; but required in type &apos;{ Completed: BadgeColor; Pending: BadgeColor; Canceled: BadgeColor; Unknown: BadgeColor; }&apos;.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we remove the status &lt;code&gt;Pending&lt;/code&gt;, TypeScript will also complain:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Object literal may only specify known properties, and &apos;Pending&apos; does not exist in type &apos;{ Completed: BadgeColor; Canceled: BadgeColor; }&apos;.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we try to assign a non-existing &lt;code&gt;BadgeColor&lt;/code&gt;, TypeScript will also complain:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Type &apos;&quot;blue&quot;&apos; is not assignable to type &apos;BadgeColor&apos;.&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>How to set up Sass in a Vue.js Vite project</title><link>https://ramigs.dev/blog/how-to-set-up-sass-in-a-vue-vite-project/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-set-up-sass-in-a-vue-vite-project/</guid><description>Vue.js 3: how to configure Sass in a Vite based project</description><pubDate>Sun, 06 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;First, install &lt;code&gt;sass-embedded&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;sass-embedded&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;yarn add -D sass-embedded&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that &lt;code&gt;sass-embedded&lt;/code&gt; should be installed, &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;sass&lt;/code&gt;; otherwise
you’ll get the warning &lt;code&gt;Deprecation [legacy-js-api]: The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then, add the following property to the &lt;code&gt;UserConfig&lt;/code&gt; object in &lt;code&gt;vite.config.ts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;preprocessorOptions&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;scss&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;modern-compiler&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;css: {  preprocessorOptions: {    scss: {      api: &amp;#x27;modern-compiler&amp;#x27;    }  }},&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can now update the extension of your &lt;code&gt;.css&lt;/code&gt; files to &lt;code&gt;.scss&lt;/code&gt; and use &lt;code&gt;&amp;lt;style lang=&quot;scss&quot;&amp;gt;&lt;/code&gt; in your &lt;code&gt;.vue&lt;/code&gt; files.&lt;/p&gt;
</content:encoded></item><item><title>Vite dev: automatically open app in the browser</title><link>https://ramigs.dev/blog/vite-dev-automatically-open-app-in-the-browser/</link><guid isPermaLink="true">https://ramigs.dev/blog/vite-dev-automatically-open-app-in-the-browser/</guid><description>Automatically open your app in the browser when running vite dev</description><pubDate>Sat, 05 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When running the &lt;code&gt;vite&lt;/code&gt; dev server (commands &lt;code&gt;vite&lt;/code&gt;, &lt;code&gt;vite dev&lt;/code&gt;, and &lt;code&gt;vite server&lt;/code&gt;), it’s possible to specify the option &lt;code&gt;--open&lt;/code&gt; so that the app opens
automatically in the browser.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BROWSER&lt;/code&gt; and &lt;code&gt;BROWSER_ARGS&lt;/code&gt; can also be used to pass additional settings,
either as environment variables or as &lt;code&gt;process.env&lt;/code&gt; arguments.&lt;/p&gt;
&lt;p&gt;For example, in my case I want to open Firefox Developer Edition, so in
&lt;code&gt;package.json&lt;/code&gt; I use:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;BROWSER=&apos;/Applications/Firefox Developer Edition.app&apos; vite --open&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;quot;dev&amp;quot;: &amp;quot;BROWSER=&amp;#x27;/Applications/Firefox Developer Edition.app&amp;#x27; vite --open&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] Unix shebang</title><link>https://ramigs.dev/blog/unix-shebang/</link><guid isPermaLink="true">https://ramigs.dev/blog/unix-shebang/</guid><description>How the Unix shebang is actually used</description><pubDate>Sat, 14 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how the Unix shebang is actually used.&lt;/p&gt;
&lt;p&gt;You know that first line in shell scripts starting with &lt;code&gt;!#&lt;/code&gt;, typically
something like &lt;code&gt;#!/bin/bash&lt;/code&gt; or &lt;code&gt;#!/bin/zsh&lt;/code&gt;? That’s the shebang.&lt;/p&gt;
&lt;p&gt;When a script is used as an executable (i.e., had its execute permission &lt;code&gt;x&lt;/code&gt; set
and is being executed as &lt;code&gt;./my-script&lt;/code&gt;), the operating system’s program loader
is instructed to run the shell interpreter (&lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt;, for example),
passing the rest of the script file content as the first argument to the
interpreter.&lt;/p&gt;
&lt;p&gt;This means that the file extension is not actually used by the interpreter. Even
though the presence of the extension has become a common convention (its
presence might provide some visible clue about the file type), &lt;a href=&quot;https://stackoverflow.com/a/27824204/10485152&quot;&gt;some argue that
extensions should not be used at
all&lt;/a&gt;. The rationale behind it is
that the user of the script should not care or need to know about how it was
implemented.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Git: commit early, commit often</title><link>https://ramigs.dev/blog/git-commit-early-commit-often/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-commit-early-commit-often/</guid><description>Avoid accidentally loosing ongoing work by git committing more often</description><pubDate>Sun, 08 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just another gentle reminder to “commit early, commit often”.&lt;/p&gt;
&lt;p&gt;Yesterday I got reminded of this the hard way, when loosing a reasonable amount
of work due to an accidental &lt;code&gt;git restore .&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My IDE was closed at that time, so wasn’t even able to use its undo
functionality to recover my changes 😭.&lt;/p&gt;
</content:encoded></item><item><title>GitHub Actions: trigger a workflow_dispatch workflow from another workflow</title><link>https://ramigs.dev/blog/github-actions-trigger-workflow-dispatch-workflow-from-another-workflow/</link><guid isPermaLink="true">https://ramigs.dev/blog/github-actions-trigger-workflow-dispatch-workflow-from-another-workflow/</guid><description>How to trigger a GitHub Actions workflow_dispatch workflow from another workflow</description><pubDate>Tue, 11 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s say you have your deploy pipeline set as a GitHub Action workflow, which
is triggered manually (using the &lt;code&gt;workflow_dispatch&lt;/code&gt; event) and allows you to
select to which environment you want to deploy.&lt;/p&gt;
&lt;p&gt;On certain occasions you might be interested in deploying to all environments.
Instead of having to manually trigger the pipeline for each environment, you
could create a new workflow and use the action
&lt;a href=&quot;https://github.com/benc-uk/workflow-dispatch&quot;&gt;&lt;code&gt;benc-uk/workflow-dispatch&lt;/code&gt;&lt;/a&gt;,
allowing you to trigger this workflow only once and deploy to all environments,
as such:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Deploy to all environments pipeline&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;workflow_dispatch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;deploy&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Deploy to all environments&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;runs-on&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;steps&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Invoke Deploy pipeline workflow for dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;benc-uk/workflow-dispatch@v1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;workflow&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;deploy-pipeline.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;inputs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;{ &quot;environment&quot;: &quot;dev&quot; }&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Invoke Deploy pipeline workflow for staging&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;benc-uk/workflow-dispatch@v1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;workflow&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;deploy-pipeline.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;inputs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;{ &quot;environment&quot;: &quot;staging&quot; }&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Invoke Deploy pipeline workflow for production&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;benc-uk/workflow-dispatch@v1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;workflow&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;deploy-pipeline.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;inputs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;{ &quot;environment&quot;: &quot;production&quot; }&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;name: Deploy to all environments pipelineon:  workflow_dispatch:jobs:  deploy:    name: &amp;quot;Deploy to all environments&amp;quot;    runs-on: ubuntu-latest    steps:      - name: Invoke Deploy pipeline workflow for dev        uses: benc-uk/workflow-dispatch@v1        with:          workflow: deploy-pipeline.yaml          inputs: &amp;#x27;{ &amp;quot;environment&amp;quot;: &amp;quot;dev&amp;quot; }&amp;#x27;      - name: Invoke Deploy pipeline workflow for staging        uses: benc-uk/workflow-dispatch@v1        with:          workflow: deploy-pipeline.yaml          inputs: &amp;#x27;{ &amp;quot;environment&amp;quot;: &amp;quot;staging&amp;quot; }&amp;#x27;      - name: Invoke Deploy pipeline workflow for production        uses: benc-uk/workflow-dispatch@v1        with:          workflow: deploy-pipeline.yaml          inputs: &amp;#x27;{ &amp;quot;environment&amp;quot;: &amp;quot;production&amp;quot; }&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Another cool thing about this action is that it your workflows will run in
parallel, since they’re triggered behind-the-scenes via REST API calls.&lt;/p&gt;
</content:encoded></item><item><title>Open Props review</title><link>https://ramigs.dev/blog/open-props-review/</link><guid isPermaLink="true">https://ramigs.dev/blog/open-props-review/</guid><description>A review on using Open Props in production</description><pubDate>Thu, 06 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-i-discovered-open-props&quot;&gt;How I discovered Open Props&lt;/h2&gt;
&lt;p&gt;Recently, we were given a mission to fully replace the frontend design in one of
my client’s applications - a typical user dashboard, built on &lt;a href=&quot;https://v2.nuxt.com/&quot;&gt;Nuxt
2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We were handed new Figma designs, which totally differed from the previous
designs, so we had no way other than deleting the existing CSS/Sass code
entirely and re-style the frontend from scratch.&lt;/p&gt;
&lt;p&gt;The previous version of styles were not in very good shape. The project had gone
through several design iterations in the past, with the participation of various
developers and without much thought having ever been put into CSS architecture
and conventions.&lt;/p&gt;
&lt;p&gt;We began researching how we could use this opportunity to implement a &lt;strong&gt;design
system&lt;/strong&gt; that could help us materialize the new Figma designs (pixel-perfect was
a requirement) more efficiently, while achieving more &lt;strong&gt;modular&lt;/strong&gt; and
&lt;strong&gt;maintainable&lt;/strong&gt; codebase.&lt;/p&gt;
&lt;p&gt;We came across &lt;a href=&quot;https://open-props.style&quot;&gt;Open Props&lt;/a&gt; and after studying its
documentation and watching some YouTube videos, we ended up deciding to
integrate it in our project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open Props is a CSS framework that provides built-in CSS custom properties
with sensible values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;installing-open-props&quot;&gt;Installing Open Props&lt;/h2&gt;
&lt;p&gt;We used the most recent version available at the time of implementation,
&lt;code&gt;1.6.21&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since we were still using an older version of Nuxt (which uses PostCSS 7 by
default), we faced some initial difficulties, but in the end we managed to
integrate Open Props, by upgrading to PostCSS 8 (and supported by
&lt;code&gt;@nuxt/postcss8&lt;/code&gt; and &lt;code&gt;postcss-html&lt;/code&gt;). We also used &lt;code&gt;postcss-jit-props&lt;/code&gt;, so that
only used variables got included and shipped.&lt;/p&gt;
&lt;p&gt;Autocomplete in VSCode for Open Props variables (and project global variables)
was pretty straight-forward to achieve by using the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=phoenisx.cssvar&quot;&gt;CSS Var Complete
extension&lt;/a&gt;
and following the documentation.&lt;/p&gt;
&lt;h2 id=&quot;using-open-props&quot;&gt;Using Open Props&lt;/h2&gt;
&lt;p&gt;One of the cool things about Open Props is that it is incrementally adoptable,
meaning you can load only the modules that are actually used.&lt;/p&gt;
&lt;p&gt;We began by loading the &lt;code&gt;normalize.light.min.css&lt;/code&gt; stylesheet to normalize the
styles between the different browsers and set some sensible defaults.&lt;/p&gt;
&lt;p&gt;Besides the normalize module, we’ve ended up actually &lt;strong&gt;not using any of the
other modules&lt;/strong&gt;. We discovered that our new design didn’t match the Open Props
values, so we ended up having to create our own design tokens, which were
nevertheless heavily inspired by Open Props.&lt;/p&gt;
&lt;p&gt;We haven’t still implemented - or given instructions on how to implement -
animations, but I can foresee us using the &lt;code&gt;animations.css&lt;/code&gt;, &lt;code&gt;durations.css&lt;/code&gt;,
and &lt;code&gt;easings.css&lt;/code&gt; modules. We’ll try to coordinate with the designer so that we
can make use of these already existing Open Props sensible values, avoiding
having to come up with our own.&lt;/p&gt;
&lt;h2 id=&quot;verdict&quot;&gt;Verdict&lt;/h2&gt;
&lt;p&gt;Although I can see tremendous value in this tool, I came to the conclusion that
it really didn’t fit our use case - a pixel-perfect implementation of an already
existing design.&lt;/p&gt;
&lt;p&gt;It did however heavily influence the structure and implementation of our design
system and respective design tokens.&lt;/p&gt;
&lt;p&gt;As mentioned above, we had some difficulties with the installation, but that’s
probably more on us using a legacy version of Nuxt. I believe that with current
versions of the most popular frontend frameworks the integration should be
seamless.&lt;/p&gt;
&lt;p&gt;All in all, I think this tool could be extremely helpful for someone that does
not have an already existing design and needs to more quickly create something
that looks consistent (and end up with more maintainable CSS), by letting Open
Props &lt;em&gt;guide&lt;/em&gt; the design.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] CSS: detect user request for light/dark themes</title><link>https://ramigs.dev/blog/css-detect-user-request-for-light-dark-themes/</link><guid isPermaLink="true">https://ramigs.dev/blog/css-detect-user-request-for-light-dark-themes/</guid><description>CSS: how to natively detect user request for light/dark themes</description><pubDate>Sat, 09 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about the &lt;code&gt;prefers-color-scheme&lt;/code&gt; CSS media feature, which allows to natively
detect if a user requested light or dark themes (typically through an operating
system or user agent setting).&lt;/p&gt;
&lt;p&gt;It can be used as such:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (prefers-color-scheme: dark) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;background&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;--bg-color-dark&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@media (prefers-color-scheme: dark) {  body {    background: var(--bg-color-dark);  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Chrome DevTools has a &lt;a href=&quot;https://stackoverflow.com/questions/57606960/how-can-i-emulate-prefers-color-scheme-media-query-in-chrome&quot;&gt;very useful
toggle&lt;/a&gt;
that allows emulating different &lt;code&gt;prefers-color-scheme&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;Learn more about &lt;code&gt;prefers-color-scheme&lt;/code&gt;
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Fully uninstall an application on macOS</title><link>https://ramigs.dev/blog/fully-uninstall-an-application-on-macos/</link><guid isPermaLink="true">https://ramigs.dev/blog/fully-uninstall-an-application-on-macos/</guid><description>How to fully uninstall an application on macOS</description><pubDate>Sun, 21 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Unfortunately, not all applications provide a clean, full uninstall.&lt;/p&gt;
&lt;p&gt;On macOS, one generally deletes the &lt;code&gt;.app&lt;/code&gt; file from &lt;code&gt;/Applications&lt;/code&gt;. But many
applications leave behind support files (cache, preferences, etc.), so might be
a good idea to go through the following folders and delete the respective
leftovers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/Library&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Library/Application Support&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Library/LaunchAgents&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Library/LaunchDaemons&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Library/Preferences&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Library/PrivilegedHelperTools&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Application Scripts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Application Support&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Caches&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Cookies&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Group Containers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Launch Agents&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Logs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Preferences&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/Library/Saved Application State&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>GitHub Actions: how to set a value conditionally</title><link>https://ramigs.dev/blog/github-actions-how-to-set-a-value-conditionally/</link><guid isPermaLink="true">https://ramigs.dev/blog/github-actions-how-to-set-a-value-conditionally/</guid><description>How to set a value conditionally in GitHub Actions</description><pubDate>Tue, 16 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;How to conditionally set a value in GitHub Actions:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;TOKEN&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;github.event.inputs.env == &apos;dev&apos; &amp;amp;&amp;amp; secrets.DEV_TOKEN || secrets.PROD_TOKEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;env:  TOKEN: github.event.inputs.env == &amp;#x27;dev&amp;#x27; &amp;amp;&amp;amp; secrets.DEV_TOKEN || secrets.PROD_TOKEN&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If &lt;code&gt;github.event.inputs.env == &apos;dev&apos;&lt;/code&gt; evaluates as &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;TOKEN&lt;/code&gt; will have
value &lt;code&gt;secrets.DEV_TOKEN&lt;/code&gt;; otherwise it will have value &lt;code&gt;secrets.PROD_TOKEN&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>What I do when my PR includes commits that are already in main</title><link>https://ramigs.dev/blog/what-i-do-when-my-pr-includes-commits-that-are-already-in-main/</link><guid isPermaLink="true">https://ramigs.dev/blog/what-i-do-when-my-pr-includes-commits-that-are-already-in-main/</guid><description>Specify which node version should be used to run a project</description><pubDate>Fri, 12 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sometimes I have an open PR (branch &lt;code&gt;my-pr&lt;/code&gt;) and I need to sync it with latest
&lt;code&gt;main&lt;/code&gt;. I usually do the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pull&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;origin&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-pr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git checkout maingit pull origin maingit checkout my-pr&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If there are merge conflicts, for some reason that I haven’t exactly figured
out, commits that are already in &lt;code&gt;main&lt;/code&gt; get included in my PR, when pushed.&lt;/p&gt;
&lt;p&gt;Might not be the most elegant solution, but one which works effectively for me.
After fixing merge conflicts, committing, and pushing, I do the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-pr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-b&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-pr-v2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;origin&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-pr-v2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git checkout my-prgit checkout -b my-pr-v2git push origin my-pr-v2&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, when opening the PR only my PR commits will be included. I can now close
the PR that has branch &lt;code&gt;my-pr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, I’ve read that it’s also possible to edit the PR via GitHub UI,
change the base branch to another branch and back to &lt;code&gt;main&lt;/code&gt;, but I haven’t tried
this solution myself.&lt;/p&gt;
</content:encoded></item><item><title>Integrating GitHub CLI in my workflow</title><link>https://ramigs.dev/blog/integrating-github-cli-in-my-workflow/</link><guid isPermaLink="true">https://ramigs.dev/blog/integrating-github-cli-in-my-workflow/</guid><description>Integrating GitHub CLI in my workflow: pull request management</description><pubDate>Sat, 30 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As the end of the year rapidly approaches, I’ve been reflecting and looking for
ways to increase my productivity in the next year.&lt;/p&gt;
&lt;p&gt;For some time I’ve been considering integrating &lt;a href=&quot;https://cli.github.com/&quot;&gt;GitHub
CLI&lt;/a&gt; in my workflow, aiming to reduce the back and
forth between the terminal and the GitHub web UI.&lt;/p&gt;
&lt;p&gt;Since I interact with pull requests pretty much everyday, several times a day,
that’s where I’ll focus mainly.&lt;/p&gt;
&lt;p&gt;Listing some useful commands below for reference.&lt;/p&gt;
&lt;h3 id=&quot;open-repository-in-the-web-browser&quot;&gt;Open repository in the web browser&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;browse&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh browse&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;list-open-prs&quot;&gt;List open PRs&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr list&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;get-status-of-relevant-prs&quot;&gt;Get status of relevant PRs&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;status&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr status&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;view-pr-in-the-browser&quot;&gt;View PR in the browser&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;view&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--web&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr view --web&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;checkout-a-pr&quot;&gt;Checkout a PR&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr checkout&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Accepts PR number or branch name.&lt;/p&gt;
&lt;h3 id=&quot;create-a-pr&quot;&gt;Create a PR&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr create&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It’s also possible to skip the interactive PR creation, by directly specify the
title and body:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--title&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;PR title&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--body&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;PR body&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr create --title &amp;quot;PR title&amp;quot; --body &amp;quot;PR body&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Other options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To mark PR as draft use option &lt;code&gt;-d&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To open the web browser to create the PR use option &lt;code&gt;-w&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;close-pr&quot;&gt;Close PR&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;close&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gh pr close&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Other options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To leave a closing comment use option &lt;code&gt;-c&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To delete the local and remote branch after close use option &lt;code&gt;-d&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The entire list of available commands and respective documentation can be found
&lt;a href=&quot;https://cli.github.com/manual/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Specify node version in package.json</title><link>https://ramigs.dev/blog/specify-node-version-in-package-json/</link><guid isPermaLink="true">https://ramigs.dev/blog/specify-node-version-in-package-json/</guid><description>Specify which node version should be used to run a project</description><pubDate>Thu, 28 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One way to minimize “it works on my machine” type of issues and bad surprises
related to incompatibilities (especially in team contexts) is to be very
specific (and if possible, ideally enforce) about the software versions that are
used across the entire stack.&lt;/p&gt;
&lt;p&gt;TIL about &lt;code&gt;engines.node&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;. As stated in the
&lt;a href=&quot;https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines&quot;&gt;documentation&lt;/a&gt;,
it’s used to “specify the version of node that your stuff works on”.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;engines.node&lt;/code&gt; is specified, someone that tries to &lt;code&gt;yarn install&lt;/code&gt; (and not
using a compatible &lt;code&gt;node&lt;/code&gt; version) will get an error similar to &lt;code&gt;The engine &quot;node&quot; is incompatible with this module. Expected version &quot;v20.10.0&quot;. Got &quot;16.20.2&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Run the following command to set &lt;code&gt;engines.node&lt;/code&gt; according to the current &lt;code&gt;node&lt;/code&gt;
version:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pkg&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;engines.node=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-v&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm pkg set engines.node=$(node -v)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] VSCode: Two file management extensions</title><link>https://ramigs.dev/blog/vscode-two-file-management-extensions/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-two-file-management-extensions/</guid><description>Two file management extensions in VSCode for increased productivity</description><pubDate>Tue, 26 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about two file management VSCode extensions for increased productivity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=sleistner.vscode-fileutils&quot;&gt;File Utils by Steffen
Leistner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=patbenatar.advanced-new-file&quot;&gt;advanced-new-file by
patbenatar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks for &lt;a href=&quot;https://www.youtube.com/watch?v=LY-DNBzXy48&quot;&gt;this tip&lt;/a&gt; James Q
Quick!&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Manage yarn via nvm</title><link>https://ramigs.dev/blog/manage-yarn-via-nvm/</link><guid isPermaLink="true">https://ramigs.dev/blog/manage-yarn-via-nvm/</guid><description>How to manage different yarn versions via nvm</description><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible to manage via &lt;code&gt;nvm&lt;/code&gt;, not only &lt;code&gt;node&lt;/code&gt; versions, but also
&lt;code&gt;yarn&lt;/code&gt; versions.&lt;/p&gt;
&lt;p&gt;The advantage of doing so (instead of one single installation via &lt;code&gt;brew&lt;/code&gt;, for
example), is that you’re able to &lt;em&gt;pin&lt;/em&gt; a specific &lt;code&gt;yarn&lt;/code&gt; version to each &lt;code&gt;node&lt;/code&gt;
version.&lt;/p&gt;
&lt;p&gt;For already installed &lt;code&gt;node&lt;/code&gt; versions, make sure you’re using the intended
version (i.e., &lt;code&gt;which node&lt;/code&gt; should print something like
&lt;code&gt;$NVM_DIR/versions/node/v20.10.0/bin/node&lt;/code&gt;) and then run &lt;code&gt;npm install -g yarn&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For future &lt;code&gt;node&lt;/code&gt; versions you’ll install, there’s a way to automatically
install &lt;code&gt;yarn&lt;/code&gt; alongside &lt;code&gt;node&lt;/code&gt;, without needing to explicitly install.&lt;/p&gt;
&lt;p&gt;We can use &lt;code&gt;nvm&lt;/code&gt;’s &lt;a href=&quot;https://github.com/nvm-sh/nvm#default-global-packages-from-file-while-installing&quot;&gt;default global packages from file while
installing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To do so, create a text file at &lt;code&gt;$NVM_DIR/default-packages&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;yarn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;yarn&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now no more old versions of &lt;code&gt;yarn&lt;/code&gt; 🎉, you’ll get the latest every time you
install a new &lt;code&gt;node&lt;/code&gt; version.&lt;/p&gt;
&lt;p&gt;You can also explore the possibility of adding other &lt;code&gt;npm&lt;/code&gt; packages that might
interest you, such as &lt;code&gt;@vue/cli&lt;/code&gt; or &lt;code&gt;nuxi&lt;/code&gt;, for example.&lt;/p&gt;
&lt;p&gt;Source:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/a/61175494/10485152&quot;&gt;Stack Overflow answer&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Migrating to Cypress.js 13 is awesome DX</title><link>https://ramigs.dev/blog/migrating-to-cypress-13-is-awesome-dx/</link><guid isPermaLink="true">https://ramigs.dev/blog/migrating-to-cypress-13-is-awesome-dx/</guid><description>My experience updating Cypress.js versions in two different projects</description><pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I’ve successfully migrated Cypress.js to &lt;code&gt;v13.6.0&lt;/code&gt; in two projects (one
from &lt;code&gt;v12.17.3&lt;/code&gt;, the other from &lt;code&gt;v9.7.0&lt;/code&gt;), pretty much flawlessly and in a
matter of minutes.&lt;/p&gt;
&lt;p&gt;In a nutshell, what I did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;update to new version in &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yarn install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;execute &lt;code&gt;cypress open&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cypress recognizes the migration, and suggests using the migration tool;
follow along with the three migrations steps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And … it’s done! Well pretty much. In my case, I also started to get some
conflicts with Jest, which I had to
&lt;a href=&quot;https://github.com/cypress-io/cypress/issues/22059#issuecomment-1148921141&quot;&gt;fix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Was such a nice experience using the migration tool, take a look at the amazing
UI of one of the migration steps (replacing &lt;code&gt;cypress.json&lt;/code&gt; with
&lt;code&gt;cypress.config.ts&lt;/code&gt;, because &lt;code&gt;cypress.json&lt;/code&gt; is no longer supported):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Require status checks&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2385&quot; height=&quot;1591&quot; src=&quot;https://ramigs.dev/_astro/2023-12-01-migrating-to-cypress-13-is-awesome-dx.DZqkl78Z_1JiRkQ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Thank you Cypress team, great work! We know how difficult version management can
be, especially in the JavaScript ecosystem 😅.&lt;/p&gt;
&lt;p&gt;See more about Cypress version migration
&lt;a href=&quot;https://docs.cypress.io/guides/references/migration-guide&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] VSCode: Setting the correct TypeScript version</title><link>https://ramigs.dev/blog/vscode-setting-typescript-version/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-setting-typescript-version/</guid><description>The importance of setting the TypeScript version according to the project in VSCode</description><pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Important update:&lt;/strong&gt; the settings mentioned below have since been deprecated in
favor of new ones, as documented in VSCode’s &lt;a href=&quot;https://github.com/microsoft/vscode/blob/main/extensions/typescript-language-features/package.nls.json&quot;&gt;&lt;code&gt;package.nls.json&lt;/code&gt;
file&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;# Deprecated in favor of the two settings below&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;# &quot;typescript.tsdk&quot;: &quot;node_modules/typescript/lib&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;# &quot;typescript.enablePromptUseWorkspaceTsdk&quot;: true,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;js/ts.tsdk.path&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;node_modules/typescript/lib&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;js/ts.tsdk.promptToUseWorkspaceVersion&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;true,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# Deprecated in favor of the two settings below# &amp;quot;typescript.tsdk&amp;quot;: &amp;quot;node_modules/typescript/lib&amp;quot;,# &amp;quot;typescript.enablePromptUseWorkspaceTsdk&amp;quot;: true,&amp;quot;js/ts.tsdk.path&amp;quot;: &amp;quot;node_modules/typescript/lib&amp;quot;,&amp;quot;js/ts.tsdk.promptToUseWorkspaceVersion&amp;quot;: true,&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Mystery solved! I finally discovered why sometimes I’d notice inconsistencies in
terms of the TypeScript errors between the terminal and VSCode.&lt;/p&gt;
&lt;p&gt;This happened because I was using different TypeScript versions. By default,
VSCode uses its own TypeScript version (typically a more recent version than the
one used by the project).&lt;/p&gt;
&lt;p&gt;I’d expect that the default would be for VSCode to use the project’s version,
but it seems it doesn’t.&lt;/p&gt;
&lt;p&gt;I suggest always having VSCode use the project’s version. This can be achieved
by &lt;a href=&quot;https://github.com/microsoft/TypeScript/issues/52396#issuecomment-1404056467&quot;&gt;setting VSCode to use the TypeScript Workspace
Version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This will add &lt;code&gt;&quot;typescript.tsdk&quot;: &quot;node_modules/typescript/lib&quot;&lt;/code&gt; to
&lt;code&gt;.vscode/settings.json&lt;/code&gt; and should be committed to the repository, so that the
entire team can benefit from it.&lt;/p&gt;
&lt;p&gt;You can also add the setting to your own VSCode &lt;strong&gt;User Settings&lt;/strong&gt;, so that this
applies to any instance of VSCode you open:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;typescript.tsdk&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;node_modules/typescript/lib&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;typescript.enablePromptUseWorkspaceTsdk&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;true,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;quot;typescript.tsdk&amp;quot;: &amp;quot;node_modules/typescript/lib&amp;quot;,&amp;quot;typescript.enablePromptUseWorkspaceTsdk&amp;quot;: true,&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now the project is in charge (not the editor), no more confusing differences 🙌.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Don’t forget to check with your team before pushing the &lt;code&gt;.vscode&lt;/code&gt;
folder to the repository, because if someone is already using a
&lt;code&gt;.vscode/settings.json&lt;/code&gt; file locally, this will cause conflicts. Unfortunately,
at the moment of writing, it’s still not possible to &lt;a href=&quot;https://github.com/microsoft/vscode/issues/15909&quot;&gt;extend
settings&lt;/a&gt;. Alternatively, you
can push a &lt;code&gt;.vscode/settings.json.default&lt;/code&gt; to serve as reference, similar to
what it’s done with &lt;code&gt;env.default&lt;/code&gt; or &lt;code&gt;env.sample&lt;/code&gt;, for example.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Vue Router Navigation Guards</title><link>https://ramigs.dev/blog/vue-router-navigation-guards/</link><guid isPermaLink="true">https://ramigs.dev/blog/vue-router-navigation-guards/</guid><description>How to hook into Vue&apos;s route navigation process</description><pubDate>Thu, 30 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about &lt;a href=&quot;https://router.vuejs.org/guide/advanced/navigation-guards.html&quot;&gt;Vue Router’s Navigation
Guards&lt;/a&gt;, which
allow us to hook into the navigation process.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;beforeRouteLeave&lt;/code&gt; can be especially useful for alerting user about
unsaved changes in a form and preventing accidental/undesired navigation.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] yarn link</title><link>https://ramigs.dev/blog/yarn-link/</link><guid isPermaLink="true">https://ramigs.dev/blog/yarn-link/</guid><description>A use case for yarn link</description><pubDate>Tue, 31 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about &lt;code&gt;yarn link&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Very useful for local development. The
&lt;a href=&quot;https://classic.yarnpkg.com/lang/en/docs/cli/link/&quot;&gt;documentation&lt;/a&gt; says it
best:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“For development, a package can be linked into another project. This is often
useful to test out new features or when trying to debug an issue in a package
that manifests itself in another project.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you’re done, don’t forget to run &lt;code&gt;yarn unlink&lt;/code&gt; on the &lt;em&gt;child&lt;/em&gt; package (to
remove all symlinks) and &lt;code&gt;yarn install --force&lt;/code&gt; on the &lt;em&gt;parent&lt;/em&gt; project (to
force the re-installation of dependencies and use the package from the project’s
&lt;code&gt;node_modules&lt;/code&gt; folder again).&lt;/p&gt;
</content:encoded></item><item><title>[TIL] git: interactive rebase</title><link>https://ramigs.dev/blog/git-interactive-rebase/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-interactive-rebase/</guid><description>git: how to interactive rebase</description><pubDate>Sat, 14 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Thanks P for sharing this.&lt;/p&gt;
&lt;p&gt;Often referred to as the “Swiss Army Knife of Git”, in broad terms, interactive
rebase is used to rewrite the commit history (such as edit, delete, and squash).&lt;/p&gt;
&lt;p&gt;In our case, we needed to delete some commits in &lt;code&gt;feature-branch-B&lt;/code&gt;, which were
originally brought over from &lt;code&gt;feature-branch-A&lt;/code&gt;. &lt;code&gt;feature-branch-A&lt;/code&gt; ended up
being discarded, and now we needed to delete those commits, so that they
wouldn’t be included when merging &lt;code&gt;feature-branch-B&lt;/code&gt; to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;TIL how to perform a &lt;code&gt;git&lt;/code&gt; interactive rebase:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure &lt;code&gt;main&lt;/code&gt; is updated&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout feature-branch-B&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git rebase -i main&lt;/code&gt;: editor pops up with all commits listed: remove the
lines (representing commits) you don’t want (or squash them, change commit
message, etc.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin +feature-branch-B&lt;/code&gt; to force push the new shiny commit history&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[TIL] The importance of font smoothing in WebKit and Firefox</title><link>https://ramigs.dev/blog/the-importance-of-font-smoothing-in-webkit-and-firefox/</link><guid isPermaLink="true">https://ramigs.dev/blog/the-importance-of-font-smoothing-in-webkit-and-firefox/</guid><description>CSS font smoothing makes a difference on macOS</description><pubDate>Wed, 27 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that the following CSS font smoothing rules, really make a difference on
Apple OSs (Firefox and WebKit-based browsers):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-webkit-font-smoothing&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;antialiased&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-moz-osx-font-smoothing&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;grayscale&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;body {  -webkit-font-smoothing: antialiased;  -moz-osx-font-smoothing: grayscale;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Take a look at the difference with and without
&lt;a href=&quot;https://davidwalsh.name/font-smoothing&quot;&gt;here&lt;/a&gt; and
&lt;a href=&quot;https://tailwindcss.com/docs/font-smoothing&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even though there are some &lt;a href=&quot;https://ui.dev/rwd/articles/font-smoothing&quot;&gt;arguments against
it&lt;/a&gt; I still think the pros outweigh
the cons, so better to set these rules.&lt;/p&gt;
</content:encoded></item><item><title>[BOOKMARK] A CSS reset for 2023</title><link>https://ramigs.dev/blog/a-css-reset-for-2023/</link><guid isPermaLink="true">https://ramigs.dev/blog/a-css-reset-for-2023/</guid><description>A modern CSS reset for 2023</description><pubDate>Sun, 24 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Came across the recent blog post &lt;a href=&quot;https://andy-bell.co.uk/a-more-modern-css-reset/&quot;&gt;A (more) Modern CSS
Reset&lt;/a&gt; by &lt;a href=&quot;https://andy-bell.co.uk/&quot;&gt;Andy
Bell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It includes a set of CSS rules with sensible declarations for reducing browser
inconsistencies.&lt;/p&gt;
&lt;p&gt;Really like that it’s quite comprehensive (without being huge), as well as the
author’s breakdown of each rule. Will consider using it (at least as a starting)
in my future projects.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Nuxt 2: nuxt generate fails silently and how to avoid it</title><link>https://ramigs.dev/blog/nuxt2-generate-fails-silently-and-how-to-avoid-it/</link><guid isPermaLink="true">https://ramigs.dev/blog/nuxt2-generate-fails-silently-and-how-to-avoid-it/</guid><description>Nuxt 2: How to force generate command to exit with non-0 code on errors</description><pubDate>Tue, 19 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that in Nuxt 2, command &lt;code&gt;nuxt generate&lt;/code&gt; as is, exits with code 0 (success)
when errors are thrown during the execution (potentially skipping the generation
of routes where error is manifesting).&lt;/p&gt;
&lt;p&gt;To avoid unexpected issues, specially in production deploy pipelines, use flag
&lt;code&gt;--fail-on-error&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] iTerm2: click filename to open in VSCode</title><link>https://ramigs.dev/blog/iterm2-click-filename-to-open-in-vscode/</link><guid isPermaLink="true">https://ramigs.dev/blog/iterm2-click-filename-to-open-in-vscode/</guid><description>How to click filename in iTerm2 and have it open in VSCode</description><pubDate>Tue, 12 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible to ⌘-click a file in iTerm2 and have it open in VSCode.&lt;/p&gt;
&lt;p&gt;To enable, open &lt;strong&gt;Preferences -&amp;gt; Profiles -&amp;gt; Advanced -&amp;gt; Semantic History&lt;/strong&gt; and
select options &lt;code&gt;Open with editor...&lt;/code&gt; and &lt;code&gt;VS Code&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] git: how to merge a remote branch locally</title><link>https://ramigs.dev/blog/git-how-to-merge-a-remote-branch-locally/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-how-to-merge-a-remote-branch-locally/</guid><description>git: how to merge a remote branch locally</description><pubDate>Thu, 17 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to how to merge a remote branch (for example &lt;code&gt;main&lt;/code&gt;) locally, which may
be useful for when you’re working on a feature branch, &lt;code&gt;main&lt;/code&gt; has been updated,
and you’d like to include those updates in your branch:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;git fetch origin main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;git checkout a-local-branch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;git merge origin/main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;git push origin a-local-branch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git fetch origin maingit checkout a-local-branchgit merge origin/maingit push origin a-local-branch&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] Firefox DevTools: request duration</title><link>https://ramigs.dev/blog/firefox-devtools-request-duration/</link><guid isPermaLink="true">https://ramigs.dev/blog/firefox-devtools-request-duration/</guid><description>How to find out the duration of requests in Firefox Developer Tools</description><pubDate>Sun, 11 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to check the duration of a request (time from start of the request until
the end of the respective response) in Firefox DevTools.&lt;/p&gt;
&lt;p&gt;It can be specially helpful for performance analysis.&lt;/p&gt;
&lt;p&gt;To display the Duration column in the network table toolbar, open up DevTools,
select the Network tab, right-click the request table header (any column), and
select &lt;strong&gt;Timings -&amp;gt; Duration&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Request Duration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1566&quot; height=&quot;1016&quot; src=&quot;https://ramigs.dev/_astro/2023-06-11-request-duration.BYCYdMF0_tn9sq.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Learn more about the &lt;a href=&quot;https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/request_list/index.html#network-request-list&quot;&gt;Network request
list&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] VSCode: configure auto format on save</title><link>https://ramigs.dev/blog/vscode-configure-auto-format-on-save/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-configure-auto-format-on-save/</guid><description>Project settings to enable auto format on save in VSCode</description><pubDate>Sun, 11 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about VSCode project configurations to enable auto format on save.&lt;/p&gt;
&lt;p&gt;This can be specially helpful in team projects configured with &lt;code&gt;eslint&lt;/code&gt; and
&lt;code&gt;prettier&lt;/code&gt;, where you’re interested in enforcing code conventions and standards.&lt;/p&gt;
&lt;p&gt;From the project root, create a &lt;code&gt;.vscode/settings.json&lt;/code&gt; file with the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.formatOnSave&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.codeActionsOnSave&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;source.fixAll.eslint&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.defaultFormatter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;esbenp.prettier-vscode&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;editor.formatOnSave&amp;quot;: true,  &amp;quot;editor.codeActionsOnSave&amp;quot;: {    &amp;quot;source.fixAll.eslint&amp;quot;: true  },  &amp;quot;editor.defaultFormatter&amp;quot;: &amp;quot;esbenp.prettier-vscode&amp;quot;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When a project contributor checks out the project and is using VSCode (with
&lt;code&gt;eslint&lt;/code&gt; and &lt;code&gt;prettier&lt;/code&gt; plugins installed) auto format on save will be enabled,
based on the &lt;code&gt;eslint&lt;/code&gt; and &lt;code&gt;prettier&lt;/code&gt; rules configured.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Firefox DevTools: how to persist logs on page navigation</title><link>https://ramigs.dev/blog/firefox-devtools-persist-logs-on-page-navigation/</link><guid isPermaLink="true">https://ramigs.dev/blog/firefox-devtools-persist-logs-on-page-navigation/</guid><description>How to persist Web Console and Network Monitor logs in Firefox Developer Tools upon page navigation and page reload</description><pubDate>Sat, 10 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about a Firefox DevTools option, which allows to specify whether the request
list and logs should be cleared or not on page navigation (or page reload).&lt;/p&gt;
&lt;p&gt;It can be specially helpful while developing/troubleshooting.&lt;/p&gt;
&lt;p&gt;The default is for requests and logs to be cleared, so to instead have them
persist, open up DevTools, click the settings cog wheel, and select &lt;strong&gt;Persist
Logs&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Persist Logs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1225&quot; height=&quot;539&quot; src=&quot;https://ramigs.dev/_astro/2023-06-10-persist-logs.CT6oxqCu_c6IVi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>[TIL] JavaScript: directly chaining catch handler to await expression</title><link>https://ramigs.dev/blog/javascript-chaining-catch-handler-to-await-expression/</link><guid isPermaLink="true">https://ramigs.dev/blog/javascript-chaining-catch-handler-to-await-expression/</guid><description>JavaScript: chaining catch handler to await expression, outside of try/catch block</description><pubDate>Fri, 19 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible in JavaScript to directly chain a &lt;code&gt;catch&lt;/code&gt; handler to an
&lt;code&gt;await&lt;/code&gt; expression:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;fetchProfile&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;handleFetchProfileError&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(e));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;await fetchProfile().catch((e) =&gt; handleFetchProfileError(e));&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that this can be done outside (and without requiring) a &lt;code&gt;try/catch&lt;/code&gt; block.&lt;/p&gt;
&lt;p&gt;This can be specially useful when you’d want the execution to continue and/or
treat the &lt;code&gt;await&lt;/code&gt; expression individually (i.e., not only one single &lt;code&gt;catch&lt;/code&gt; for
a block of code).&lt;/p&gt;
&lt;p&gt;Many thanks to all contributors in &lt;a href=&quot;https://stackoverflow.com/questions/44663864/correct-try-catch-syntax-using-async-await&quot;&gt;this Stack Overflow
thread&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Responsive HTML element without media queries</title><link>https://ramigs.dev/blog/responsive-html-element-without-media-queries/</link><guid isPermaLink="true">https://ramigs.dev/blog/responsive-html-element-without-media-queries/</guid><description>CSS: how to make an HTML element responsive without the need for media queries</description><pubDate>Fri, 19 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible in CSS to make an HTML responsive (automatically adapt to
screen width), without having to use media queries:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;outside-container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;responsive-element&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;I&apos;m a paragraph!&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;div class=&amp;quot;outside-container&amp;quot;&gt;  &lt;div class=&amp;quot;responsive-element&amp;quot;&gt;    &lt;p&gt;I&amp;#x27;m a paragraph!&lt;/p&gt;  &lt;/div&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.outside-container&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;border&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;solid&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;blue&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.responsive-element&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;border&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;solid&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;red&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;max-width&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;580&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;.outside-container {  border: 1px solid blue;}.responsive-element {  border: 1px solid red;  width: 100%;  max-width: 580px;  margin: auto;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is achieved with the combination of &lt;code&gt;width: 100%;&lt;/code&gt; and &lt;code&gt;max-width: 580px;&lt;/code&gt;,
where we’re saying “width be 100% of the parent’s width, but never exceed
580px”. Notice how the element with red border adapts when screen width changes:&lt;/p&gt;
&lt;style&gt;
.outside-container {
  margin-bottom: 2rem;
  border: 1px solid blue;
}

.responsive-element {
  border: 1px solid red;
  width: 100%;
  max-width: 580px;
  margin: auto;
}
&lt;/style&gt;
&lt;div class=&quot;outside-container&quot;&gt;
  &lt;div class=&quot;responsive-element&quot;&gt;
    &lt;p&gt;I&apos;m a paragraph!&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Many thanks to &lt;a href=&quot;https://twitter.com/Ali_Developer05&quot;&gt;@Ali_Developer05&lt;/a&gt; for the
&lt;a href=&quot;https://twitter.com/Ali_Developer05/status/1658759323651305472&quot;&gt;tweet&lt;/a&gt; where I
got this tip from, and which I’ve been able to use at work the very next day.&lt;/p&gt;
</content:encoded></item><item><title>VSCode: Vue 2 or Vue 3 extensions per project</title><link>https://ramigs.dev/blog/vscode-how-to-configure-extensions-vue-2-or-vue-3/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-how-to-configure-extensions-vue-2-or-vue-3/</guid><description>VSCode: How to configure extensions for Vue 2 or Vue 3 per project</description><pubDate>Mon, 08 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Up until Vue 2, &lt;a href=&quot;https://github.com/vuejs/vetur&quot;&gt;Vetur&lt;/a&gt; has been the recommended
VScode extension for Vue support.&lt;/p&gt;
&lt;p&gt;Since the release of Vue 3 (which introduces first-class TypeScript support),
the &lt;a href=&quot;https://vuejs.org/guide/typescript/overview.html#ide-support&quot;&gt;official
recommendation&lt;/a&gt; is
to use &lt;a href=&quot;https://github.com/vuejs/language-tools&quot;&gt;Volar/Vue Language Tools&lt;/a&gt;
instead.&lt;/p&gt;
&lt;p&gt;I’m currently working on multiple Vue.js projects (some Vue 2, some Vue 3),
using the same VSCode installation.&lt;/p&gt;
&lt;p&gt;As recommend, tried uninstalling Vetur and using Volar instead in some of the
Vue 2 projects, but faced some (apparently) minor issues, such as &lt;a href=&quot;https://github.com/vuejs/language-tools/issues/2576&quot;&gt;this
one&lt;/a&gt;, for example.&lt;/p&gt;
&lt;p&gt;Since fixes to such issues required updates in the code (which could impact my
colleagues’ dev environments), and having nothing to complain about Vetur, I’ve
decided to keep using Vetur for Vue 2 projects.&lt;/p&gt;
&lt;p&gt;To do so, I have both extensions installed globally, and disabled on a
project-by-project basis accordingly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if project is Vue 2, disable Volar in the project’s (current) workspace.&lt;/li&gt;
&lt;li&gt;if project is Vue 3, disable Vetur in the project’s (current) workspace.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Credit goes to &lt;a href=&quot;https://stackoverflow.com/questions/71268372/is-there-a-way-to-toggle-vs-code-extensions-per-project&quot;&gt;this Stack Overflow answer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; also noticed that for ESLint to work properly, Vue 2 projects needed
the VSCode ESLint extension pinned to version &lt;code&gt;2.4.2&lt;/code&gt;, while Vue 3 projects work
fine with the up-to-date &lt;code&gt;3.0.10&lt;/code&gt;. Since a single VSCode installation can’t have
two versions of the same extension active at once, I achieved this using
separate &lt;a href=&quot;https://code.visualstudio.com/docs/editor/profiles&quot;&gt;VSCode profiles&lt;/a&gt;,
one per Vue version, each with its own pinned ESLint version.&lt;/p&gt;
&lt;p&gt;Vetur itself is also pinned, at &lt;code&gt;0.37.3&lt;/code&gt;, since it’s the legacy Vue 2
language-tooling extension and hasn’t seen further releases.&lt;/p&gt;
&lt;p&gt;Also, for Vetur to actually handle formatting in Vue 2 projects, I had to set it
as the default formatter for &lt;code&gt;.vue&lt;/code&gt; files in my &lt;code&gt;settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;[vue]&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.defaultFormatter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;octref.vetur&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;quot;[vue]&amp;quot;: {  &amp;quot;editor.defaultFormatter&amp;quot;: &amp;quot;octref.vetur&amp;quot;,},&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;On the Vue 3 projects, formatting was instead handled by Prettier, configured
in each project’s &lt;code&gt;.vscode/settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.codeActionsOnSave&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;source.fixAll&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;explicit&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.formatOnSave&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.defaultFormatter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;esbenp.prettier-vscode&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;[vue]&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;editor.defaultFormatter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;esbenp.prettier-vscode&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;editor.codeActionsOnSave&amp;quot;: {    &amp;quot;source.fixAll&amp;quot;: &amp;quot;explicit&amp;quot;  },  &amp;quot;editor.formatOnSave&amp;quot;: true,  &amp;quot;editor.defaultFormatter&amp;quot;: &amp;quot;esbenp.prettier-vscode&amp;quot;,  &amp;quot;[vue]&amp;quot;: {    &amp;quot;editor.defaultFormatter&amp;quot;: &amp;quot;esbenp.prettier-vscode&amp;quot;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;There are probably better ways to handle this, with a more intentional
separation of VSCode profiles and extensions per Vue version, but this is how I
was able to get it working. I’m happy I no longer need to support Vue 2
projects, and I’m writing this down mostly so I can come back to it in case
another Vue 2 project lands on my lap.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] JavaScript: renaming variables during object destructuring</title><link>https://ramigs.dev/blog/javascript-renaming-variables-during-object-destructuring/</link><guid isPermaLink="true">https://ramigs.dev/blog/javascript-renaming-variables-during-object-destructuring/</guid><description>JavaSctipt: how to rename variables when doing destructuring an object</description><pubDate>Tue, 02 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible in JavaScript to rename variables at the moment of destructuring.&lt;/p&gt;
&lt;p&gt;Let’s say you have an object &lt;code&gt;user&lt;/code&gt;, previously fetched from an API, with &lt;code&gt;snake_case&lt;/code&gt;
property names.&lt;/p&gt;
&lt;p&gt;However, you’d like variable names to be in &lt;code&gt;lowerCamelCase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can do the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;userId&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; user;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const { user_id: userId, age } = user;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Variable name is now &lt;code&gt;userId&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] TypeScript type predicates</title><link>https://ramigs.dev/blog/typescript-type-predicates/</link><guid isPermaLink="true">https://ramigs.dev/blog/typescript-type-predicates/</guid><description>Type narrowing in TypeScript using type predicates</description><pubDate>Fri, 28 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Type narrowing is the process by which a type is refined to a more specific
type.&lt;/p&gt;
&lt;p&gt;The TypeScript compiler does its best to narrow types using the existing
JavaScript code.&lt;/p&gt;
&lt;p&gt;TIL about TypeScript type predicates, a way to be more explicit and have better
control over type inference.&lt;/p&gt;
&lt;p&gt;First, we define a function whose return type is a type predicate:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;isAudio&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Audio&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Audio&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (content &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Audio&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).duration &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function isAudio(content: Audio | Text): content is Audio {  return (content as Audio).duration !== undefined;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We can now use &lt;code&gt;isAudio&lt;/code&gt; to narrow the type of a variable we’re working with,
allowing TypeScript from that point on to &lt;em&gt;know&lt;/em&gt; the more specific type:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; content &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;getContent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;isAudio&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(content)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;content.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;play&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;content.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let content = getContent();if (isAudio(content)) {  content.play();} else {  content.render();}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/narrowing.html&quot;&gt;Narrowing - TypeScript
documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates&quot;&gt;Type predicates - TypeScript
documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>GitHub Actions: how to skip PR status checks based on changed files</title><link>https://ramigs.dev/blog/github-actions-how-to-skip-pr-status-checks-based-on-changed-files/</link><guid isPermaLink="true">https://ramigs.dev/blog/github-actions-how-to-skip-pr-status-checks-based-on-changed-files/</guid><description>GitHub Actions: how to conditionally status checks in PRs based on changed files</description><pubDate>Mon, 24 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s say you have a &lt;code&gt;pull_request&lt;/code&gt; GitHub Action workflow that runs unit tests
and end-to-end tests on every PR that targets branch &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Test pipeline&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;pull_request&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;branches&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;run-unit-tests&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;runs-on&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;steps&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;run-browser-tests&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;runs-on&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;steps&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;name: Test pipelineon:  pull_request:    branches: [main]jobs:  run-unit-tests:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v3  run-browser-tests:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is a valuable software development practice, because tests (assuming they
are well designed and providing reasonable coverage) are running automatically
on every PR, offering immediate feedback to developers about whether changes
being included are breaking something or not.&lt;/p&gt;
&lt;p&gt;You may have also opted to configure a branch protection rule for &lt;code&gt;main&lt;/code&gt;,
requiring status checks (in this case, tests) to pass before merging is allowed:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Require status checks&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1612&quot; height=&quot;847&quot; src=&quot;https://ramigs.dev/_astro/2023-04-24-require-status-checks.DQ5v0vxy_oNgkR.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;By using this configuration, the workflow’s jobs will be executed and reported
in the pull request (visible in the &lt;strong&gt;Checks&lt;/strong&gt; tab and near the merge button):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;PR checks&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1895&quot; height=&quot;355&quot; src=&quot;https://ramigs.dev/_astro/2023-04-24-pr-checks.BlBzNwUI_IT56W.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The downside of this setup is that tests will have to run and pass on each and
every PR, even when changed files are not source code (such as &lt;code&gt;README&lt;/code&gt; updates
and documentation contributions).&lt;/p&gt;
&lt;p&gt;In such cases, couldn’t the test executions be skipped, providing the ability to
immediately merge the PR and spare (potentially billable) workflow execution
time?&lt;/p&gt;
&lt;p&gt;Let’s see how we can achieve this!&lt;/p&gt;
&lt;p&gt;First, let’s make use of
&lt;a href=&quot;https://github.com/tj-actions/changed-files&quot;&gt;tj-actions/changed-files&lt;/a&gt; and add
a new step in each job to get the list of changed files (excluding markdown
files):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;run-unit-tests&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;runs-on&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;steps&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Get all changed file(s), excluding the docs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;changed-files-excluded&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;tj-actions/changed-files@v35&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;files_ignore&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;**/*.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;jobs:  run-unit-tests:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v3      - name: Get all changed file(s), excluding the docs        id: changed-files-excluded        uses: tj-actions/changed-files@v35        with:          files_ignore: |            **/*.md&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The output of this step can now be used in subsequent steps, so that they are
executed only if changed files are not markdown:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;actions/setup-node@v3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;steps.changed-files-excluded.outputs.any_changed == &apos;true&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;node-version&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;16.x&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;- uses: actions/setup-node@v3  if: steps.changed-files-excluded.outputs.any_changed == &amp;#x27;true&amp;#x27;  with:    node-version: &amp;quot;16.x&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this way, jobs will still execute with a &lt;code&gt;success&lt;/code&gt; status (which is needed
for PR checks), with individual steps themselves being skipped.&lt;/p&gt;
&lt;p&gt;Please note that the setup above can probably be optimized to not require &lt;code&gt;if&lt;/code&gt;
to be included in all subsequent steps, but instead immediately interrupt the
job and &lt;code&gt;exit&lt;/code&gt; with status &lt;code&gt;0&lt;/code&gt; (no errors).&lt;/p&gt;
&lt;p&gt;Also note that there are most likely other ways to achieve this outcome, such as
for example using
&lt;a href=&quot;https://github.com/fkirc/skip-duplicate-actions&quot;&gt;fkirc/skip-duplicate-actions&lt;/a&gt;,
but I have not explored them in detail.&lt;/p&gt;
&lt;p&gt;Also note that in case you have status checks configured like we do in this
example, in order to achieve this outcome, the intervention will have to be at
the job-level (and not workflow-level).&lt;/p&gt;
</content:encoded></item><item><title>How to fix deprecated GitHub Action chrisdickinson/setup-yq</title><link>https://ramigs.dev/blog/how-to-fix-deprecated-github-action-chrisdickinson-setup-yq/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-fix-deprecated-github-action-chrisdickinson-setup-yq/</guid><description>How to fix deprecated Node.js 12 GitHub Action chrisdickinson/setup-yq</description><pubDate>Fri, 07 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Node.js 12 actions are currently being deprecated on GitHub Actions.&lt;/p&gt;
&lt;p&gt;If you’re using
&lt;a href=&quot;https://github.com/chrisdickinson/setup-yq&quot;&gt;&lt;code&gt;chrisdickinson/setup-yq&lt;/code&gt;&lt;/a&gt; you’re
probably encountering the following warning:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;Node.js 12 actions are deprecated.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;Please update the following actions to use Node.js 16: chrisdickinson/setup-yq@latest.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Node.js 12 actions are deprecated.Please update the following actions to use Node.js 16: chrisdickinson/setup-yq@latest.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Since this project has not been updated to use Node 16, in order to fix do the
following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;remove usage of &lt;code&gt;chrisdickinson/setup-yq@latest&lt;/code&gt;, it’s no longer needed as
&lt;code&gt;yq&lt;/code&gt; is now part of &lt;code&gt;ubuntu-latest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(if needed) update usage of command &lt;code&gt;yq&lt;/code&gt; because it works &lt;a href=&quot;https://mikefarah.gitbook.io/yq/upgrading-from-v3&quot;&gt;in a different
way&lt;/a&gt; on v4 (action uses v3)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] How to help browsers offer appropriate form autofill options</title><link>https://ramigs.dev/blog/how-to-help-browsers-offer-appropriate-autofill/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-help-browsers-offer-appropriate-autofill/</guid><description>[TIL] How to help browsers offer automated assistance in filling out forms</description><pubDate>Fri, 07 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about HTML attribute &lt;code&gt;autocomplete&lt;/code&gt;, which allows to specify user
agent/browser permissions for providing automated assistance in filling out
forms (such as login credentials and credit card details), as well as guidance
on the type of information expected in the respective form fields.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/learn/forms/autofill/&quot;&gt;Learn all about autofill and the autocomplete
attribute.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/&quot;&gt;HTML attribute:
autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] VSCode setup for Nunjucks</title><link>https://ramigs.dev/blog/vscode-setup-for-nunjucks/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-setup-for-nunjucks/</guid><description>Setting up VSCode for better developer experience using Nunjucks</description><pubDate>Tue, 14 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to setup VSCode for a better developer experience using Nunjucks.&lt;/p&gt;
&lt;p&gt;Useful VSCode extensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ronnidc.nunjucks&quot;&gt;&lt;code&gt;ronnidc.nunjucks&lt;/code&gt;&lt;/a&gt;,
for syntax highlighting;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=okitavera.vscode-nunjucks-formatter&quot;&gt;&lt;code&gt;okitavera.vscode-nunjucks-formatter&lt;/code&gt;&lt;/a&gt;,
for template formatting;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=eseom.nunjucks-template&quot;&gt;&lt;code&gt;eseom.nunjucks-template&lt;/code&gt;&lt;/a&gt;,
for template syntax, template formatting, and snippets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, don’t forget &lt;a href=&quot;https://11ty.rocks/tips/vscode/#extend-emmet-for-nunjucks&quot;&gt;to enable Emmet for
Nunjucks&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hyunbinseo.medium.com/nunjucks-settings-for-vs-code-a0da0dc66b95&quot;&gt;Nunjucks Settings for VS Code -
Hyunbin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://11ty.rocks/tips/vscode/&quot;&gt;VSCode Settings - 11ty Rocks!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] just: command runner</title><link>https://ramigs.dev/blog/just-command-runner/</link><guid isPermaLink="true">https://ramigs.dev/blog/just-command-runner/</guid><description>Using just command runner for Node.js projects</description><pubDate>Thu, 09 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about command runner &lt;code&gt;just&lt;/code&gt;, which can be used as an alternative to &lt;code&gt;npm&lt;/code&gt; scripts.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/casey/just&quot;&gt;https://github.com/casey/just&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://just.systems/man/en/&quot;&gt;https://just.systems/man/en/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] Vuex: how to commit a mutation for a specific namespaced module</title><link>https://ramigs.dev/blog/vuex-how-to-commit-mutation-namespaced-module/</link><guid isPermaLink="true">https://ramigs.dev/blog/vuex-how-to-commit-mutation-namespaced-module/</guid><description>Vuex: how to commit a mutation for a specific namespaced module</description><pubDate>Thu, 09 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to execute a Vuex mutation inside a namespaced module, from object &lt;code&gt;Store&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This can be particularly useful to initialize state when using &lt;code&gt;jest&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;createStore&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;store.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;commit&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;AuthModule/setInitialData&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, initialData);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const store = createStore();store.commit(&amp;quot;AuthModule/setInitialData&amp;quot;, initialData);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] Useful k3d and kubectl commands</title><link>https://ramigs.dev/blog/useful-k3d-and-kubectl-commands/</link><guid isPermaLink="true">https://ramigs.dev/blog/useful-k3d-and-kubectl-commands/</guid><description>Listing some useful k3d and kubectl commands I&apos;ve been using lately</description><pubDate>Sat, 29 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Listing some useful &lt;a href=&quot;https://k3d.io/&quot;&gt;k3d&lt;/a&gt; and &lt;code&gt;kubectl&lt;/code&gt; commands I’ve been using lately.&lt;/p&gt;
&lt;h2 id=&quot;k3d&quot;&gt;k3d&lt;/h2&gt;
&lt;h3 id=&quot;create-cluster&quot;&gt;Create cluster&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-cluster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;k3d cluster create my-cluster&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;create-cluster-with-load-balancer-and-respective-port-binding-useful-for-testing-locally&quot;&gt;Create cluster with load balancer and respective port binding (useful for testing locally)&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;80:30000@loadbalancer&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;k3d cluster create my-cluster -p &amp;quot;80:30000@loadbalancer&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;create-cluster-without-load-balancer&quot;&gt;Create cluster without load balancer&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--no-lb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;k3d cluster create --no-lb&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;create-cluster-with-specified-number-of-control-planes-and-worker-nodes&quot;&gt;Create cluster with specified number of control planes and worker nodes&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--servers&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--agents&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;k3d cluster create my-cluster --servers 3 --agents 3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;list-clusters&quot;&gt;List clusters&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;k3d cluster list&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;delete-cluster&quot;&gt;Delete cluster&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cluster&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;k3d cluster list&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;kubectl&quot;&gt;kubectl&lt;/h2&gt;
&lt;h3 id=&quot;list-all-supported-resource-types-useful-to-know-which-version-to-use-when-writing-manifests&quot;&gt;List all supported resource types (useful to know which version to use when writing manifests)&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;api-resources&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl api-resources&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;get-list-of-nodes-in-the-cluster&quot;&gt;Get list of nodes in the cluster&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;nodes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl get nodes&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;apply-resources-specified-in-a-manifest-file&quot;&gt;Apply resources specified in a manifest file&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pod.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl apply -f pod.yaml&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;get-pods&quot;&gt;Get Pods&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pods&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl get pods&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;get-pod-details-useful-to-know-which-image-tagversion-is-running&quot;&gt;Get Pod details (useful to know which image tag/version is running)&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pod&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;my-pod&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl describe pod my-pod&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;port-bind-pod-port-to-localhost-port&quot;&gt;Port bind Pod port to localhost port&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;port-forward&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pod/conversao-temperatura&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;8080:8080&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl port-forward pod/conversao-temperatura 8080:8080&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;delete-pod&quot;&gt;Delete Pod&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pod&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;conversao-temperatura&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl delete pod conversao-temperatura&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;delete-resources-specified-in-a-manifest-file&quot;&gt;Delete resources specified in a manifest file&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pod.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl delete -f pod.yaml&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] Useful terraform commands</title><link>https://ramigs.dev/blog/useful-terraform-commands/</link><guid isPermaLink="true">https://ramigs.dev/blog/useful-terraform-commands/</guid><description>Listing some useful terraform commands I&apos;ve been using lately</description><pubDate>Sat, 29 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Listing some useful &lt;a href=&quot;https://www.terraform.io/&quot;&gt;Terraform&lt;/a&gt; commands I’ve been using lately.&lt;/p&gt;
&lt;h3 id=&quot;initialize-a-working-directory&quot;&gt;Initialize a working directory&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;init&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform init&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;create-an-execution-plan-with-preview&quot;&gt;Create an execution plan with preview&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;plan&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform plan&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;execute-actions-proposed-in-a-plan&quot;&gt;Execute actions proposed in a plan&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;apply&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform apply&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;format-configuration-files-into-a-canonical-format-and-style&quot;&gt;Format configuration files into a canonical format and style&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;fmt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform fmt&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;More about &lt;a href=&quot;https://spacelift.io/blog/terraform-fmt&quot;&gt;terraform
fmt&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;extract-the-value-of-an-output-variable-from-the-state-file&quot;&gt;Extract the value of an output variable from the state file&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;output&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform output&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;destroy-all-remote-objects-managed-by-a-particular-configuration&quot;&gt;Destroy all remote objects managed by a particular configuration&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;destroy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform destroy&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;More about &lt;a href=&quot;https://spacelift.io/blog/how-to-destroy-terraform-resources&quot;&gt;terraform
destroy&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] TypeScript: How to define a type for objects with dynamic properties</title><link>https://ramigs.dev/blog/typescript-how-to-define-type-for-objects-with-dynamic-properties/</link><guid isPermaLink="true">https://ramigs.dev/blog/typescript-how-to-define-type-for-objects-with-dynamic-properties/</guid><description>TypeScript: How to define a type for objects with dynamic properties</description><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to define a type for objects with dynamic properties. By this we mean an
object that can have any number of properties, with unknown property names and
values. However, we know what their &lt;strong&gt;types&lt;/strong&gt; should be.&lt;/p&gt;
&lt;p&gt;Let’s take a look at an example to make this clearer.&lt;/p&gt;
&lt;p&gt;Let’s say we want to create a type to represent dictionary objects such as:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;dictionary&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;hello: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;olá&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;goodbye: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;adeus&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const dictionary = {  hello: &amp;quot;olá&amp;quot;,  goodbye: &amp;quot;adeus&amp;quot;,};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this case, we want TypeScript to help us enforce that both property name and
property value are of type &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;Record&amp;lt;Keys, Type&amp;gt;&lt;/code&gt; utility type, like so:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;MyDictionary&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Record&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;dictionary&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;MyDictionary&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type MyDictionary = Record&lt;string, string&gt;;const dictionary: MyDictionary = {};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, if we try to set something like the following, TypeScript will signal an
error and stop us:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Type &apos;number&apos; is not assignable to type &apos;string&apos;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;dictionary.one &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// Type &amp;#x27;number&amp;#x27; is not assignable to type &amp;#x27;string&amp;#x27;.dictionary.one = 1;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Record&amp;lt;Keys, Type&amp;gt;&lt;/code&gt; utility type is a name alias for &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures&quot;&gt;index
signatures&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;MyDictionary&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;k&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type MyDictionary = { [k: string]: string };&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;See:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type&quot;&gt;Record&amp;lt;Keys, Type&amp;gt; - TypeScript documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bobbyhadz.com/blog/typescript-object-with-dynamic-keys&quot;&gt;Define a Type for Object with Dynamic keys in TypeScript - Borislav Hadzhiev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] Cypress: How to run only one test inside a spec file</title><link>https://ramigs.dev/blog/cypress-how-to-run-only-one-test-inside-a-spec-file/</link><guid isPermaLink="true">https://ramigs.dev/blog/cypress-how-to-run-only-one-test-inside-a-spec-file/</guid><description>Cypress: How to run only one test inside a spec file to improve efficiency when creating tests</description><pubDate>Fri, 26 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL a Cypress tip that can help improve efficiency when creating tests.&lt;/p&gt;
&lt;p&gt;Let’s say you have a spec file with several tests. To avoid having to execute
all the tests in the file, you can temporarily use &lt;code&gt;it.only(&lt;/code&gt;, instead of &lt;code&gt;it(&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Don’t forget to revert the change when you’re done, otherwise the other tests
will not execute when they should (e.g., in a pipeline execution).&lt;/p&gt;
&lt;p&gt;See more details in the
&lt;a href=&quot;https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests.html#Excluding-and-Including-Tests&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Useful AWS CLI commands for S3 and CloudFront</title><link>https://ramigs.dev/blog/useful-aws-cli-commands-for-s3-and-cloudfront/</link><guid isPermaLink="true">https://ramigs.dev/blog/useful-aws-cli-commands-for-s3-and-cloudfront/</guid><description>Listing some useful commands I&apos;ve been using lately for AWS S3 and CloudFront</description><pubDate>Wed, 04 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Listing some useful commands I’ve been using lately for AWS S3 and CloudFront.&lt;/p&gt;
&lt;h2 id=&quot;amazon-s3&quot;&gt;Amazon S3&lt;/h2&gt;
&lt;h3 id=&quot;list-buckets&quot;&gt;List buckets&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;s3api&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;list-buckets&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3api list-buckets&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;get-bucket-regionlocation&quot;&gt;Get bucket region/location&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;s3api&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get-bucket-location&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--bucket&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cdn-dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3api get-bucket-location --bucket cdn-dev&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;upload-file&quot;&gt;Upload file&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;static/logo.png&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;s3://cdn-dev/logo.png&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3 cp static/logo.png s3://cdn-dev/logo.png&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;amazon-cloudfront&quot;&gt;Amazon CloudFront&lt;/h2&gt;
&lt;h3 id=&quot;get-distribution-id-list&quot;&gt;Get distribution id list&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cloudfront&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;list-distributions&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--output&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;DistributionList.Items[*].Id&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws cloudfront list-distributions --output table --query &amp;#x27;DistributionList.Items[*].Id&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;check-details-of-specific-distribution&quot;&gt;Check details of specific distribution&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cloudfront&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get-distribution&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;E2FXR8603J97N3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws cloudfront get-distribution --id E2FXR8603J97N3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;create-cache-invalidation&quot;&gt;Create cache invalidation&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cloudfront&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create-invalidation&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--distribution-id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;E2FXR8603J97N3&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--paths&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws cloudfront create-invalidation --distribution-id E2FXR8603J97N3 --paths &amp;quot;/*&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;check-status-of-cache-invalidation&quot;&gt;Check status of cache invalidation&lt;/h3&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;cloudfront&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get-invalidation&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;I23C6NJI4OQFFP&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--distribution-id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;E2FXR8603J97N3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws cloudfront get-invalidation --id I23C6NJI4OQFFP --distribution-id E2FXR8603J97N3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] VSCode: Editing files remotely over SSH</title><link>https://ramigs.dev/blog/vscode-editing-files-remotely-over-ssh/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-editing-files-remotely-over-ssh/</guid><description>How to access folders and files remotely on VSCode using SSH</description><pubDate>Mon, 18 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about this &lt;a href=&quot;https://code.visualstudio.com/docs/remote/ssh&quot;&gt;VScode extension&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It allows accessing and editing folder and files on any remote environment over
SSH.&lt;/p&gt;
&lt;p&gt;Even though this is a great productivity tool to have in my toolkit, it should
not serve as an excuse for not learning more in-depth either &lt;code&gt;nano&lt;/code&gt; or &lt;code&gt;vim&lt;/code&gt; 🤓.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] K8s: Difference between ingress controller and service mesh</title><link>https://ramigs.dev/blog/ingress-controller-vs-service-mesh/</link><guid isPermaLink="true">https://ramigs.dev/blog/ingress-controller-vs-service-mesh/</guid><description>Understanding the different roles played by ingress controller and service mesh in a K8s cluster</description><pubDate>Sun, 17 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about the difference between &lt;strong&gt;ingress controller&lt;/strong&gt; and &lt;strong&gt;service mesh&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The former is responsible for managing traffic that flows into the the
application (North-South traffic).&lt;/p&gt;
&lt;p&gt;The latter is used to mediate and secure service-to-service communication within
the cluster (East-West traffic).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Diagram of ingress controller and service mesh&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1196&quot; height=&quot;1043&quot; src=&quot;https://ramigs.dev/_astro/2022-04-17-ingress-controller-vs-service-mesh.CwDMpvvW_1FHNfd.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>[TIL] VSCode: How to save without auto formatting</title><link>https://ramigs.dev/blog/vscode-save-without-auto-formatting/</link><guid isPermaLink="true">https://ramigs.dev/blog/vscode-save-without-auto-formatting/</guid><description>How to save a file on VSCode without auto formatting</description><pubDate>Fri, 01 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to save a file on VSCode without auto formatting being applied: &lt;code&gt;CMD + K S&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This can be useful in situations where one is working in a repository and is not
interested in having a big file auto formatted, just for the sake of a trivial
change.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] JavaScript: How to update the URL without page reload</title><link>https://ramigs.dev/blog/how-to-update-url-without-page-reload/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-update-url-without-page-reload/</guid><description>How to programmatically set the URL in the URL bar without page reload</description><pubDate>Mon, 28 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that it’s possible to programmatically set the URL in the browser’s URL bar
without having the browser try to load it.&lt;/p&gt;
&lt;p&gt;This can be useful, for example in the context of a SPA, for updating the URL
when a certain component is rendered or after a certain user action takes place,
for analytics purposes (e.g., &lt;a href=&quot;https://varn.co.uk/11/13/how-to-track-pageviews-on-single-page-applications-using-google-tag-manager/&quot;&gt;Google Tag Manager requires this for the History
Change
trigger&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;window.history.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;replaceState&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/verified&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;window.history.replaceState(null, &amp;quot;&amp;quot;, &amp;quot;/verified&amp;quot;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;See more details in the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] K8s AWS: How to check Pod logs</title><link>https://ramigs.dev/blog/k8s-aws-how-to-check-pod-logs/</link><guid isPermaLink="true">https://ramigs.dev/blog/k8s-aws-how-to-check-pod-logs/</guid><description>How to check Pod logs on a K8s cluster running on AWS EKS</description><pubDate>Fri, 11 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to check Pod logs on a K8s cluster running on &lt;a href=&quot;https://aws.amazon.com/eks/&quot;&gt;AWS
EKS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;K8s cluster on AWS EKS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html&quot;&gt;AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, connect to the AWS account. Here, I’m doing it using &lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html&quot;&gt;Named
Profiles&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; AWS_PROFILE&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;ramigs-dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export AWS_PROFILE=ramigs-dev&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Update the context on your local &lt;code&gt;.kube/config&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;eks&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--region&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;eu-north-1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;update-kubeconfig&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;k8s-cluster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws eks --region eu-north-1 update-kubeconfig --name k8s-cluster&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Confirm that your connection is working, by requesting the list of namespaces:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ns&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl get ns&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Take note of the namespace tho which the pod you want to check belongs to.&lt;/p&gt;
&lt;p&gt;Get the list of pods:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pods&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-n&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;namespace&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl get pods -n namespace&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Check logs:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;logs&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pod-name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-n&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;container-name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;kubectl logs -f pod-name -n namespace container-name&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] GitHub Actions: how to get execution status of a specific job</title><link>https://ramigs.dev/blog/github-actions-how-to-get-status-execution-of-a-specific-job/</link><guid isPermaLink="true">https://ramigs.dev/blog/github-actions-how-to-get-status-execution-of-a-specific-job/</guid><description>GitHub Actions: How to get execution status of a specific job</description><pubDate>Wed, 09 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that in GitHub Actions, one can use &lt;code&gt;needs.job.result&lt;/code&gt; to get the execution
status of a specific job.&lt;/p&gt;
&lt;p&gt;Let’s say you have a job named &lt;code&gt;invalidate-cache&lt;/code&gt;. You can then, in another job,
check its execution status, like so:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;needs.invalidate-cache.result == &apos;success&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if: needs.invalidate-cache.result == &amp;#x27;success&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] Vue: parsing input value as number</title><link>https://ramigs.dev/blog/vue-parsing-input-value-as-number/</link><guid isPermaLink="true">https://ramigs.dev/blog/vue-parsing-input-value-as-number/</guid><description>Using modifier .number on v-model in order to parse an input value as number</description><pubDate>Mon, 07 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about the Vue modifier &lt;code&gt;.number&lt;/code&gt; on &lt;code&gt;v-model&lt;/code&gt;, which can be used to parse
the value of an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element as &lt;code&gt;number&lt;/code&gt; (instead of as &lt;code&gt;string&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;searchFilters.amount&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;input v-model.number=&amp;quot;searchFilters.amount&amp;quot; /&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;typeof searchFilters.amount&lt;/code&gt; will be &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Node: specifying the versions a package works on</title><link>https://ramigs.dev/blog/node-specifying-versions-a-package-works-on/</link><guid isPermaLink="true">https://ramigs.dev/blog/node-specifying-versions-a-package-works-on/</guid><description>Using configuration engines in package.json to specify which versions a package works on</description><pubDate>Sat, 05 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about configuration &lt;code&gt;engines&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;, which can be used as a
best-practice for explicitly specifying under what versions of &lt;code&gt;node&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt;
a package can be installed:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;engines&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&amp;gt;= 6.0.0&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;npm&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&amp;gt;= 3.0.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;  &amp;quot;engines&amp;quot;: {    &amp;quot;node&amp;quot;: &amp;quot;&gt;= 6.0.0&amp;quot;,    &amp;quot;npm&amp;quot;: &amp;quot;&gt;= 3.0.0&amp;quot;  },&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This applies only to &lt;strong&gt;packages&lt;/strong&gt; and is related to the moment a package is
installed with &lt;code&gt;npm install&lt;/code&gt; as package (e.g., from one directory up), and not
&lt;code&gt;npm install&lt;/code&gt; inside a project (which installs the dependencies of the project).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/cli/v6/configuring-npm/package-json#engines&quot;&gt;package.json - npm documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.dev/learn/the-package-json-guide&quot;&gt;The package.json guide - Node documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.marcusoft.net/2015/03/packagejson-and-engines-and-enginestrict.html&quot;&gt;package.json: engines &amp;amp; engineStrict - and how to use them - Marcus
Hammarberg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] How to parse flags passed to a bash script</title><link>https://ramigs.dev/blog/how-to-parse-flags-passed-to-a-bash-script/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-parse-flags-passed-to-a-bash-script/</guid><description>Parsing flags passed to a bash script using built-in function getopts</description><pubDate>Tue, 01 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to parse flags passed to a bash script, using the built-in function
&lt;code&gt;getopts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s say you have a script named &lt;code&gt;maintenance.sh&lt;/code&gt;, to which you’d like to pass
some flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f filename&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These flags can be parsed in the script, like so:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;getopts&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;edf:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;flag&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;flag&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#DBEDFF&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Got flag -e&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#DBEDFF&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Got flag -d&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#DBEDFF&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Got flag -f with respective option ${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;OPTARG&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;esac&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;while getopts edf: flagdo    case &amp;quot;${flag}&amp;quot; in        e) echo &amp;quot;Got flag -e&amp;quot;;;        d) echo &amp;quot;Got flag -d&amp;quot;;;        f) echo &amp;quot;Got flag -f with respective option ${OPTARG}&amp;quot;;;    esacdone&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice in the arguments of &lt;code&gt;getopts&lt;/code&gt; that &lt;code&gt;f&lt;/code&gt; is the only flag that is followed
by &lt;code&gt;:&lt;/code&gt;, which is used to indicate that the flag is followed by a respective
value.&lt;/p&gt;
&lt;p&gt;Script can then be called as &lt;code&gt;sh maintenance.sh -e&lt;/code&gt; or &lt;code&gt;sh maintenance.sh -e -f file.json&lt;/code&gt;, for example.&lt;/p&gt;
&lt;p&gt;See:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/linux/use-command-line-arguments-in-bash-script&quot;&gt;How to Use Command Line Arguments in a Bash
Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/getopts.1p.html&quot;&gt;getopts man page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] Docker: How to execute without sudo</title><link>https://ramigs.dev/blog/docker-execute-without-sudo/</link><guid isPermaLink="true">https://ramigs.dev/blog/docker-execute-without-sudo/</guid><description>Avoid having to type sudo every time when executing the command docker on Ubuntu</description><pubDate>Tue, 22 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On certain Linux distributions, such as Ubuntu, the &lt;code&gt;docker&lt;/code&gt; command can only be
executed by the root user or by a user in the &lt;code&gt;docker&lt;/code&gt; group.&lt;/p&gt;
&lt;p&gt;For the sake of convenience, to not have to type &lt;code&gt;sudo&lt;/code&gt; every time, add your
user to the &lt;code&gt;docker&lt;/code&gt; group, as so:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;sudo usermod -aG docker ${USER}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo usermod -aG docker ${USER}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Source:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04#step-2-executing-the-docker-command-without-sudo-optional&quot;&gt;How To Install and Use Docker on Ubuntu 20.04 - Brian Hogan&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] Cypress custom selector commands</title><link>https://ramigs.dev/blog/cypress-custom-selector-commands/</link><guid isPermaLink="true">https://ramigs.dev/blog/cypress-custom-selector-commands/</guid><description>Configuring custom selector commands in Cypress</description><pubDate>Mon, 21 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You may already know that it’s a good practice in Cypress to use &lt;code&gt;data-*&lt;/code&gt;
attributes (e.g., &lt;code&gt;data-test&lt;/code&gt;, &lt;code&gt;data-cy&lt;/code&gt;) for targeting elements.&lt;/p&gt;
&lt;p&gt;TIL about two super useful custom selectors that can be added, to avoid always
having to write &lt;code&gt;[data-test=&quot;sign-up&quot;]&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getBySel&lt;/code&gt; yield elements with &lt;code&gt;data-test&lt;/code&gt; attribute that &lt;strong&gt;matches&lt;/strong&gt; a
specified selector&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getBySelLike&lt;/code&gt; yield elements with a &lt;code&gt;data-test&lt;/code&gt; attribute that &lt;strong&gt;contains&lt;/strong&gt; a
specified selector&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To use these selectors in your tests, first add them as commands:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Cypress.Commands.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;getBySel&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;selector&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; cy.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;`[data-test=${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;selector&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;}]`&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Cypress.Commands.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;getBySelLike&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;selector&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; cy.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;`[data-test*=${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;selector&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;}]`&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;args);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Cypress.Commands.add(&amp;quot;getBySel&amp;quot;, (selector, ...args) =&gt; {  return cy.get(&amp;#x60;[data-test=${selector}]&amp;#x60;, ...args);});Cypress.Commands.add(&amp;quot;getBySelLike&amp;quot;, (selector, ...args) =&gt; {  return cy.get(&amp;#x60;[data-test*=${selector}]&amp;#x60;, ...args);});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then, use them as so:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;cy.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;getBySel&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;sign-up&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;cy.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;getBySel&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;sign&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;click&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cy.getBySel(&amp;quot;sign-up&amp;quot;).click();cy.getBySel(&amp;quot;sign&amp;quot;).click();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Source:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cypress-io/cypress-realworld-app&quot;&gt;cypress-realworld-app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] How to backup a GPG key pair</title><link>https://ramigs.dev/blog/how-to-backup-a-gpg-key-pair/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-backup-a-gpg-key-pair/</guid><description>How to backup a GPG key pair and its respective revocation certificate</description><pubDate>Sun, 20 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that after generating a GPG key pair, one should always backup the
following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;key pair&lt;/strong&gt; itself: &lt;code&gt;gpg -o private.gpg --export-options backup --export-secret-keys my-key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;revocation certificate&lt;/strong&gt;: &lt;code&gt;gpg --output revoke.asc --gen-revoke my-key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;key passphrase&lt;/strong&gt;: should be stored separately from the above, ideally on a
password manager&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Always consider carefully your security requirements for decisions regarding
redundancy and backup storage location (ideally on offline media).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For more information, please check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnupg.org/gph/en/manual/c481.html&quot;&gt;Daily use of GnuPG - The GNU Privacy
Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jwillikers.com/backup-and-restore-a-gpg-key&quot;&gt;Backup and Restore a GPG Key -
JWillikers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnupg.org/gph/en/manual/c14.html#REVOCATION&quot;&gt;Generating a revocation certificate - The GNU Privacy
Handbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[TIL] Connecting Adminer to an Azure MySQL database</title><link>https://ramigs.dev/blog/adminer-mysql-azure/</link><guid isPermaLink="true">https://ramigs.dev/blog/adminer-mysql-azure/</guid><description>How to fix SSL-related issues when trying to connect Adminer running in Docker to an Azure MySQL database</description><pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’re having SSL-related issues when connecting
&lt;a href=&quot;https://www.adminer.org/&quot;&gt;Adminer&lt;/a&gt; to an &lt;a href=&quot;https://azure.microsoft.com/en-us/services/mysql/&quot;&gt;Azure MySQL
database&lt;/a&gt;, try out this &lt;a href=&quot;https://superuser.com/questions/1458910/docker-adminer-image-cannot-read-login-ssl-plugin-from-var-www-html-plugins-ena/1557752#1557752&quot;&gt;very
helpful
answer&lt;/a&gt;,
with the following nuances:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;no need for client key or client certificate, i.e., discard environment
variables &lt;code&gt;DB_SSL_KEY&lt;/code&gt;, &lt;code&gt;DB_SSL_CERT&lt;/code&gt; and the respective volumes&lt;/li&gt;
&lt;li&gt;use only &lt;code&gt;DB_SSL_CA&lt;/code&gt; and its respective volume with the &lt;a href=&quot;https://www.digicert.com/CACerts/BaltimoreCyberTrustRoot.crt.pem&quot;&gt;certificate provided
by Azure&lt;/a&gt;
(see more details
&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/mysql/howto-configure-ssl&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: these instructions assume you have Adminer running as a Docker container,
but the same arguments being passed to the &lt;a href=&quot;https://github.com/vrana/adminer/blob/master/plugins/login-ssl.php&quot;&gt;Adminer plugin
login-ssl&lt;/a&gt;
should apply nonetheless.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] git: how to rollback in trunk based development</title><link>https://ramigs.dev/blog/git-how-to-rollback-in-trunk-based-development/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-how-to-rollback-in-trunk-based-development/</guid><description>git: how to rollback in trunk based development</description><pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to rollback when working in a trunk based development model.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A source-control branching model, where developers collaborate on code in a
single branch called ‘trunk’ (main or master, in Git nomenclature), resist any
pressure to create other long-lived development branches by employing
documented techniques. They therefore avoid merge hell, do not break the
build, and live happily ever after.” - &lt;em&gt;&lt;a href=&quot;https://trunkbaseddevelopment.com/&quot;&gt;Trunk Based
Development&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s say you’ve deployed branch &lt;code&gt;main&lt;/code&gt; and discovered that you need to rollback
the deploy. You can either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;leverage PRs/short-live feature branches, by directly deploying the branch
you want to rollback to&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;if you want to rollback to a specific commit hash which is not &lt;code&gt;HEAD&lt;/code&gt; of any
of the existing branches, create a new branch from this specific commit &lt;code&gt;git checkout -b rollback-2022-02-13 ad3da78&lt;/code&gt; and deploy that branch&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ve also learned that a git commit hash is a cryptographic checksum that is
calculated from the &lt;strong&gt;state of the repository&lt;/strong&gt; (including the hash of all the
files in the repository, the hash of the previous commit, the current date and
time, etc.), and contrarily to what I previously thought, not related to
individual files.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] How to fix error CORS OPTIONS Missing Allow Header</title><link>https://ramigs.dev/blog/how-to-fix-cors-options-missing-allow-header/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-to-fix-cors-options-missing-allow-header/</guid><description>How to fix error CORS OPTIONS Missing Allow Header</description><pubDate>Sat, 12 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to fix errors such as &lt;code&gt;OPTIONS https://id.dev.nordikcoin.com/auth/questionnaire CORS Missing Allow Header&lt;/code&gt; and
&lt;code&gt;Reason: header &apos;authorization&apos; is not allowed according to header &apos;Access-Control Allow-Headers&apos; from CORS preflight response.&lt;/code&gt;, which tend to
manifest specially when working in local development.&lt;/p&gt;
&lt;p&gt;Header &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt; is a response header to a preflight
request (&lt;code&gt;OPTIONS&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;These issues can be fixed from the server side either by setting header
&lt;code&gt;Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH,OPTIONS&lt;/code&gt;,
&lt;code&gt;Access-Control-Allow-Headers: authorization&lt;/code&gt;, or both.&lt;/p&gt;
&lt;p&gt;From Postman the request may succeed, but only because Postman is more
permissive than the browser and does not send the preflight request &lt;code&gt;OPTIONS&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Email delivery in Auth0</title><link>https://ramigs.dev/blog/auth0-email-delivery/</link><guid isPermaLink="true">https://ramigs.dev/blog/auth0-email-delivery/</guid><description>The importance of setting up an external email provider for Auth0 email delivery</description><pubDate>Thu, 10 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that &lt;a href=&quot;https://auth0.com/&quot;&gt;Auth0&lt;/a&gt; does not guarantee the instant delivery of
emails that are part of Auth0’s authentication workflows, when using their
default internal email provider.&lt;/p&gt;
&lt;p&gt;It’s necessary to configure an external email provider, such as &lt;a href=&quot;https://aws.amazon.com/ses/&quot;&gt;Amazon
SES&lt;/a&gt;, to route all emails through a high-volume
email service.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] logrotate: how to prevent deletion of old logs</title><link>https://ramigs.dev/blog/logrotate-prevent-deletion-of-old-logs/</link><guid isPermaLink="true">https://ramigs.dev/blog/logrotate-prevent-deletion-of-old-logs/</guid><description>How to avoid logrotate to delete rotated logs</description><pubDate>Thu, 10 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that in a logrotate configuration file, with setting &lt;code&gt;daily&lt;/code&gt; configured, if
&lt;code&gt;rotate&lt;/code&gt; is not explicitly set, old rotated log files will be deleted (after one
rotation, it seems).&lt;/p&gt;
&lt;p&gt;To avoid this, set &lt;code&gt;rotate n&lt;/code&gt;, where &lt;code&gt;n&lt;/code&gt; is the number of logs to be kept.&lt;/p&gt;
&lt;p&gt;Haven’t found a way to completely disable deletion. Common practice seems to be
setting &lt;code&gt;rotate&lt;/code&gt; with a &lt;em&gt;high number&lt;/em&gt;. See:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/50181/how-i-configure-logrotate-to-not-delete-my-log-files-after-rotation&quot;&gt;https://serverfault.com/questions/50181/how-i-configure-logrotate-to-not-delete-my-log-files-after-rotation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/377031/logrotate-does-not-remove-old-logs&quot;&gt;https://serverfault.com/questions/377031/logrotate-does-not-remove-old-logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/377031/logrotate-does-not-remove-old-logs&quot;&gt;https://serverfault.com/questions/694935/logrotate-how-change-it-so-that-it-never-deletes-logs-and-will-create-a-gz-ev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example of the configuration file I’m referring to:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;/nginx-logs/access.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;/nginx-logs/error.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;daily&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;rotate 30&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;dateext&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;dateformat .%Y-%m-%d&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;extension .log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;sharedscripts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;compress&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;postrotate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;sudo docker kill --signal=USR1 nginx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;endscript&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;/nginx-logs/access.log/nginx-logs/error.log{    daily    rotate 30    dateext    dateformat .%Y-%m-%d    extension .log    sharedscripts    compress    postrotate      sudo docker kill --signal=USR1 nginx    endscript}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded></item><item><title>[TIL] git: multiple line commit message</title><link>https://ramigs.dev/blog/git-multiple-line-commit-message/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-multiple-line-commit-message/</guid><description>How to commit with multiple line commit message in git</description><pubDate>Wed, 09 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL how to commit with multiple line commit message in git from the command
line:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;$ git commit -m &apos;line 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;line 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ git commit -m &amp;#x27;line 1line 2&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The use of single quotes &lt;code&gt;&apos;&lt;/code&gt; instead of double &lt;code&gt;&quot;&lt;/code&gt; is what does the trick here.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Style Editor in Firefox Developer Tools</title><link>https://ramigs.dev/blog/style-editor-firefox-developer-tools/</link><guid isPermaLink="true">https://ramigs.dev/blog/style-editor-firefox-developer-tools/</guid><description>Style Editor in Firefox Developer Tools</description><pubDate>Sun, 06 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools/Style_Editor&quot;&gt;Style
Editor&lt;/a&gt; in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools&quot;&gt;Firefox
Developer Tools&lt;/a&gt; and how useful
it can be to quickly view and edit all the stylesheets associated with a page.
It allows also to create/import new ones and apply them to the page.&lt;/p&gt;
&lt;p&gt;It can be specially helpful in situations where one is not able to run a project
locally and only needs to work on the CSS, or when the project does not have Hot
Module Replacement.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] git: moving unstaged changes to a new branch</title><link>https://ramigs.dev/blog/git-moving-unstaged-changes-to-a-new-branch/</link><guid isPermaLink="true">https://ramigs.dev/blog/git-moving-unstaged-changes-to-a-new-branch/</guid><description>How to move unstaged changes and switch to a new branch in git</description><pubDate>Sat, 05 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that in git, it’s possible to directly move unstaged changes and switch to a
new branch, using command &lt;code&gt;git switch -c new-branch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Very useful when one forgets to create a new branch and starts to do some work
on the mainline branch.&lt;/p&gt;
&lt;p&gt;Found on this &lt;a href=&quot;https://css-tricks.com/git-switching-unstaged-changes-to-a-new-branch/&quot;&gt;CSS-Tricks
article&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Difference between data streaming tools and message brokers</title><link>https://ramigs.dev/blog/stream-processing-tools-vs-message-brokers/</link><guid isPermaLink="true">https://ramigs.dev/blog/stream-processing-tools-vs-message-brokers/</guid><description>Understanding the different use cases for data streaming tools and message brokers</description><pubDate>Sat, 05 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about the difference between data streaming processing tools and message
brokers. The former (e.g., &lt;a href=&quot;https://kafka.apache.org/&quot;&gt;Apache Kafka&lt;/a&gt;) is
tailored for &lt;strong&gt;dynamic data&lt;/strong&gt; being generated on a continual basis. The latter
(e.g., &lt;a href=&quot;https://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt;) is used to mediate
&lt;strong&gt;communication&lt;/strong&gt; among applications in distributed environments
(microservices).&lt;/p&gt;
&lt;p&gt;When designing a solution, it’s important to carefully consider the
requirements, in order to choose the right tool for the job.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Nuxt: hook created is executed when building as static</title><link>https://ramigs.dev/blog/nuxt-static-created-hook/</link><guid isPermaLink="true">https://ramigs.dev/blog/nuxt-static-created-hook/</guid><description>Vue&apos;s lifecycle hook created is executed when building with generate</description><pubDate>Fri, 04 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that in Nuxt, Vue’s &lt;a href=&quot;https://v3.vuejs.org/api/options-lifecycle-hooks.html&quot;&gt;lifecycle
hook&lt;/a&gt; &lt;code&gt;created&lt;/code&gt; is
executed when building a static site with &lt;code&gt;generate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For strictly client-side purposes, use &lt;code&gt;mounted&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] Linux commands: recursive options instead of wildcards</title><link>https://ramigs.dev/blog/linux-commands-recursive-options/</link><guid isPermaLink="true">https://ramigs.dev/blog/linux-commands-recursive-options/</guid><description>Preferring the usage of recursive options in Linux commands in order to prevent errors</description><pubDate>Wed, 02 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that in commands such as &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;scp&lt;/code&gt;, and &lt;code&gt;zip&lt;/code&gt;, it is preferable to use the
command’s native recursive options (e.g.,&lt;code&gt;-r&lt;/code&gt;, &lt;code&gt;-R&lt;/code&gt;) instead of wildcards (e.g.,
&lt;code&gt;*&lt;/code&gt;). The reason is to avoid unexpected errors, such as &lt;code&gt;-bash: /usr/bin/zip: Argument list too long&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] msmtp: sending emails from the command line</title><link>https://ramigs.dev/blog/msmtp/</link><guid isPermaLink="true">https://ramigs.dev/blog/msmtp/</guid><description>msmtp: a tool to send emails from the command line and bash scripts</description><pubDate>Wed, 02 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL about a very straightforward to use tool called &lt;code&gt;msmtp&lt;/code&gt;, which allows
sending emails from the command line and bash scripts.&lt;/p&gt;
&lt;p&gt;Follow &lt;a href=&quot;https://www.linuxscrew.com/bash-send-email&quot;&gt;this guide&lt;/a&gt; for instant
results.&lt;/p&gt;
</content:encoded></item><item><title>[TIL] mv and cp file permissions</title><link>https://ramigs.dev/blog/mv-and-cp-file-permissions/</link><guid isPermaLink="true">https://ramigs.dev/blog/mv-and-cp-file-permissions/</guid><description>mv and cp file permissions</description><pubDate>Sat, 29 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL that &lt;code&gt;mv&lt;/code&gt; preserves file permissions, but &lt;code&gt;cp&lt;/code&gt; does not.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://opensource.com/article/19/8/moving-files-linux-without-mv&quot;&gt; Moving files on Linux without mv
&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Load testing with Artillery</title><link>https://ramigs.dev/blog/load-testing-artillery/</link><guid isPermaLink="true">https://ramigs.dev/blog/load-testing-artillery/</guid><description>An account on using Artillery to load test an application&apos;s backend (and database)</description><pubDate>Fri, 01 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is the story about how my team got to know and use
&lt;a href=&quot;https://artillery.io&quot;&gt;Artillery&lt;/a&gt; to load test the backend (and database) of the
application we’re working on.&lt;/p&gt;
&lt;p&gt;I’ll begin by giving a bit of context on the challenge that led us to need load
testing and Artillery as the right tool for that.&lt;/p&gt;
&lt;p&gt;I’ll then provide a brief overview on what Artillery is and how to use it to
write and run load tests. I’ll also be sharing some of the insights we’ve
learned along the way, plus some very useful Artillery features and testing
strategies.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge&quot;&gt;The challenge&lt;/h2&gt;
&lt;p&gt;So, recently we got some really good news from our product managers. The first
iteration of our application in production has been a success, and as a result,
new users are expected to be onboarded soon.&lt;/p&gt;
&lt;p&gt;This means we need to make sure our application and infrastructure will be able
to scale accordingly, as the number of concurrent users is estimated to increase
by a factor of 50 and the database size to grow by a factor of 10.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is our current infrastructure able to handle the expected traffic increase?
How will performance be affected?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instead of second-guessing, we decided it would be better to rely on concrete
metrics that would help us make better-informed decisions.&lt;/p&gt;
&lt;h2 id=&quot;load-testing&quot;&gt;Load testing&lt;/h2&gt;
&lt;p&gt;At this point, it was clear that we needed a tool to load test the application.
After researching and gathering some in-house positive feedback, we opted to go
with Artillery.&lt;/p&gt;
&lt;p&gt;Our application is deployed on a virtual private server using Docker containers,
and follows a common architecture consisting of three main components: frontend
(Nuxt.js), backend API (.NET Core C#), and database (MySQL). In front of
everything we have nginx serving as a reverse proxy.&lt;/p&gt;
&lt;p&gt;Even though Artillery is more specifically tailored for backend testing,
Artillery’s HTTP testing is ultimately accomplished by sending HTTP requests to
a URI and checking the responses’ status and latency.&lt;/p&gt;
&lt;p&gt;The way our application is set up allows us to load test the entire stack
(including frontend and nginx), since all requests go through nginx before being
dispatched to and handled by
&lt;a href=&quot;https://www.npmjs.com/package/@nuxtjs/proxy&quot;&gt;&lt;code&gt;@nuxtjs/proxy&lt;/code&gt;&lt;/a&gt;. This works great
for us, as it makes our load testing more closely resemble real user behavior.&lt;/p&gt;
&lt;p&gt;In any case, even if your application is not set up in a similar way, but you’d
still like to test other components of your stack, Artillery’s extensibility
(through “hooks”, as we’ll see later down the article) allows you to introduce
further logic in your tests (e.g., HTTP requests to the frontend).&lt;/p&gt;
&lt;h2 id=&quot;artillery&quot;&gt;Artillery&lt;/h2&gt;
&lt;p&gt;Artillery is an open source Node.js load testing tool. It’s designed to test the
&lt;strong&gt;reliability&lt;/strong&gt; and &lt;strong&gt;performance&lt;/strong&gt; of backend services. It operates by
simulating user behavior, allowing developers, test engineers, and SREs to
verify how their backend services and infrastructure handle traffic spikes and
sustained increases in workload.&lt;/p&gt;
&lt;p&gt;Some of its key features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;emulation of advanced (complex) user behavior&lt;/li&gt;
&lt;li&gt;extensive protocol support (HTTP, Socket.io, WebSockets + others via plugins)&lt;/li&gt;
&lt;li&gt;writing tests in a declarative style (YAML)&lt;/li&gt;
&lt;li&gt;integration with external monitoring/observability services (e.g.,
&lt;a href=&quot;https://www.datadoghq.com/&quot;&gt;Datadog&lt;/a&gt;, &lt;a href=&quot;https://www.honeycomb.io/&quot;&gt;Honeycomb&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;extensibility and customization (JavaScript)&lt;/li&gt;
&lt;li&gt;official &lt;a href=&quot;https://hub.docker.com/r/artilleryio/artillery&quot;&gt;Docker image&lt;/a&gt; available&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;test-specification&quot;&gt;Test specification&lt;/h3&gt;
&lt;p&gt;An Artillery test script is a YAML file containing one or more scenarios. A
scenario is a sequence of actions (e.g., HTTP requests) that a virtual user goes
through. Here’s an example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;scenarios&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;login + home page (list products)&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;flow&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/users/login&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;username&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{{ $processEnvironment.VIRTUSER_USERNAME }}&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{{ $processEnvironment.VIRTUSER_PASSWORD }}&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;beforeRequest&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ensureSessionCookieSet&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/users/role&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;selectedRole&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;CUSTOMER&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;beforeRequest&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;ensureSessionCookieSet&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/services&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;scenarios:  - name: &amp;quot;login + home page (list products)&amp;quot;    flow:      - post:          url: &amp;quot;/users/login&amp;quot;          json:            username: &amp;quot;{{ $processEnvironment.VIRTUSER_USERNAME }}&amp;quot;            password: &amp;quot;{{ $processEnvironment.VIRTUSER_PASSWORD }}&amp;quot;      - post:          beforeRequest: ensureSessionCookieSet          url: &amp;quot;/users/role&amp;quot;          json:            selectedRole: &amp;quot;CUSTOMER&amp;quot;      - get:          beforeRequest: ensureSessionCookieSet          url: &amp;quot;/services&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A really cool feature we were pleasantly surprised to find:
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie&quot;&gt;&lt;code&gt;Set-Cookie&lt;/code&gt;&lt;/a&gt;
support, which allows out-of-the-box session-based cookie authentication.&lt;/p&gt;
&lt;p&gt;In the snippet above you may have also noticed &lt;code&gt;beforeRequest&lt;/code&gt;. It’s an
&lt;a href=&quot;https://artillery.io/docs/guides/guides/http-reference.html&quot;&gt;Artillery “hook”&lt;/a&gt;.
“Hooks” allow custom JavaScript logic to be attached to the lifecycle of
scenarios and individual requests.&lt;/p&gt;
&lt;p&gt;Other attributes we’ve found to be very useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;weight&lt;/code&gt;: which can be used to specify the probability of each scenario being
executed by a new virtual user;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;think&lt;/code&gt;: which can be used to more realistically mimic human user behavior, by
pausing the execution for N seconds between requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;test-configuration&quot;&gt;Test configuration&lt;/h3&gt;
&lt;p&gt;Besides section &lt;code&gt;scenarios&lt;/code&gt;, a test script is composed of another main section:
&lt;code&gt;config&lt;/code&gt;. This is where the test configuration (target URIs, environments,
custom code, etc.) is defined:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;timeout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;environments&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;staging&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;https://staging.my.app&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;phases&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;duration&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;120&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;arrivalRate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;production&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;https://my.app&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;phases&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;duration&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1200&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;arrivalRate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;config:  timeout: 2environments:    staging:      target: &amp;quot;https://staging.my.app&amp;quot;      phases:        - duration: 120        arrivalRate: 10    production:      target: &amp;quot;https://my.app&amp;quot;      phases:        - duration: 1200        arrivalRate: 20&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code&gt;phases&lt;/code&gt; we can find the core load phase attributes which determine &lt;em&gt;how&lt;/em&gt;
Artillery will generate new virtual users during test execution.&lt;/p&gt;
&lt;p&gt;For each environment a test may execute one or more
&lt;a href=&quot;https://artillery.io/docs/guides/guides/test-script-reference.html#Load-Phases&quot;&gt;phases&lt;/a&gt;.
Generally, you’ll find that test a may begin with a warm-up phase, followed by a
ramp-up phase, and finally end with a maximum load phase.&lt;/p&gt;
&lt;p&gt;One feature that we are not currently using (but planning to in the near future)
is &lt;a href=&quot;https://artillery.io/docs/guides/guides/test-script-reference.html#Setting-success-conditions-with-ensure&quot;&gt;setting up success
conditions&lt;/a&gt;.
This enables Artillery to return with non-zero if a certain condition (response
time or error rate) is not met, which may be very useful for integrating
Artillery into CI/CD pipelines. Here’s an example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;ensure&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;maxErrorRate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;config:  ensure:    maxErrorRate: 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally, after you’ve executed the test, you may also examine the results
visually, by uploading the JSON results file to the &lt;a href=&quot;https://reportviewer.artillery.io/&quot;&gt;Artillery report
viewer&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;We had a great experience using Artillery. Excellent documentation,
straightforward to set up and start running tests right away.&lt;/p&gt;
&lt;p&gt;By combining Artillery’s test results with data from an internal observability
service, we were able to confirm that the higher potential for performance
bottlenecks comes from the database.&lt;/p&gt;
&lt;p&gt;We’ve found it very useful to perform several tests using different strategies
(warm-up, ramp-up, and maximum load), mixing up different &lt;code&gt;phase&lt;/code&gt; attributes and
respective values, to really understand how the current infrastructure responds.&lt;/p&gt;
&lt;p&gt;We combined all the results in an Excel sheet which we then examined to derive
the points of inflection (in terms of number of concurrent users and database
size) at which performance and user experience start to go below thresholds
we’ve defined as acceptable.&lt;/p&gt;
&lt;p&gt;As a next step, we’ll be adding more computational resources to the database, by
migrating it to a managed database service, as we continue to use Artillery to
monitor the performance improvements that result from each update we implement.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;Some great resources that helped us along the way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://artillery.io/docs/guides/overview/welcome.html&quot;&gt;Artillery Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/artilleryio/artillery-examples&quot;&gt;Artillery Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=jZSgg9pmw2g&quot;&gt;Load testing using AWS &amp;amp; Artillery - João Tiago (20m talk + 10m Q&amp;amp;A) [2020.05 DevOps Lisbon]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://azevedorafaela.com/2019/06/27/performance-tests-with-artillery/&quot;&gt;Performance Tests with Artillery - Rafaela Azevedo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=j1Spkw0faq0&quot;&gt;Automating performance and load tests with Artillery + Keptn - Francesco Lentini&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/compute/load-testing-a-web-applications-serverless-backend/&quot;&gt;Load testing a web application’s serverless backend - James Beswick&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>How to reliably clear a Linux log file</title><link>https://ramigs.dev/blog/reliably-clear-log-file-linux/</link><guid isPermaLink="true">https://ramigs.dev/blog/reliably-clear-log-file-linux/</guid><description>Presenting file truncation and log rotation as two viable approaches for reliably clearing a log file on Linux</description><pubDate>Tue, 20 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Have you ever found your Linux server running out of disk space, only to
discover a single log file taking up gigabytes of storage?&lt;/p&gt;
&lt;p&gt;Well, I have 😅. Recently, in one of the servers I’m managing, I detected a 5 GB
(and steadily increasing) &lt;code&gt;/var/log/maillog&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Turned out to be an issue with an incomplete removal of a hosting control panel
tool that was causing the log file to be written to every second.&lt;/p&gt;
&lt;p&gt;After fixing the issue that was causing this non-stop growth of the log, I began
looking for a way to reliably get the disk space back.&lt;/p&gt;
&lt;p&gt;I had a sneaky suspicion that simply &lt;code&gt;rm&lt;/code&gt;’ing and recreating the file
would not be such a great idea.&lt;/p&gt;
&lt;p&gt;Turns out my hunch was right. My investigation led me to learn that when a
process opens a file - either for read or write, it’s actually holding a handle
to that file’s &lt;a href=&quot;https://linuxhandbook.com/inode-linux/&quot;&gt;inode&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;inode is a Linux filesystem data structure that’s assigned to each created
file. Its purpose is to store various metadata about the file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the file gets deleted by a different process, this may cause other programs
that reference that inode to malfunction. Also, the disk space is not freed up
until processes close their handle on it.&lt;/p&gt;
&lt;p&gt;Moreover, file ownership and permissions will most likely get messed up, as the
newly created file won’t have the same inode as the deleted file.&lt;/p&gt;
&lt;h2 id=&quot;file-truncation&quot;&gt;File truncation&lt;/h2&gt;
&lt;p&gt;Ok, so deleting and recreating the log file is not a viable solution. What can
we do instead to free up that disk space?&lt;/p&gt;
&lt;p&gt;We need the file’s inode to remain the same, so we’ll &lt;strong&gt;truncate&lt;/strong&gt; its contents
without deleting it.&lt;/p&gt;
&lt;p&gt;Manually editing the file is not &lt;em&gt;clean&lt;/em&gt; solution a at all. What if the file
gets written to by another process while we’re editing it?&lt;/p&gt;
&lt;p&gt;To truncate the log file we can rely on Linux’s standard output redirect
operator to redirect the output of &lt;em&gt;nothing&lt;/em&gt; to the file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /var/log/maillog&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&gt; /var/log/maillog&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Or, we can use command &lt;code&gt;truncate&lt;/code&gt;, which truncates the file to a precise length
in bytes:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;truncate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-s&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/var/log/maillog&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;truncate -s 0 /var/log/maillog&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Truncating a file is also much faster than deleting the file, recreating it, and
setting the correct ownership and permissions.&lt;/p&gt;
&lt;h2 id=&quot;log-rotation&quot;&gt;Log rotation&lt;/h2&gt;
&lt;p&gt;Before we wrap up, it’s important to bring up the topic of log rotation.&lt;/p&gt;
&lt;p&gt;In a more critical/production scenario, you may need to store the logs for
archive. Log rotation helps us achieve this, by renaming and compressing old log
files, making them ready to be backed up. &lt;code&gt;logrotate&lt;/code&gt; is the Linux tool that
achieves precisely this.&lt;/p&gt;
&lt;p&gt;After you’ve backed up a rotated log file, it’s fine to just remove it and gain
that disk space back.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;Some resources that helped me write this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.howtogeek.com/465350/everything-you-ever-wanted-to-know-about-inodes-on-linux/&quot;&gt;Everything You Ever Wanted to Know About inodes on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxhandbook.com/inode-linux/&quot;&gt;Everything You Need to Know About inodes in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/285843/is-there-a-proper-way-to-clear-logs&quot;&gt;Server Fault Question: Is there a proper way to clear logs?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/665213/missing-var-log-mail-log-after-deleting-it-how-do-i-recreate-it&quot;&gt;Server Fault Question: Missing /var/log/mail.log (after deleting it) - How do I recreate it?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://askubuntu.com/questions/1138180/can-i-delete-var-log-files-because-of-low-root-space-in-ubuntu&quot;&gt;Ask Ubuntu Question: Can I delete /var/log files because of low root space in Ubuntu?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxhandbook.com/empty-file-linux/&quot;&gt;How to Empty a Log File in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linux.die.net/man/1/truncate&quot;&gt;truncate(1) - Linux man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linuxconfig.org/logrotate&quot;&gt;logrotate command in Linux with examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tecmint.com/install-logrotate-to-manage-log-rotation-in-linux/&quot;&gt;How to Setup and Manage Log Rotation Using Logrotate in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.redhat.com/sysadmin/setting-logrotate&quot;&gt;Setting up logrotate in Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Automating database backups</title><link>https://ramigs.dev/blog/automating-database-backups/</link><guid isPermaLink="true">https://ramigs.dev/blog/automating-database-backups/</guid><description>Describing an automated database backup procedure</description><pubDate>Sat, 12 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We already know that backups (and even more so, &lt;strong&gt;restores&lt;/strong&gt;) are of paramount
importance.&lt;/p&gt;
&lt;p&gt;The hard work we put into our projects must be safeguarded. In the context of
teams and organizations this necessity becomes even more pronounced.&lt;/p&gt;
&lt;p&gt;Nowadays, features such as codebase backup and version control are assumed as
given when we use a git-based cloud provider, such as GitHub or GitLab.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Depending on how critical to the business an application is, you may want to
consider further measures in assuring the codebase is backed up with
appropriate redundancy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But what about the database, and, more specifically, the data that it stores?&lt;/p&gt;
&lt;p&gt;Once an application goes into production, its generated data has an
incommensurable value. Loosing it is a scenario that an organization simply
can’t afford.&lt;/p&gt;
&lt;p&gt;On the occurrence of hardware faults, software faults, or human errors,
&lt;strong&gt;disaster recovery&lt;/strong&gt; plans are crucial to ensure that organizations can respond
quickly to minimize any negative effects on business operations. In the context
of databases, the ability to recover is fundamentally defined by ability to
restore.&lt;/p&gt;
&lt;p&gt;In this article, we’ll describe the implementation of an &lt;strong&gt;automated database
backup process&lt;/strong&gt;. It will execute daily, taking a snapshot of a production
database, encrypting it, and securely sending it to a remote backup storage
server.&lt;/p&gt;
&lt;h2 id=&quot;infrastructure-and-tools&quot;&gt;Infrastructure and tools&lt;/h2&gt;
&lt;p&gt;As a general rule of thumb, before implementing a custom solution, one should
investigate if the problem has already been solved.&lt;/p&gt;
&lt;p&gt;Although many times we may find that it has been solved already, a solution that
perfectly fits our requirements does either not exist or the effort to customize
it is bigger than just implementing a solution of our own.&lt;/p&gt;
&lt;p&gt;This was the case when I was asked to implement this automated database backup
procedure. I didn’t find anything matching the specificities of our setup, so I
had to go with a custom solution.&lt;/p&gt;
&lt;p&gt;Let’s now examine the following diagram, an overview of the infrastructure and
tools involved in the setup:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Diagram of automated backup procedure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1214&quot; height=&quot;622&quot; src=&quot;https://ramigs.dev/_astro/2021-06-12-automating-database-backups.Bu9c4BFe_2rXwed.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’re working with two Linux servers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the &lt;strong&gt;production server&lt;/strong&gt;, where the database is running&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;backup server&lt;/strong&gt;, where database backups are stored&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the production server, we have a MySQL database running inside a Docker
container.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; is an awesome containerization tool that
helps standardizing development and deployment, by packaging applications and
their dependencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On the same production server, we also have a cron job, configured to run a
shell script that takes a snapshot of the database (including all the data it
contains) and sends it to the backup server via SSH.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man8/cron.8.html&quot;&gt;cron&lt;/a&gt; is a time-based job
scheduler for Unix-like computer operating systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;SSH is the de facto standard for secure remote access and data exchange between
a client and a server. SSH is a vast subject. Here you can find information on
how to &lt;a href=&quot;https://goteleport.com/blog/how-to-ssh-properly/&quot;&gt;configure it
properly&lt;/a&gt; and &lt;a href=&quot;https://goteleport.com/blog/ssh-key-management/&quot;&gt;manage its
keys&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The purpose of this article is not to serve as a step-by-step guide (although
you can pretty much use it as such) - but more as a general description of how
the procedure was implemented in a real production setting, so that you can
adapt it to your specific setup.&lt;/p&gt;
&lt;h2 id=&quot;backup-script&quot;&gt;Backup script&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Before executing any procedure in production, always make sure to test it
beforehand in a development/staging environment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s now examine the production server shell script
&lt;code&gt;/root/database-backup/db-backup-production.sh&lt;/code&gt;. This file is the core of the
backup procedure. When executed, it will access the Docker container and export
a database snapshot, zip it, encrypt it with GPG, and securely copy the
resulting file to the backup server.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/root/database-backup&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;today&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;+&quot;%Y-%m-%d&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;+%s&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Starting backup %s %s\n&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; $today $timestamp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;container_database_1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;mysqldump&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-u&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--password=password123&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--events&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--routines&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--triggers&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;bd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backup_db_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${today}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${timestamp}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.sql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;zip&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backup-db_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${today}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${timestamp}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.zip&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backup_db_&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--batch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--passphrase&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;pass123&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backup-db_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${today}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${timestamp}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.zip&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backups&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;scp&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backup-db_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${today}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;${timestamp}&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.zip.gpg&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;backup-repo-host.com:~/database-backups&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Backup completed!\n&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd /root/database-backuptoday=$(date +&amp;quot;%Y-%m-%d&amp;quot;)timestamp=$(date +%s)printf &amp;quot;Starting backup %s %s\n&amp;quot; $today $timestampdocker exec container_database_1 mysqldump -u root --password=password123 --events --routines --triggers bd &gt; backup_db_${today}_${timestamp}.sqlzip backup-db_${today}_${timestamp}.zip backup_db_*gpg -c --batch --passphrase pass123 backup-db_${today}_${timestamp}.zipmkdir -p backupsscp backup-db_${today}_${timestamp}.zip.gpg backup-repo-host.com:~/database-backupsprintf &amp;quot;Backup completed!\n&amp;quot;printf &amp;quot;\n&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This script is not supposed to be executed directly. Instead, we’ll rely on a
secondary script &lt;code&gt;/root/database-backup/run-db-backup-production.sh&lt;/code&gt; that will
allow us to have visibility over the history and status of executions, by
appending the execution outputs to a log file every time the procedure runs.
These are the contents of this script:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/root/database-backup&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;sh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;db-backup-production.sh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; log.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd /root/database-backupsh db-backup-production.sh &amp;amp;&gt;&gt; log.txt&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The backup procedure can be executed with two modes of operation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;manually, on-demand&lt;/li&gt;
&lt;li&gt;automatically, scheduled to run at fixed times, dates, or intervals&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;manual-backup&quot;&gt;Manual backup&lt;/h2&gt;
&lt;p&gt;To run the backup procedure manually, just execute the script:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;sh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run-db-backup-production.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sh run-db-backup-production.sh&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Look into file &lt;code&gt;/root/database-backup/log.txt&lt;/code&gt; for details on the execution
outputs.&lt;/p&gt;
&lt;h2 id=&quot;scheduled-backups&quot;&gt;Scheduled backups&lt;/h2&gt;
&lt;p&gt;To have it run regularly, we’ll rely on cron.&lt;/p&gt;
&lt;p&gt;Let’s configure a cron job to run everyday at 10 PM. To do that, execute the
command &lt;code&gt;crontab -e&lt;/code&gt; and add the following entry:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;       &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;       &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;       &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;       &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;       &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/bin/sh&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/root/database-backup/run-db-backup-production.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;0       22       *       *       *       /bin/sh /root/database-backup/run-db-backup-production.sh&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;restoring-a-backup&quot;&gt;Restoring a backup&lt;/h2&gt;
&lt;p&gt;A backup has no value if we can’t restore it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Nobody wants backup, everybody wants restore.” -
&lt;em&gt;&lt;a href=&quot;https://adminzen.org/backup/&quot;&gt;The Admin Zen&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To restore a backup, follow these steps:&lt;/p&gt;
&lt;h3 id=&quot;access-backup-server&quot;&gt;Access backup server&lt;/h3&gt;
&lt;p&gt;Log in to the backup storage server, navigate to the backup folder and select
the GPG file &lt;code&gt;backup-db_${date}_${timestamp}.zip.gpg&lt;/code&gt; of the snapshot you want
to restore.&lt;/p&gt;
&lt;h3 id=&quot;copy&quot;&gt;Copy&lt;/h3&gt;
&lt;p&gt;Copy it to the server where the database is running, using a secure method such
as &lt;code&gt;scp&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;decrypt&quot;&gt;Decrypt&lt;/h3&gt;
&lt;p&gt;Decrypt the GPG file using the following command &lt;code&gt;gpg --batch --yes --passphrase pass123 backup-db-01-21_1611250508.zip.gpg&lt;/code&gt;. The decrypted zip file will be
written to the same folder.&lt;/p&gt;
&lt;h3 id=&quot;unzip&quot;&gt;Unzip&lt;/h3&gt;
&lt;p&gt;Unzip the file that resulted from the previous step, using &lt;code&gt;unzip&lt;/code&gt; or any other
archive tool at your disposal.&lt;/p&gt;
&lt;h3 id=&quot;restore-database&quot;&gt;Restore database&lt;/h3&gt;
&lt;p&gt;Access the web interface of the database content managing tool you’re using
(e.g., phpMyAdmin, Adminer) and run the SQL file that resulted from the previous
step. Alternatively, if you don’t have a content managing tool installed for
your database, you can also execute the SQL file through the command-line.&lt;/p&gt;
&lt;h3 id=&quot;verify-restore&quot;&gt;Verify restore&lt;/h3&gt;
&lt;p&gt;Confirm that the SQL script executed without errors and that the database has
been created and populated. Also, make sure to verify that client apps that use
the database continue to work as expected.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;And, we’re done 💪.&lt;/p&gt;
&lt;p&gt;Thank you for reading this far!&lt;/p&gt;
&lt;p&gt;We’ve discussed the importance of regular database backups and how to automate
them.&lt;/p&gt;
&lt;p&gt;As in any process, there’s always room for improvement.
The next features I’d like to implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Email notifications, specially in the case of failure.&lt;/li&gt;
&lt;li&gt;Secure password management, that would allow removing database and GPG
passwords from the main script. &lt;a href=&quot;https://smallstep.com/blog/command-line-secrets/&quot;&gt;This
article&lt;/a&gt; may be a good
starting point.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to share any comment or suggestion by opening a PR on &lt;a href=&quot;https://github.com/ramigs/ramigs.dev/blob/main/src/content/blog/2021-06-12-automating-database-backups.md&quot;&gt;this
article&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Strapi Hooks</title><link>https://ramigs.dev/blog/strapi-hooks/</link><guid isPermaLink="true">https://ramigs.dev/blog/strapi-hooks/</guid><description>Understanding the different types/categories of Strapi Hooks</description><pubDate>Sat, 06 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;(This article was originally published on &lt;a href=&quot;https://strapi.io/blog/understanding-the-different-types-categories-of-strapi-hooks&quot;&gt;strapi.io&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hooks are one of the main built-in developer interfaces that we can use to customize and extend Strapi’s default functionality.&lt;/p&gt;
&lt;p&gt;In this article, we’ll review and compare the three different types of Strapi hooks - describing and summarizing each type’s method of implementation and common use cases.&lt;/p&gt;
&lt;p&gt;To follow this article, although not required, a basic familiarity with Strapi will definitely help better understand the use cases and code snippets. Nevertheless, this is not a step-by-step guide, so feel free to skim through or just go directly to the hooks section you’re looking for.&lt;/p&gt;
&lt;p&gt;Let’s begin.&lt;/p&gt;
&lt;h2 id=&quot;content-type-hooks&quot;&gt;Content-Type Hooks&lt;/h2&gt;
&lt;p&gt;If you’re familiar with Strapi, you most likely already know what a Content-Type (or &lt;a href=&quot;https://strapi.io/documentation/developer-docs/latest/concepts/models.html#concept&quot;&gt;Model&lt;/a&gt;) is. A Content-Type is a JSON representation that is used to specify the underlying database structure of a content entity we want to store in Strapi’s database.&lt;/p&gt;
&lt;p&gt;The first type of hooks we’ll examine are &lt;a href=&quot;https://strapi.io/documentation/v3.x/concepts/models.html#lifecycle-hooks&quot;&gt;lifecycle hooks&lt;/a&gt;.
These hooks allow us to extend Strapi’s default &lt;strong&gt;Content-Type&lt;/strong&gt; functionality, by introducing custom code that will run whenever (before or after) a &lt;a href=&quot;https://strapi.io/documentation/v3.x/concepts/queries.html&quot;&gt;query&lt;/a&gt; is executed over a Content-Type - no matter if that’s done through the Admin Panel, an API call, or the execution of custom code that uses &lt;strong&gt;default&lt;/strong&gt; queries.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“When you are building custom ORM specific queries the lifecycles will not be triggered. You can however call a lifecycle function directly if you wish.” - &lt;em&gt;&lt;a href=&quot;https://strapi.io/documentation/developer-docs/latest/concepts/models.html#lifecycle-hooks&quot;&gt;Strapi Developer Documentation&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;use-case-examples&quot;&gt;Use Case Examples&lt;/h3&gt;
&lt;p&gt;Lifecycle hooks are ideal for when you’d want to automatically trigger an action whenever Strapi content is queried or updated.&lt;/p&gt;
&lt;p&gt;Lifecycle hooks can be used, for instance in an e-commerce app, to send an email notification or clear a CDN cache, when a new product is added to the store.&lt;/p&gt;
&lt;h3 id=&quot;how-to-implement-a-content-type-hook&quot;&gt;How to Implement a Content-Type Hook&lt;/h3&gt;
&lt;p&gt;To create a Content-Type lifecycle hook, first, you’ll have to determine to which &lt;strong&gt;model&lt;/strong&gt; and to which &lt;strong&gt;query&lt;/strong&gt; you would like to attach the hook. Here’s the list of the available default Strapi queries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;find&lt;/code&gt;: Returns a list of entries matching Strapi filters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;findOne&lt;/code&gt;: Returns the first entry matching some basic parameters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create&lt;/code&gt;: Creates an entry in the database and returns the entry.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update&lt;/code&gt;: Updates an entry in the database and returns the entry.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt;: Deletes an entry (or multiple entries at once) and return its value before deletion.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt;: Returns the count of entries matching Strapi filters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search&lt;/code&gt;: Returns entries based on a search on all fields allowing it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;countSearch&lt;/code&gt;: Returns the total count of entries based on a search.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each of the previous events, you can configure the hook to run before or after the event is executed. To do so, capitalize the first letter of the event name and prefix it with &lt;code&gt;before&lt;/code&gt; or &lt;code&gt;after&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can now set a &lt;code&gt;lifecycles&lt;/code&gt; key in the model file &lt;code&gt;./api/{apiName}/models/{modelName}.js&lt;/code&gt; with its respective lifecycle hooks.&lt;/p&gt;
&lt;p&gt;Going back to the previous e-commerce app example, this is how a &lt;strong&gt;Product&lt;/strong&gt; lifecycle hook that sends an email notification every time a new product is created could look like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;* Triggered before user creation.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;lifecycles: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;afterCreate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; strapi.plugins[&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].services.email.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;to: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;customers@my-store.io&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;from: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;noreply@my-store.io&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;subject: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;New Product Available!&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;text: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Check out this amazing new product :)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = {  /**   * Triggered before user creation.   */  lifecycles: {    async afterCreate(data) {      await strapi.plugins[&amp;#x27;email&amp;#x27;].services.email.send({        to: &amp;#x27;customers@my-store.io&amp;#x27;,        from: &amp;#x27;noreply@my-store.io&amp;#x27;,        subject: &amp;#x27;New Product Available!&amp;#x27;,        text: &amp;#x27;Check out this amazing new product :)&amp;#x27;,      });    },  },};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;server-hooks&quot;&gt;Server Hooks&lt;/h2&gt;
&lt;p&gt;The second type of hooks - &lt;a href=&quot;https://strapi.io/documentation/v3.x/concepts/hooks.html#structure&quot;&gt;server hooks&lt;/a&gt; - allow us to add functionality to Strapi’s core.&lt;/p&gt;
&lt;p&gt;When the Strapi instance boots, server hooks are loaded into the global object, becoming therefore usable &lt;em&gt;anywhere&lt;/em&gt; in the application.&lt;/p&gt;
&lt;h3 id=&quot;use-case-examples-1&quot;&gt;Use Case Examples&lt;/h3&gt;
&lt;p&gt;By far, the most common application of server hooks is third-party service/API integration.&lt;/p&gt;
&lt;p&gt;Check out some of the hooks made available by the community:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/strapi-hook-algolia&quot;&gt;strapi-hook-algolia&lt;/a&gt;: This hook allows you to use &lt;a href=&quot;https://algolia.com&quot;&gt;Algolia&lt;/a&gt; as a service in Strapi &lt;code&gt;strapi.services.algolia&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/strapi-hook-magento&quot;&gt;strapi-hook-magento&lt;/a&gt;: This hook allows you to use the &lt;a href=&quot;https://devdocs.magento.com/guides/v2.4/rest/bk-rest.html&quot;&gt;Magento 2 Rest API&lt;/a&gt; with Strapi.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/strapi-hook-twitter&quot;&gt;strapi-hook-twitter&lt;/a&gt;: This hook allows you to use the &lt;a href=&quot;https://developer.twitter.com/en/docs/twitter-api&quot;&gt;Twitter API&lt;/a&gt; with Strapi.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/strapi-hook-allegro&quot;&gt;strapi-hook-allegro&lt;/a&gt;: This hook allows you to use &lt;a href=&quot;https://developer.allegro.pl/documentation/&quot;&gt;Allegro Rest API&lt;/a&gt; with Strapi.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The docs provide a &lt;a href=&quot;https://strapi.io/documentation/developer-docs/latest/guides/client.html&quot;&gt;detailed guide&lt;/a&gt; - using a GitHub client as an example - on how to integrate a third-party client in Strapi.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A pretty common development pattern of a server hook is to have it run an initialization function when the server boots, and then expose its functionality via methods made available either in &lt;a href=&quot;https://strapi.io/documentation/developer-docs/latest/global-strapi/api-reference.html#strapi-services&quot;&gt;&lt;code&gt;strapi.services&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://strapi.io/documentation/developer-docs/latest/global-strapi/api-reference.html#strapi-hook&quot;&gt;&lt;code&gt;strapi.hook&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a result of being available in the Strapi global object, a server hook may also, for instance, be combined with a lifecycle hook, allowing for even further custom functionality.&lt;/p&gt;
&lt;h3 id=&quot;how-to-implement-a-server-hook&quot;&gt;How to Implement a Server Hook&lt;/h3&gt;
&lt;p&gt;The code of a server hook goes inside a file named &lt;code&gt;index.js&lt;/code&gt;, and should follow the structure below:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;strapi&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;hook&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;* Default options&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;defaults: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// config object&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;* Initialize the hook&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;initialize&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Merge defaults and config/hook.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;settings&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.defaults, &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;strapi.config.hook.settings.&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// await someAsyncCode()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; hook;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = strapi =&gt; {  const hook = {    /**     * Default options     */    defaults: {      // config object    },    /**     * Initialize the hook     */    async initialize() {      // Merge defaults and config/hook.json      const settings = {...this.defaults, ...strapi.config.hook.settings.**};      // await someAsyncCode()    },  };  return hook;};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A server hook can be loaded either from a &lt;strong&gt;node module&lt;/strong&gt; or from the &lt;strong&gt;local hooks folder&lt;/strong&gt; (&lt;code&gt;./hooks&lt;/code&gt;) in the project.&lt;/p&gt;
&lt;p&gt;Every folder that follows the pattern &lt;code&gt;strapi-hook-*&lt;/code&gt; and is located in the &lt;code&gt;./node_modules&lt;/code&gt; folder will be mounted into the &lt;code&gt;strapi.hook&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;Every folder that’s inside the &lt;code&gt;./hooks&lt;/code&gt; folder will also be seen as a hook and mounted in the &lt;code&gt;strapi.hook&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;No matter the location from where it is loaded, for a hook to run at the instance boot, it needs to be enabled and configured in your Strapi app.
The &lt;code&gt;./config/hook.js&lt;/code&gt; file is where we enable the hook, alongside any optional custom settings:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;settings: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;hook-name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;enabled: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = {  settings: {    &amp;#x27;hook-name&amp;#x27;: {      enabled: true,    },  },};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s now examine the implementation specificities of each server hook location.&lt;/p&gt;
&lt;h4 id=&quot;node-module-hook&quot;&gt;Node Module Hook&lt;/h4&gt;
&lt;p&gt;The node module approach is useful if you’d like to publish the hook as an &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; package, so that it can be easily shared across multiple projects, and make use of all the features npm provides.&lt;/p&gt;
&lt;p&gt;A node module hook requires the following folder structure:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;/strapi-hook-[...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;└─── lib&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- index.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- LICENSE.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- package.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- README.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;/strapi-hook-[...]└─── lib     - index.js- LICENSE.md- package.json- README.md&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;index.js&lt;/code&gt; file is the entry point to the hook. It has to follow the structure of the &lt;code&gt;index.js&lt;/code&gt; example above.&lt;/p&gt;
&lt;h4 id=&quot;local-hook&quot;&gt;Local Hook&lt;/h4&gt;
&lt;p&gt;A local hook is a server hook that is imported directly from the &lt;code&gt;./hooks&lt;/code&gt; folder at the root of your project, without having to be installed through npm. It’s useful for project-specific hooks that won’t be reused in other Strapi projects.&lt;/p&gt;
&lt;p&gt;To add a local hook to your project, create a folder with the name of the hook and a &lt;code&gt;index.js&lt;/code&gt; file inside it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;/project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;└─── admin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;└─── api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;└─── config&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;│    - hook.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;└─── hooks&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;│   └─── strapi-my-local-hook&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;│        - index.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;└─── public&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- favicon.ico&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- package.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;- server.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;/project└─── admin└─── api└─── config│    - hook.js└─── hooks│   └─── strapi-my-local-hook│        - index.js└─── public- favicon.ico- package.json- server.js&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;webhooks&quot;&gt;Webhooks&lt;/h2&gt;
&lt;p&gt;Finally, we get to the last type of hooks: &lt;a href=&quot;https://strapi.io/documentation/v3.x/concepts/webhooks.html#what-is-a-webhook&quot;&gt;webhooks&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sunny Hsiao wrote an &lt;a href=&quot;https://strapi.io/blog/what-is-a-webhook-and-how-does-it-work&quot;&gt;article specifically about webhooks&lt;/a&gt;, going more in-depth than I will in this general overview, so I recommend you check it out if you’d like to dive deeper into webhooks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Webhooks are not exclusive to Strapi. An application that implements webhooks is able to notify other applications as a certain event occurs in its context.&lt;/p&gt;
&lt;p&gt;Technically, webhooks are typically implemented as HTTP POST requests.&lt;/p&gt;
&lt;h3 id=&quot;use-case-examples-2&quot;&gt;Use Case Examples&lt;/h3&gt;
&lt;p&gt;A webhook can be a great tool to notify third-party providers to run CI/CD operations, such as build or deploy.&lt;/p&gt;
&lt;p&gt;Recently, I’ve come across a very interesting use case in &lt;a href=&quot;https://www.youtube.com/watch?v=u9pg5fuKI9s&quot;&gt;this Strapi webinar by Charles Ouellet&lt;/a&gt;, where a webhook is used to rebuild a Nuxt static site whenever the content is updated in Strapi.&lt;/p&gt;
&lt;h3 id=&quot;how-to-configure-a-webhook&quot;&gt;How to Configure a Webhook&lt;/h3&gt;
&lt;p&gt;The webhook configuration panel is accessible from the Admin Panel, from the sidebar, in &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Webhooks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To create a new webhook, click the &lt;strong&gt;Add new webhook&lt;/strong&gt; button in the top-right of the panel:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Admin Panel&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3360&quot; height=&quot;1878&quot; src=&quot;https://ramigs.dev/_astro/strapi-hooks-admin-panel-webhooks.CR8BSMdB_Z19wE7z.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Next, you’ll need to fill in the &lt;strong&gt;Create a webhook&lt;/strong&gt; form with the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name&lt;/li&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;li&gt;Request headers&lt;/li&gt;
&lt;li&gt;Trigger events&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Create a Webhook&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3360&quot; height=&quot;1878&quot; src=&quot;https://ramigs.dev/_astro/strapi-hooks-create-a-webhook.ALUAyO5i_1EmdyV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;By default, Strapi provides a set of events that can trigger a webhook.
These events are related to either a &lt;strong&gt;Content-Type entry&lt;/strong&gt; or to a &lt;strong&gt;media asset&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For Content-Type entries, we have the following events available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;create&lt;/code&gt;: When an entry is created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update&lt;/code&gt;: When an entry is updated.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt;: When an entry is deleted.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;publish&lt;/code&gt;: When an entry is published (available when &lt;a href=&quot;https://strapi.io/documentation/developer-docs/latest/concepts/draft-and-publish.html&quot;&gt;draft and publish&lt;/a&gt; is enabled on the Content-Type).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unpublish&lt;/code&gt;: When an entry is unpublished (available when draft and publish is enabled on the Content-Type).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For media assets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;create&lt;/code&gt;: When a media asset is created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update&lt;/code&gt;: When a media asset is updated.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt;: When a media asset is deleted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s how a sample webhook payload looks like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;event&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;entry.create&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;2020-01-10T08:47:36.649Z&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;entry&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;geolocation&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;city&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Paris&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;postal_code&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;full_name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Paris&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;2020-01-10T08:47:36.264Z&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;updated_at&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;2020-01-10T08:47:36.264Z&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;cover&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;images&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: []&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;event&amp;quot;: &amp;quot;entry.create&amp;quot;,  &amp;quot;created_at&amp;quot;: &amp;quot;2020-01-10T08:47:36.649Z&amp;quot;,  &amp;quot;model&amp;quot;: &amp;quot;address&amp;quot;,  &amp;quot;entry&amp;quot;: {    &amp;quot;id&amp;quot;: 1,    &amp;quot;geolocation&amp;quot;: {},    &amp;quot;city&amp;quot;: &amp;quot;Paris&amp;quot;,    &amp;quot;postal_code&amp;quot;: null,    &amp;quot;category&amp;quot;: null,    &amp;quot;full_name&amp;quot;: &amp;quot;Paris&amp;quot;,    &amp;quot;created_at&amp;quot;: &amp;quot;2020-01-10T08:47:36.264Z&amp;quot;,    &amp;quot;updated_at&amp;quot;: &amp;quot;2020-01-10T08:47:36.264Z&amp;quot;,    &amp;quot;cover&amp;quot;: null,    &amp;quot;images&amp;quot;: []  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can also set additional webhook global header configurations. This is done in the &lt;code&gt;./config/server.js&lt;/code&gt; file and will be applied to all the outgoing webhooks:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;webhooks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;defaultHeaders: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;Custom-Header&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;my-custom-header&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = {  webhooks: {    defaultHeaders: {      &amp;#x27;Custom-Header&amp;#x27;: &amp;#x27;my-custom-header&amp;#x27;,    },  },};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If it’s an Authorization header, you can use &lt;code&gt;Authorization: &apos;Bearer my-very-secured-token&apos;,&lt;/code&gt; instead.
This will allow the notified applications to read the header and appropriately handle verification and authentication.&lt;/p&gt;
&lt;p&gt;Besides the explicitly configured headers, Strapi will also add another header named &lt;code&gt;X-Strapi-Event&lt;/code&gt;, where the corresponding value is the name of the event type that was triggered.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As we’ve seen, hooks are a great tool for customizing and extending Strapi’s core functionality.&lt;/p&gt;
&lt;p&gt;We’ve examined the three different types of Strapi hooks, presenting the main use cases for each type, when to use one or another, and how to implement them.&lt;/p&gt;
&lt;p&gt;I’d like to thank &lt;a href=&quot;https://forum.strapi.io/u/malgamves/summary&quot;&gt;malgamves&lt;/a&gt; for reviewing this article, as well as &lt;a href=&quot;https://forum.strapi.io/u/MattieBelt&quot;&gt;MattieBelt&lt;/a&gt; and &lt;a href=&quot;https://forum.strapi.io/u/yringler/summary&quot;&gt;yringler&lt;/a&gt; for the use case suggestions.&lt;/p&gt;
&lt;p&gt;If you have any cool use cases of Strapi hooks you’d like to share, you’re very welcome to join the &lt;a href=&quot;https://forum.strapi.io/t/strapi-hooks-use-cases/2001&quot;&gt;ongoing conversation&lt;/a&gt; in the forum.&lt;/p&gt;
</content:encoded></item><item><title>Strapi Authentication in Nuxt.js</title><link>https://ramigs.dev/blog/strapi-authentication-in-nuxt-js/</link><guid isPermaLink="true">https://ramigs.dev/blog/strapi-authentication-in-nuxt-js/</guid><description>This is a step-by-step guide on how to implement Strapi-based authentication in a Nuxt.js app.</description><pubDate>Tue, 25 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;(This article was originally published on &lt;a href=&quot;https://strapi.io/blog/strapi-authentication-in-nuxt-js&quot;&gt;strapi.io&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a step-by-step guide on how to implement Strapi-based authentication in
a Nuxt.js app.&lt;/p&gt;
&lt;p&gt;Here’s a preview of what we’re setting to achieve:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Preview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1264&quot; height=&quot;530&quot; src=&quot;https://ramigs.dev/_astro/nuxt-strapi-auth-preview.PCmSD_he_ZiPrqP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In essence, authentication is the process through which a website or app
verifies the identity of its users.&lt;/p&gt;
&lt;p&gt;As the gatekeeper to an app, authentication needs to be secure and reliable.
After all, it deals with user information, potentially the most critical data in
an app.&lt;/p&gt;
&lt;p&gt;Implementing a secure authentication mechanism from scratch is &lt;em&gt;hard&lt;/em&gt; and can
quickly become cumbersome. Where do you save the user data? Should you roll out
a database and model the user content type? What about registration, login, and
password reset?&lt;/p&gt;
&lt;p&gt;But it doesn’t end there. How to securely deal with passwords? Hashing and all
that fun stuff 😵.&lt;/p&gt;
&lt;p&gt;That’s a lot to think about, when you just want to dive into the core
functionality of the app you’re developing!&lt;/p&gt;
&lt;p&gt;You could build your own authentication mechanism, but do you really &lt;em&gt;need&lt;/em&gt; or
&lt;em&gt;want&lt;/em&gt; to? I’d say, better to rely on something that’s already built and
thoroughly tested before.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://strapi.io/&quot;&gt;Strapi&lt;/a&gt; is an awesome open source Node.js headless CMS,
backed by a large, &lt;a href=&quot;https://strapi.io/community&quot;&gt;active community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the cool things about Strapi is that it provides authentication right out
of the box, with built-in admin and user content types and API endpoints to perform the
main authentication operations.&lt;/p&gt;
&lt;p&gt;On the frontend, we’ll be using &lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt.js&lt;/a&gt; and relying on
Nuxt’s &lt;a href=&quot;https://auth.nuxtjs.org/&quot;&gt;Auth Module&lt;/a&gt;, which is the official
zero-boilerplate authentication module for Nuxt.js.&lt;/p&gt;
&lt;p&gt;So, in this article, we’ll be building two projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Backend: Strapi app to store and manage users&lt;/li&gt;
&lt;li&gt;Frontend: Nuxt app that will use Strapi’s API for authentication purposes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The source code for both projects can be found on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ramigs/strapi-users&quot;&gt;strapi-users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ramigs/nuxt-auth&quot;&gt;nuxt-auth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Strapi’s authentication scheme is based on email/username and password
credentials, along with JWT tokens. Upon successful authentication, the response
will return a JWT authentication token that will be added to subsequent API
requests. The Auth Module will conveniently help us manage this workflow.&lt;/p&gt;
&lt;p&gt;We will also be implementing some basic authorization features, such as
restricting certain pages to only logged in/out users.&lt;/p&gt;
&lt;p&gt;This guide builds on top of Chimezie Enyinnaya’s &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/implementing-authentication-in-nuxtjs-app&quot;&gt;awesome
work&lt;/a&gt;,
adapting it to Strapi’s specific use case, and adding also the following
features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Email confirmation for registration&lt;/li&gt;
&lt;li&gt;Password reset&lt;/li&gt;
&lt;li&gt;Token expiration strategy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I won’t go into detailed explanation at every step. Instead, I’ll focus on
Strapi and the new functionality. For everything else, I recommend you refer to
&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/implementing-authentication-in-nuxtjs-app&quot;&gt;Chimezie’s
tutorial&lt;/a&gt;
and the &lt;a href=&quot;https://auth.nuxtjs.org/#getting-started&quot;&gt;Auth Module documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pre-requisites&quot;&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;To follow this tutorial, make sure you have Node.js installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 12.x&lt;/li&gt;
&lt;li&gt;npm 6.x&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although not required, a basic knowledge of Strapi, Nuxt.js, and JWT
fundamentals is recommended.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: this tutorial was written based on Strapi 3.0.1 (stable release)
and Nuxt.js 2.12.2. It should work on different versions too, but you may need
to make some adaptations here and there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s get started!&lt;/p&gt;
&lt;h2 id=&quot;install-strapi&quot;&gt;Install Strapi&lt;/h2&gt;
&lt;p&gt;First things first, we begin by creating a Strapi project:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create-strapi-app&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;strapi-users&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;--quickstart&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx create-strapi-app strapi-users --quickstart&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ve used the &lt;code&gt;--quickstart&lt;/code&gt; flag that installs Strapi with default settings.
It also tells Strapi to use SQLite as the database engine and automatically run
our application.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our installation, we used the default database, SQLite, because it doesn’t
require a dedicated database server. Instead, the database is just a single
file. For the sake of convenience, we’ll be using it in this tutorial, but the
steps in this guide also apply to different database engines.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the installation is done, Strapi will automatically be launched in your
browser, asking you to create an administrator account.&lt;/p&gt;
&lt;p&gt;To finish the setup and secure your app, go ahead and create a root/admin user,
by filling-in the necessary information:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Admin&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2525&quot; height=&quot;1367&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-admin.thlFdVaZ_ZTFmLO.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;From now on, you can access Strapi’s local Admin interface by visiting
&lt;a href=&quot;http://localhost:1337/admin&quot;&gt;http://localhost:1337/admin&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;enable-email-confirmation&quot;&gt;Enable email confirmation&lt;/h2&gt;
&lt;p&gt;By default, the user registration process in Strapi does not include email
confirmation.&lt;/p&gt;
&lt;p&gt;To enable it, from the left sidebar of the Admin dashboard, click &lt;strong&gt;Roles &amp;amp;
Permissions&lt;/strong&gt;. Select the &lt;strong&gt;Advanced Settings&lt;/strong&gt; tab, enable the “Enable email
confirmation” option and save:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Enable email confirmation Strapi&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2516&quot; height=&quot;1273&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-enable-email-confirmation.Cunt5keE_Z1IXlQi.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;email-console-provider&quot;&gt;Email console provider&lt;/h2&gt;
&lt;p&gt;Thanks to Strapi’s Email plugin, we can have a Strapi instance send emails from
our server’s local email system or from an external provider (e.g., SendGrid).&lt;/p&gt;
&lt;p&gt;Email setup and configuration is not within the scope of this article. We just
want to make sure that the emails are being fired when expected and inspect
their content.&lt;/p&gt;
&lt;p&gt;For that, we’re going to use
&lt;a href=&quot;https://www.npmjs.com/package/strapi-provider-email-console&quot;&gt;strapi-provider-email-console&lt;/a&gt;,
a Strapi email mock provider used in development, that instead of sending,
outputs the emails to the console.&lt;/p&gt;
&lt;p&gt;Stop the Strapi app that’s running, navigate to the project’s root directory,
and install the email mock provider:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;strapi-users&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;strapi-provider-email-console&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd strapi-usersnpm install strapi-provider-email-console&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once the installation is done, you’ll need to add in the provider. Create the
file &lt;code&gt;./config/plugins.js&lt;/code&gt; and paste the following code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;email: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;provider: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = ({ env }) =&gt; ({  email: {    provider: &amp;quot;console&amp;quot;,  },});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Since we’ve used &lt;code&gt;--quickstart&lt;/code&gt; the first time we ran our Strapi app, before
running it in development mode, we need to install the dependencies:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once that’s done, start the Strapi app in development mode with the command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;develop&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm run develop&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;create-a-nuxt-app&quot;&gt;Create a Nuxt app&lt;/h2&gt;
&lt;p&gt;Now, let’s change gears and focus on the frontend app. It will be a Server-Side
Rendered “Universal” Nuxt.js app.&lt;/p&gt;
&lt;p&gt;To get started quickly, open a new terminal and create the project using Nuxt’s
scaffolding tool:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create-nuxt-app&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;nuxt-auth&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx create-nuxt-app nuxt-auth&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Go through the guide and make sure to select following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;axios and dotenv in the &lt;strong&gt;Nuxt.js modules&lt;/strong&gt; step&lt;/li&gt;
&lt;li&gt;Bulma CSS in the &lt;strong&gt;UI framework&lt;/strong&gt; step, which we’ll use to style our app&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Create a Nuxt app&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2390&quot; height=&quot;546&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-create-nuxt-app-options.DkbpQvJA_Z1afOV8.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Strapi’s API URL will vary depending on the environment. So, we want to have it
dynamically loaded from an environment variable.&lt;/p&gt;
&lt;p&gt;Once the tool finishes creating the app, edit the &lt;code&gt;.env&lt;/code&gt; file in the project’s
root directory, adding a new environment variable that points to the URL of the
Strapi app that’s running locally:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;API_AUTH_URL&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;http://localhost:1337&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;API_AUTH_URL=http://localhost:1337&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Next, navigate to the project’s root directory and install the required Nuxt
Auth module dependency:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;nuxt-auth&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;@nuxtjs/auth&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd nuxt-authnpm install @nuxtjs/auth&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once the installation is done, add the module &lt;code&gt;@nuxtjs/auth&lt;/code&gt; in
&lt;code&gt;./nuxt.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;modules&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Doc: https://github.com/nuxt-community/modules/tree/master/packages/bulma&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;@nuxtjs/bulma&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Doc: https://axios.nuxtjs.org/usage&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;@nuxtjs/axios&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Doc: https://github.com/nuxt-community/dotenv-module&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;@nuxtjs/dotenv&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;@nuxtjs/auth&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;modules: [  // Doc: https://github.com/nuxt-community/modules/tree/master/packages/bulma  &amp;#x27;@nuxtjs/bulma&amp;#x27;,  // Doc: https://axios.nuxtjs.org/usage  &amp;#x27;@nuxtjs/axios&amp;#x27;,  // Doc: https://github.com/nuxt-community/dotenv-module  &amp;#x27;@nuxtjs/dotenv&amp;#x27;,  &amp;#x27;@nuxtjs/auth&amp;#x27;],&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At the top of &lt;code&gt;nuxt.config.js&lt;/code&gt;, add also the following code to load the
environment variables:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;dotenv&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;require(&amp;quot;dotenv&amp;quot;).config();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;One last step we need to do in this file. Configure the base URL that axios will
use when making API requests. In our case, this corresponds to the environment
variable we’ve added previously:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;axios&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;baseURL&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;API_AUTH_URL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;axios: {  baseURL: process.env.API_AUTH_URL},&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;configure-nuxt-auth&quot;&gt;Configure Nuxt Auth&lt;/h2&gt;
&lt;p&gt;The Auth module uses Vuex’s state management to store the user authentication
status and user info.&lt;/p&gt;
&lt;p&gt;Enable the Vuex store by creating a file &lt;code&gt;./store/index.js&lt;/code&gt; with the store
getters:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;getters&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;isAuthenticated&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; state.auth.loggedIn;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;loggedInUser&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; state.auth.user;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export const getters = {  isAuthenticated(state) {    return state.auth.loggedIn;  },  loggedInUser(state) {    return state.auth.user;  },};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now we are ready to configure the Auth module. The default, general purpose
authentication scheme - supporting Cookie and JWT login flows - is named
&lt;code&gt;local&lt;/code&gt;. Let’s now map its endpoints with Strapi’s authentication endpoints.&lt;/p&gt;
&lt;p&gt;Paste the code below into &lt;code&gt;./nuxt.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;/*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;** Auth module configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;** See https://auth.nuxtjs.org/schemes/local.html#options&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;auth&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;strategies&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;endpoints&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;auth/local&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;post&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;propertyName&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;jwt&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;users/me&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;get&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;propertyName&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;logout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;/* ** Auth module configuration ** See https://auth.nuxtjs.org/schemes/local.html#options */auth: {  strategies: {    local: {      endpoints: {        login: {          url: &amp;#x27;auth/local&amp;#x27;,          method: &amp;#x27;post&amp;#x27;,          propertyName: &amp;#x27;jwt&amp;#x27;        },        user: {          url: &amp;#x27;users/me&amp;#x27;,          method: &amp;#x27;get&amp;#x27;,          propertyName: false        },        logout: false      }    }  }},&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ve set up two endpoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;login&lt;/code&gt;: authenticates the user. On successful authentication, the JWT token
will be available in the &lt;code&gt;jwt&lt;/code&gt; property of the response object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user&lt;/code&gt;: retrieves the authenticated user’s info. If the user is authenticated,
the JWT token will be added to the request, allowing Strapi to identify the
user. Since the response object is already the user info itself, we set
&lt;code&gt;propertyName&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ve also disabled the &lt;code&gt;logout&lt;/code&gt; endpoint, since logging out a user is only done
locally, and doesn’t require any request to Strapi’s API. The token is simply
removed the from the local storage when the user logs out.&lt;/p&gt;
&lt;h2 id=&quot;navbar-component&quot;&gt;Navbar Component&lt;/h2&gt;
&lt;p&gt;Create a file &lt;code&gt;./components/Navbar.vue&lt;/code&gt; with the following code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navigation&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aria-label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;main navigation&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-brand&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-item&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Home&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-burger burger&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aria-label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;menu&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aria-expanded&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;data-target&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbarBasicExample&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aria-hidden&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aria-hidden&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;aria-hidden&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbarBasicExample&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-menu&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;isAuthenticated&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-start&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-item has-dropdown is-hoverable&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-link&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{{ loggedInUser.username }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-dropdown&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-item&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/profile&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;My Profile&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;hr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-divider&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-item&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@click&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;logout&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Logout&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;!isAuthenticated&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-end&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;navbar-item&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;buttons&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button is-primary&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/register&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Register&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button is-light&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/login&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Log in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nav&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;nav class=&amp;quot;navbar&amp;quot; role=&amp;quot;navigation&amp;quot; aria-label=&amp;quot;main navigation&amp;quot;&gt;    &lt;div class=&amp;quot;navbar-brand&amp;quot;&gt;      &lt;nuxt-link class=&amp;quot;navbar-item&amp;quot; to=&amp;quot;/&amp;quot;&gt;Home&lt;/nuxt-link&gt;      &lt;a        role=&amp;quot;button&amp;quot;        class=&amp;quot;navbar-burger burger&amp;quot;        aria-label=&amp;quot;menu&amp;quot;        aria-expanded=&amp;quot;false&amp;quot;        data-target=&amp;quot;navbarBasicExample&amp;quot;      &gt;        &lt;span aria-hidden=&amp;quot;true&amp;quot;&gt;&lt;/span&gt;        &lt;span aria-hidden=&amp;quot;true&amp;quot;&gt;&lt;/span&gt;        &lt;span aria-hidden=&amp;quot;true&amp;quot;&gt;&lt;/span&gt;      &lt;/a&gt;    &lt;/div&gt;    &lt;div id=&amp;quot;navbarBasicExample&amp;quot; class=&amp;quot;navbar-menu&amp;quot;&gt;      &lt;div v-if=&amp;quot;isAuthenticated&amp;quot; class=&amp;quot;navbar-start&amp;quot;&gt;        &lt;div class=&amp;quot;navbar-item has-dropdown is-hoverable&amp;quot;&gt;          &lt;a class=&amp;quot;navbar-link&amp;quot;&gt;            {{ loggedInUser.username }}          &lt;/a&gt;          &lt;div class=&amp;quot;navbar-dropdown&amp;quot;&gt;            &lt;a class=&amp;quot;navbar-item&amp;quot; href=&amp;quot;/profile&amp;quot;&gt;My Profile&lt;/a&gt;            &lt;hr class=&amp;quot;navbar-divider&amp;quot; /&gt;            &lt;a class=&amp;quot;navbar-item&amp;quot; @click=&amp;quot;logout&amp;quot;&gt;Logout&lt;/a&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;      &lt;div v-if=&amp;quot;!isAuthenticated&amp;quot; class=&amp;quot;navbar-end&amp;quot;&gt;        &lt;div class=&amp;quot;navbar-item&amp;quot;&gt;          &lt;div class=&amp;quot;buttons&amp;quot;&gt;            &lt;nuxt-link class=&amp;quot;button is-primary&amp;quot; to=&amp;quot;/register&amp;quot;&gt;              &lt;strong&gt;Register&lt;/strong&gt;            &lt;/nuxt-link&gt;            &lt;nuxt-link class=&amp;quot;button is-light&amp;quot; to=&amp;quot;/login&amp;quot;&gt;              Log in            &lt;/nuxt-link&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/nav&gt;&lt;/template&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let us make the component functional by adding the following &lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;
code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;import { mapGetters } from &quot;vuex&quot;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;export default {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;computed: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mapGetters&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;isAuthenticated&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;loggedInUser&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mounted&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Get all &quot;navbar-burger&quot; elements&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;const $navbarBurgers &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;prototype&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.slice.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;document.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;.navbar-burger&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Check if there are any navbar burgers&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ($navbarBurgers.length &amp;gt; 0) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Add a click event on each of them&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$navbarBurgers.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;el.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Get the target from the &quot;data-target&quot; attribute&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; el.dataset.target;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;$target&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(target);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#616972;--1:#99A0A6&quot;&gt;// Toggle the &quot;is-active&quot; class on both the &quot;navbar-burger&quot; and the &quot;navbar-menu&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;el.classList.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;toggle&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;is-active&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$target.classList.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;toggle&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;is-active&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;script&gt;import { mapGetters } from &amp;quot;vuex&amp;quot;;export default {  computed: {    ...mapGetters([&amp;quot;isAuthenticated&amp;quot;, &amp;quot;loggedInUser&amp;quot;]),  },  mounted() {    // Get all &amp;quot;navbar-burger&amp;quot; elements    const $navbarBurgers = Array.prototype.slice.call(      document.querySelectorAll(&amp;quot;.navbar-burger&amp;quot;),      0    );    // Check if there are any navbar burgers    if ($navbarBurgers.length &gt; 0) {      // Add a click event on each of them      $navbarBurgers.forEach((el) =&gt; {        el.addEventListener(&amp;quot;click&amp;quot;, () =&gt; {          // Get the target from the &amp;quot;data-target&amp;quot; attribute          const target = el.dataset.target;          const $target = document.getElementById(target);          // Toggle the &amp;quot;is-active&amp;quot; class on both the &amp;quot;navbar-burger&amp;quot; and the &amp;quot;navbar-menu&amp;quot;          el.classList.toggle(&amp;quot;is-active&amp;quot;);          $target.classList.toggle(&amp;quot;is-active&amp;quot;);        });      });    }  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ve defined the computed properties &lt;code&gt;isAuthenticated&lt;/code&gt; and &lt;code&gt;loggedInUser&lt;/code&gt; used
in the component’s template. These are mapped from the previously created store
getters.&lt;/p&gt;
&lt;p&gt;The code in the &lt;code&gt;mounted&lt;/code&gt; hook comes from &lt;a href=&quot;https://bulma.io/documentation/components/navbar/&quot;&gt;Bulma’s Navbar
documentation&lt;/a&gt;. Its purpose
is to toggle the display of the &lt;code&gt;navbar-menu&lt;/code&gt; when the &lt;code&gt;navbar-burger&lt;/code&gt; icon is
clicked.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The navbar burger menu is displayed on smaller screen sizes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;default-layout&quot;&gt;Default Layout&lt;/h2&gt;
&lt;p&gt;Edit &lt;code&gt;./layouts/default.vue&lt;/code&gt; and replace its content with the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Navbar&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; Navbar &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;~/components/Navbar&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;components: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Navbar,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;div&gt;    &lt;Navbar /&gt;    &lt;nuxt /&gt;  &lt;/div&gt;&lt;/template&gt;&lt;script&gt;import Navbar from &amp;quot;~/components/Navbar&amp;quot;;export default {  components: {    Navbar,  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;homepage&quot;&gt;Homepage&lt;/h2&gt;
&lt;p&gt;Edit &lt;code&gt;./pages/index.vue&lt;/code&gt; and replace its content with the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Nuxt Strapi Auth&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;h1 class=&amp;quot;title&amp;quot;&gt;Nuxt Strapi Auth&lt;/h1&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is what we have so far:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt Homepage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2541&quot; height=&quot;708&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-homepage.DoaHpQlY_Z10g0GE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;notification-component&quot;&gt;Notification Component&lt;/h2&gt;
&lt;p&gt;Let’s create a Notification component to give feedback to the user.&lt;/p&gt;
&lt;p&gt;If everything goes as expected it should display a success message. Otherwise,
an error message should be displayed.&lt;/p&gt;
&lt;p&gt;Create a file &lt;code&gt;./components/Notification.vue&lt;/code&gt; and paste into it the code below:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;`is-${type}`&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;notification&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{{ message }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;name: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Notification&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;props: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;type: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;type: String,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;default: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;validator&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: (&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;danger&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(val),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;message: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;type: String,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;default: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;div :class=&amp;quot;&amp;#x60;is-${type}&amp;#x60;&amp;quot; class=&amp;quot;notification&amp;quot;&gt;    {{ message }}  &lt;/div&gt;&lt;/template&gt;&lt;script&gt;export default {  name: &amp;quot;Notification&amp;quot;,  props: {    type: {      type: String,      default: &amp;quot;success&amp;quot;,      validator: (val) =&gt; [&amp;quot;danger&amp;quot;, &amp;quot;success&amp;quot;].includes(val),    },    message: {      type: String,      default: &amp;quot;&amp;quot;,    },  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;register&quot;&gt;Register&lt;/h2&gt;
&lt;p&gt;Create a file &lt;code&gt;./pages/register.vue&lt;/code&gt; and paste into it the code below:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;columns&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;column is-4 is-offset-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title has-text-centered&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Register&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;danger&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;!success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@submit.prevent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;register&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Username&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;required&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Email&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;required&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Password&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;required&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button is-dark is-fullwidth&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Register&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;has-text-centered&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;margin-top: 20px&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Already got an account? &amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/login&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Login&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; Notification &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;~/components/Notification&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;components: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Notification,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;username: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;email: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;methods: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$axios.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;setToken&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$axios.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;auth/local/register&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;username: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.username,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;email: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.email,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.password,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.success &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;`A confirmation link has been sent to your email account. &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Please click on the link to complete the registration process.`&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (e) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; e.response.data.message[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].messages[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].message;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;div class=&amp;quot;columns&amp;quot;&gt;        &lt;div class=&amp;quot;column is-4 is-offset-4&amp;quot;&gt;          &lt;h2 class=&amp;quot;title has-text-centered&amp;quot;&gt;Register&lt;/h2&gt;          &lt;Notification v-if=&amp;quot;success&amp;quot; type=&amp;quot;success&amp;quot; :message=&amp;quot;success&amp;quot; /&gt;          &lt;Notification v-if=&amp;quot;error&amp;quot; type=&amp;quot;danger&amp;quot; :message=&amp;quot;error&amp;quot; /&gt;          &lt;form v-if=&amp;quot;!success&amp;quot; method=&amp;quot;post&amp;quot; @submit.prevent=&amp;quot;register&amp;quot;&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Username&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;username&amp;quot;                  type=&amp;quot;text&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;username&amp;quot;                  required                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Email&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;email&amp;quot;                  type=&amp;quot;email&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;email&amp;quot;                  required                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Password&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;password&amp;quot;                  type=&amp;quot;password&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;password&amp;quot;                  required                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;control&amp;quot;&gt;              &lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;button is-dark is-fullwidth&amp;quot;&gt;                Register              &lt;/button&gt;            &lt;/div&gt;          &lt;/form&gt;          &lt;div class=&amp;quot;has-text-centered&amp;quot; style=&amp;quot;margin-top: 20px&amp;quot;&gt;            Already got an account? &lt;nuxt-link to=&amp;quot;/login&amp;quot;&gt;Login&lt;/nuxt-link&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&lt;script&gt;import Notification from &amp;quot;~/components/Notification&amp;quot;;export default {  components: {    Notification,  },  data() {    return {      username: &amp;quot;&amp;quot;,      email: &amp;quot;&amp;quot;,      password: &amp;quot;&amp;quot;,      success: null,      error: null,    };  },  methods: {    async register() {      this.error = null;      try {        this.$axios.setToken(false);        await this.$axios.post(&amp;quot;auth/local/register&amp;quot;, {          username: this.username,          email: this.email,          password: this.password,        });        this.success = &amp;#x60;A confirmation link has been sent to your email account. \        Please click on the link to complete the registration process.&amp;#x60;;      } catch (e) {        this.error = e.response.data.message[0].messages[0].message;      }    },  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Before making the request to Strapi’s register endpoint, we make sure no token
is added as a request header.&lt;/p&gt;
&lt;h3 id=&quot;redirect-after-confirmation&quot;&gt;Redirect after confirmation&lt;/h3&gt;
&lt;p&gt;Before we can test the register feature, we need to tell Strapi where to
redirect the user after the confirmation link is accessed.&lt;/p&gt;
&lt;p&gt;To specify this link, from the left sidebar of the Admin dashboard, click
&lt;strong&gt;Roles &amp;amp; Permissions&lt;/strong&gt;. Select the &lt;strong&gt;Advanced Settings&lt;/strong&gt; tab, paste
&lt;code&gt;http://localhost:3000/login&lt;/code&gt; in the “Redirection url” input, and save:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Redirect After Confirmation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2518&quot; height=&quot;1324&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-redirect-after-confirmation.BugiK58b_Z1JGrWC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;configure-strapis-server-url&quot;&gt;Configure Strapi’s Server URL&lt;/h3&gt;
&lt;p&gt;We also need to configure Strapi’s public URL. This URL will be used to prefix
the confirmation link that’s sent.&lt;/p&gt;
&lt;p&gt;Inside the Strapi project root folder, create a &lt;code&gt;.env&lt;/code&gt; file by copying it from
&lt;code&gt;.env.example&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.env.example&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.env&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cp .env.example .env&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Edit &lt;code&gt;.env&lt;/code&gt; and add the &lt;code&gt;URL&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;http://localhost:1337&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;URL=http://localhost:1337&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Edit &lt;code&gt;./config/server.js&lt;/code&gt; and add the &lt;code&gt;url&lt;/code&gt; property:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;URL&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;http://localhost:1337&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;url: env(&amp;quot;URL&amp;quot;, &amp;quot;http://localhost:1337&amp;quot;),&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that we’ve set this configuration in the development environment. In
production, you’ll probably want to have SSL, so you’ll also need to install
and configure an upstream proxy application, such as Nginx - and &lt;a href=&quot;https://strapi.io/documentation/v3.x/deployment/nginx-proxy.html&quot;&gt;make Strapi
aware of
it&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;testing-register&quot;&gt;Testing Register&lt;/h3&gt;
&lt;p&gt;We’re now ready to test the register feature.&lt;/p&gt;
&lt;p&gt;Open a new terminal - so that the Strapi app is still running - and run the Nuxt
app in development mode:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm run dev&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Navigate to &lt;a href=&quot;http://localhost:3000/register&quot;&gt;http://localhost:3000/register&lt;/a&gt; and
register a user:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt Register Page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2537&quot; height=&quot;1022&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-register-page.D6fzbHaA_ZAC3D.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If the registration was successful, a success message is displayed by the
Notification component, requesting that the user completes the registration
process by clicking the confirmation link that was sent:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Register Success&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2539&quot; height=&quot;581&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-register-success.BU5UYLGk_Z121Abh.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;If an error occurs, the error message is displayed by the Notification component
we’ve created previously:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Register Error&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2543&quot; height=&quot;1088&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-register-error.ChW1BEpD_Z2bFfei.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Switch to the console where Strapi is running and confirm that you see the
email:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Register Email Console&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2552&quot; height=&quot;445&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-register-email-console.9gKv1j4i_Z7k1Rf.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Copy the confirmation link and access it in your browser. This action completes
the registration but you’ll see a “This page could not be found” error in your
browser. That’s because we haven’t implemented the login page yet.&lt;/p&gt;
&lt;p&gt;Let’s fix that.&lt;/p&gt;
&lt;h2 id=&quot;login&quot;&gt;Login&lt;/h2&gt;
&lt;p&gt;Create a file &lt;code&gt;./pages/login.vue&lt;/code&gt; and paste into it the code below:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;columns&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;column is-4 is-offset-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title has-text-centered&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Log In&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;danger&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@submit.prevent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;login&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Email&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Password&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button is-dark&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Log In&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;margin-top: 20px&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Don&apos;t have an account?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/register&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Register&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/forgot-password&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Forgot Password?&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;nuxt-link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; Notification &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;~/components/Notification&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;components: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Notification,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;email: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;methods: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$auth.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;loginWith&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;local&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;data: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;identifier: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.email,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.password,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$router.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (e) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; e.response.data.message[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].messages[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].message;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;div class=&amp;quot;columns&amp;quot;&gt;        &lt;div class=&amp;quot;column is-4 is-offset-4&amp;quot;&gt;          &lt;h2 class=&amp;quot;title has-text-centered&amp;quot;&gt;Log In&lt;/h2&gt;          &lt;Notification v-if=&amp;quot;error&amp;quot; type=&amp;quot;danger&amp;quot; :message=&amp;quot;error&amp;quot; /&gt;          &lt;form method=&amp;quot;post&amp;quot; @submit.prevent=&amp;quot;login&amp;quot;&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Email&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;email&amp;quot;                  type=&amp;quot;email&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;email&amp;quot;                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Password&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;password&amp;quot;                  type=&amp;quot;password&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;password&amp;quot;                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;control&amp;quot;&gt;              &lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;button is-dark&amp;quot;&gt;                Log In              &lt;/button&gt;            &lt;/div&gt;          &lt;/form&gt;          &lt;div style=&amp;quot;margin-top: 20px&amp;quot;&gt;            &lt;p&gt;              Don&amp;#x27;t have an account?              &lt;nuxt-link to=&amp;quot;/register&amp;quot;&gt;Register&lt;/nuxt-link&gt;            &lt;/p&gt;            &lt;p&gt;              &lt;nuxt-link to=&amp;quot;/forgot-password&amp;quot;&gt;Forgot Password?&lt;/nuxt-link&gt;            &lt;/p&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&lt;script&gt;import Notification from &amp;quot;~/components/Notification&amp;quot;;export default {  components: {    Notification,  },  data() {    return {      email: &amp;quot;&amp;quot;,      password: &amp;quot;&amp;quot;,      error: null,    };  },  methods: {    async login() {      this.error = null;      try {        await this.$auth.loginWith(&amp;quot;local&amp;quot;, {          data: {            identifier: this.email,            password: this.password,          },        });        this.$router.push(&amp;quot;/&amp;quot;);      } catch (e) {        this.error = e.response.data.message[0].messages[0].message;      }    },  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;testing-login&quot;&gt;Testing Login&lt;/h3&gt;
&lt;p&gt;Navigate to &lt;a href=&quot;http://localhost:3000/login&quot;&gt;http://localhost:3000/login&lt;/a&gt; and login
with a previously registered user:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt Login&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2545&quot; height=&quot;852&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-login.A3KlaJp-_HVTS6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Notice the changes in the Navbar:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt Login Navbar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2536&quot; height=&quot;560&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-login-navbar.CxmRc9HC_Z19F82T.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;logout&quot;&gt;Logout&lt;/h2&gt;
&lt;p&gt;Let’s now add the &lt;code&gt;logout&lt;/code&gt; method that’s triggered when the user clicks the
&lt;strong&gt;Logout&lt;/strong&gt; Navbar link.&lt;/p&gt;
&lt;p&gt;Edit &lt;code&gt;./components/Navbar.vue&lt;/code&gt; and add the following code under &lt;code&gt;mounted()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;methods&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;async &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;logout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$auth.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;logout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;methods: {    async logout() {      await this.$auth.logout()    }  }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;user-profile&quot;&gt;User Profile&lt;/h2&gt;
&lt;p&gt;Time for the user profile page.&lt;/p&gt;
&lt;p&gt;Create a file &lt;code&gt;./pages/profile.vue&lt;/code&gt; with the following code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;My Profile&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Username:&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{{ loggedInUser.username }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Email:&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{{ loggedInUser.email }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { mapGetters } &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;vuex&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;middleware: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;auth&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;computed: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mapGetters&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;loggedInUser&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;h2 class=&amp;quot;title&amp;quot;&gt;My Profile&lt;/h2&gt;      &lt;div class=&amp;quot;content&amp;quot;&gt;        &lt;p&gt;          &lt;strong&gt;Username:&lt;/strong&gt;          {{ loggedInUser.username }}        &lt;/p&gt;        &lt;p&gt;          &lt;strong&gt;Email:&lt;/strong&gt;          {{ loggedInUser.email }}        &lt;/p&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&lt;script&gt;import { mapGetters } from &amp;quot;vuex&amp;quot;;export default {  middleware: &amp;quot;auth&amp;quot;,  computed: {    ...mapGetters([&amp;quot;loggedInUser&amp;quot;]),  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;auth&lt;/code&gt; middleware guarantees that only logged in users can access this page.&lt;/p&gt;
&lt;h2 id=&quot;guest-middleware&quot;&gt;Guest middleware&lt;/h2&gt;
&lt;p&gt;If the user is already logged in, it’s probably a good idea to block the access
to the register and login pages.&lt;/p&gt;
&lt;p&gt;Create a file &lt;code&gt;./middleware/guest.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;store&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;redirect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (store.state.auth.loggedIn) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;redirect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export default function ({ store, redirect }) {  if (store.state.auth.loggedIn) {    return redirect(&amp;quot;/&amp;quot;);  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Define the new middleware in &lt;code&gt;./pages/register.vue&lt;/code&gt; and &lt;code&gt;./pages/login.vue&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;middleware: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;guest&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export default {  middleware: &amp;quot;guest&amp;quot;,};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;password-reset&quot;&gt;Password Reset&lt;/h2&gt;
&lt;p&gt;Let’s now implement a password reset mechanism.&lt;/p&gt;
&lt;p&gt;This will be achieved with the following workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;Forgot Password Page&lt;/strong&gt;, user submits email.&lt;/li&gt;
&lt;li&gt;If the email is in Strapi’s user database, user receives email with a link to
the &lt;strong&gt;Reset Password Page&lt;/strong&gt; containing a reset code as a URL parameter.&lt;/li&gt;
&lt;li&gt;User clicks the link and specifies a new password.&lt;/li&gt;
&lt;li&gt;The new password is sent to Strapi, along with the reset code.&lt;/li&gt;
&lt;li&gt;The password is updated and the user can now use it to login.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;forgot-password-page&quot;&gt;Forgot Password Page&lt;/h3&gt;
&lt;p&gt;Create a file &lt;code&gt;./pages/forgot-password.vue&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;columns&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;column is-4 is-offset-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title has-text-centered&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Forgot Password&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;danger&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;!success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@submit.prevent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;forgotPassword&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Email&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button is-dark&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Email me a reset link&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; Notification &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;~/components/Notification&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;middleware: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;guest&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;components: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Notification,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;email: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;methods: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;forgotPassword&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$axios.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;auth/forgot-password&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;email: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.email,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.success &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;`A reset password link has been sent to your email account. &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;Please click on the link to complete the password reset.`&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (e) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; e.response.data.message[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].messages[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].message;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;div class=&amp;quot;columns&amp;quot;&gt;        &lt;div class=&amp;quot;column is-4 is-offset-4&amp;quot;&gt;          &lt;h2 class=&amp;quot;title has-text-centered&amp;quot;&gt;Forgot Password&lt;/h2&gt;          &lt;Notification v-if=&amp;quot;success&amp;quot; type=&amp;quot;success&amp;quot; :message=&amp;quot;success&amp;quot; /&gt;          &lt;Notification v-if=&amp;quot;error&amp;quot; type=&amp;quot;danger&amp;quot; :message=&amp;quot;error&amp;quot; /&gt;          &lt;form v-if=&amp;quot;!success&amp;quot; method=&amp;quot;post&amp;quot; @submit.prevent=&amp;quot;forgotPassword&amp;quot;&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Email&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;email&amp;quot;                  type=&amp;quot;email&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;email&amp;quot;                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;control&amp;quot;&gt;              &lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;button is-dark&amp;quot;&gt;                Email me a reset link              &lt;/button&gt;            &lt;/div&gt;          &lt;/form&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&lt;script&gt;import Notification from &amp;quot;~/components/Notification&amp;quot;;export default {  middleware: &amp;quot;guest&amp;quot;,  components: {    Notification,  },  data() {    return {      email: &amp;quot;&amp;quot;,      success: null,      error: null,    };  },  methods: {    async forgotPassword() {      try {        await this.$axios.post(&amp;quot;auth/forgot-password&amp;quot;, {          email: this.email,        });        this.error = null;        this.success = &amp;#x60;A reset password link has been sent to your email account. \        Please click on the link to complete the password reset.&amp;#x60;;      } catch (e) {        this.error = e.response.data.message[0].messages[0].message;      }    },  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;In our implementation we’re disclosing whether the email is registered or not.
The reason is to show that Strapi gives us that information. However, for
applications with greater security requirements, we could also just display
the success message, whether Strapi responds with an error or not - helping
the prevention of phishing attacks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt Reset Password Page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2539&quot; height=&quot;657&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-forgot-password-form.DXkptEN9_97oHx.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The method &lt;code&gt;forgotPassword&lt;/code&gt; sends a request to Strapi’s &lt;code&gt;auth/forgot-password&lt;/code&gt;
endpoint. If the email address exists in Strapi’s user database, an email is
sent with a link to a reset password page in the frontend app.&lt;/p&gt;
&lt;p&gt;To specify this link, from the left sidebar of the Admin dashboard, click
&lt;strong&gt;Roles &amp;amp; Permissions&lt;/strong&gt;. Select the &lt;strong&gt;Advanced Settings&lt;/strong&gt; tab, paste
&lt;code&gt;http://localhost:3000/reset-password&lt;/code&gt; in the “Reset password page” input, and
save:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Reset Password Page Config&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2507&quot; height=&quot;797&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-reset-password-page-config.D6ETG3Zx_Z1qSknA.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Strapi will attach to it a URL parameter with the code that’s required to
successfully reset the user password.&lt;/p&gt;
&lt;h3 id=&quot;reset-password-page&quot;&gt;Reset Password Page&lt;/h3&gt;
&lt;p&gt;Let’s now create the page that will allow the user to define a new password.
Create a file &lt;code&gt;./pages/reset-password.vue&lt;/code&gt; and paste the following code into it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;columns&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;column is-4 is-offset-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title has-text-centered&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Reset Password&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;Notification&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;danger&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;!success&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@submit.prevent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;resetPassword&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;New Password&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password1&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;field&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;Confirm New Password&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-model&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password2&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;control&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;button is-dark&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Reset Password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; Notification &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;~/components/Notification&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;middleware: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;guest&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;components: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Notification,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;asyncData&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;context.route.query.code) context.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;redirect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/forgot-password&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;code: context.route.query.code,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password1: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password2: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;success: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;error: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;methods: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;resetPassword&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.password1 &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.password2) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Passwords do not match.&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$axios.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;auth/reset-password&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;code: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.code,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;password: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.password1,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;passwordConfirmation: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.password2,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.success &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Password updated successfully. You can now use it to log in to your account.&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (e) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.error &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; e.response.data.message[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].messages[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;].message;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;div class=&amp;quot;columns&amp;quot;&gt;        &lt;div class=&amp;quot;column is-4 is-offset-4&amp;quot;&gt;          &lt;h2 class=&amp;quot;title has-text-centered&amp;quot;&gt;Reset Password&lt;/h2&gt;          &lt;Notification v-if=&amp;quot;success&amp;quot; type=&amp;quot;success&amp;quot; :message=&amp;quot;success&amp;quot; /&gt;          &lt;Notification v-if=&amp;quot;error&amp;quot; type=&amp;quot;danger&amp;quot; :message=&amp;quot;error&amp;quot; /&gt;          &lt;form v-if=&amp;quot;!success&amp;quot; method=&amp;quot;post&amp;quot; @submit.prevent=&amp;quot;resetPassword&amp;quot;&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;New Password&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;password1&amp;quot;                  type=&amp;quot;password&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;password&amp;quot;                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;field&amp;quot;&gt;              &lt;label class=&amp;quot;label&amp;quot;&gt;Confirm New Password&lt;/label&gt;              &lt;div class=&amp;quot;control&amp;quot;&gt;                &lt;input                  v-model=&amp;quot;password2&amp;quot;                  type=&amp;quot;password&amp;quot;                  class=&amp;quot;input&amp;quot;                  name=&amp;quot;password&amp;quot;                /&gt;              &lt;/div&gt;            &lt;/div&gt;            &lt;div class=&amp;quot;control&amp;quot;&gt;              &lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;button is-dark&amp;quot;&gt;                Reset Password              &lt;/button&gt;            &lt;/div&gt;          &lt;/form&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&lt;script&gt;import Notification from &amp;quot;~/components/Notification&amp;quot;;export default {  middleware: &amp;quot;guest&amp;quot;,  components: {    Notification,  },  asyncData(context) {    if (!context.route.query.code) context.redirect(&amp;quot;/forgot-password&amp;quot;);    else      return {        code: context.route.query.code,      };  },  data() {    return {      password1: &amp;quot;&amp;quot;,      password2: &amp;quot;&amp;quot;,      success: null,      error: null,    };  },  methods: {    async resetPassword() {      this.error = null;      if (this.password1 !== this.password2) {        this.error = &amp;quot;Passwords do not match.&amp;quot;;        return;      }      try {        await this.$axios.post(&amp;quot;auth/reset-password&amp;quot;, {          code: this.code,          password: this.password1,          passwordConfirmation: this.password2,        });        this.success =          &amp;quot;Password updated successfully. You can now use it to log in to your account.&amp;quot;;      } catch (e) {        this.error = e.response.data.message[0].messages[0].message;      }    },  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;One more thing before we’re able to test the password reset feature. We need to
enable the Public Role permission for the &lt;code&gt;auth/reset-password&lt;/code&gt; endpoint.&lt;/p&gt;
&lt;p&gt;To specify this link, from the left sidebar of the Admin dashboard, click
&lt;strong&gt;Roles &amp;amp; Permissions&lt;/strong&gt;. Select the &lt;strong&gt;Advanced Settings&lt;/strong&gt; tab, paste
&lt;code&gt;http://localhost:3000/reset-password&lt;/code&gt; in the “Reset password page” input, and
save:&lt;/p&gt;
&lt;p&gt;To do so, from the left sidebar of the Admin dashboard, click &lt;strong&gt;Roles &amp;amp;
Permissions&lt;/strong&gt;. Click &lt;strong&gt;Public&lt;/strong&gt; and under &lt;strong&gt;Permissions&lt;/strong&gt; expand the
&lt;strong&gt;USERS-PERMISSIONS&lt;/strong&gt; plugin. Under &lt;strong&gt;Auth&lt;/strong&gt; check the option “resetpassword”
and save:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Reset Password&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2520&quot; height=&quot;936&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-reset-password.D6BuEL76_2ltT5z.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;testing-password-reset&quot;&gt;Testing Password Reset&lt;/h3&gt;
&lt;p&gt;Visit &lt;code&gt;http://localhost:3000/forgot-password&lt;/code&gt; in your browser, fill-in the
“Email” input with an email that has been registered before and click &lt;strong&gt;Email me
a reset link&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Reset Password Email Sent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2542&quot; height=&quot;602&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-reset-password-email-sent.D4ft5C4I_ZE6ygD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Switch to the terminal where Strapi is running and confirm that the mock email
is there:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Reset Password Email Console&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2543&quot; height=&quot;473&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-reset-password-email-console.El7TRYTS_Z24m2He.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Copy the entire link and access it in your browser:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Reset Password Form&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2545&quot; height=&quot;767&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-reset-password-form.L3ndgOb8_ZVykRC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Fill-in the form and click “Reset Password”. This action will reset the user
password:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Strapi Reset Password Success&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2550&quot; height=&quot;587&quot; src=&quot;https://ramigs.dev/_astro/strapi-nuxt-reset-password-success.CVn81Xxk_zNuL4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;token-expiration&quot;&gt;Token Expiration&lt;/h2&gt;
&lt;p&gt;Awesome! We’ve done a lot, but there’s still something missing before we wrap
up.&lt;/p&gt;
&lt;p&gt;If the JWT token expires, subsequent requests to Strapi will return a 401
Unauthorized error.&lt;/p&gt;
&lt;p&gt;To deal with this, we’ll intercept error responses in &lt;code&gt;axios&lt;/code&gt; and check if the
status code is &lt;code&gt;401&lt;/code&gt;. If it is, we redirect the user to the login page.&lt;/p&gt;
&lt;p&gt;Create a file &lt;code&gt;./plugins/axios.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;$axios&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;redirect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;$axios.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;onError&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;parseInt&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(error.response &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; error.response.status);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (code &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;401&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;redirect&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;/login&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export default function ({ $axios, redirect }) {  $axios.onError((error) =&gt; {    const code = parseInt(error.response &amp;amp;&amp;amp; error.response.status);    if (code === 401) redirect(&amp;quot;/login&amp;quot;);  });}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In &lt;code&gt;nuxt.config.js&lt;/code&gt; import the plugin we’ve just created:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;plugins&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;~plugins/axios&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;plugins: [&amp;#x27;~plugins/axios&amp;#x27;],&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, when the JWT expires the user will be gracefully redirected to the login page.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully you’ve found this tutorial helpful for implementing Strapi
authentication in your Nuxt app!&lt;/p&gt;
&lt;p&gt;You should now have a fully built, ready to be deployed in production
authentication flow, through which users can register, login, and reset their
password.&lt;/p&gt;
&lt;p&gt;The source code for both projects can be found on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ramigs/strapi-users&quot;&gt;strapi-users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ramigs/nuxt-auth&quot;&gt;nuxt-auth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>How to set up a canonical URL in Eleventy</title><link>https://ramigs.dev/blog/canonical-url-11ty/</link><guid isPermaLink="true">https://ramigs.dev/blog/canonical-url-11ty/</guid><description>How to set up a canonical URL in Eleventy cross posting content syndication</description><pubDate>Tue, 04 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Cross-posting can be a great way to expose your content to new, larger
audiences.&lt;/p&gt;
&lt;p&gt;Nonetheless, it’s important to consider the implications it can have on page
ranking and SEO.&lt;/p&gt;
&lt;p&gt;When you syndicate an article for publication on different domains, setting up a
canonical URL will let &lt;a href=&quot;https://support.google.com/webmasters/answer/139066?hl=en&quot;&gt;search
engines&lt;/a&gt; know which
page should be considered the original, and which ones duplication.&lt;/p&gt;
&lt;p&gt;To do this, we need to include in all the duplicate versions a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag
pointing to the &lt;strong&gt;&lt;a href=&quot;https://yoast.com/rel-canonical/&quot;&gt;canonical URL&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Implementing this in &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy&lt;/a&gt; is pretty
straight-forward.&lt;/p&gt;
&lt;p&gt;Edit your default layout (probably &lt;code&gt;_includes/layouts/base.njk&lt;/code&gt;), adding the
following inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{% if canonical %}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;canonical&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{{ canonical }}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{% endif %}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{% if canonical %}  &lt;link rel=&amp;quot;canonical&amp;quot; href=&amp;quot;{{ canonical }}&amp;quot; /&gt;{% endif %}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Basically, we’re conditionally adding the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag, depending on whether a
key &lt;code&gt;canonical&lt;/code&gt; exists in the &lt;a href=&quot;https://www.11ty.dev/docs/data-frontmatter/&quot;&gt;front
matter&lt;/a&gt; of the content page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you’re not using Nunjucks, check out the documentation of your template
language to find out how to conditionally render HTML.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then, in the front matter’s content file, simply add a &lt;code&gt;canonical&lt;/code&gt; key pointing
to the original URL, like so:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;canonical&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;https://dev.to/you/your-awesome-article&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;canonical: &amp;quot;https://dev.to/you/your-awesome-article&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Build your static site again and confirm that the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag is present.&lt;/p&gt;
&lt;p&gt;Done!&lt;/p&gt;
</content:encoded></item><item><title>Building a Jamstack app with Nuxt, Vue and FaunaDB</title><link>https://ramigs.dev/blog/building-a-jamstack-app-with-nuxt-vue-and-faunadb/</link><guid isPermaLink="true">https://ramigs.dev/blog/building-a-jamstack-app-with-nuxt-vue-and-faunadb/</guid><description>Changing the order of HTML elements between mobile and desktop layouts</description><pubDate>Tue, 14 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;(This article was originally published on &lt;a href=&quot;https://dev.to/ramigs/building-a-jamstack-app-with-nuxt-vue-and-faunadb-kg&quot;&gt;dev.to&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this article, we’ll be using a Jamstack approach to build a Repository
Catalogue.&lt;/p&gt;
&lt;p&gt;First, we’ll populate a &lt;a href=&quot;https://fauna.com/&quot;&gt;FaunaDB&lt;/a&gt; database with a set of
repos. For each repo, we’ll store its &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; URL, the
project’s name, logo, and main color.&lt;/p&gt;
&lt;p&gt;Then, at build time, we’ll use &lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt.js&lt;/a&gt; to fetch the repo
data from FaunaDB, and use it to pre-render the Repo Catalogue app.&lt;/p&gt;
&lt;p&gt;Finally, we’ll retrieve some highly dynamic repo info (such as number of stars
and forks) from the GitHub API, and with the help of &lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue’s&lt;/a&gt;
awesome client-side hydration features, display it in each repo’s page.&lt;/p&gt;
&lt;p&gt;Check out the working demo &lt;a href=&quot;https://elegant-hopper-28219e.netlify.app/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-a-repository-catalogue&quot;&gt;Why a Repository Catalogue?&lt;/h2&gt;
&lt;p&gt;As developers, we all have projects we admire/find interesting/look up to, and
like to keep track of.&lt;/p&gt;
&lt;p&gt;The Repository Catalogue will serve as a collection of GitHub projects, that you
can customize to display repo information that is more relevant to you.&lt;/p&gt;
&lt;p&gt;Although we’ll be building a very concrete implementation, its main purpose is
to serve as an example to the core underlying idea of this article.&lt;/p&gt;
&lt;p&gt;Harnessing both the benefits from pre-rendering and the flexibility of dynamic
sites, by generating as much as possible upfront, and loading the highly dynamic
data via JavaScript when the user visits the page. We’ll see that hydration is
the key that gives us the major benefit of a Single Page Application (no reloads
needed to display asynchronously requested data), while also getting the speed
of a statically loaded site.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“It’s usually a good idea to load as much data at build time as possible to
improve page performance. But if the data isn’t needed by all clients, or too
big to be sent to the client all at once, we can split things up and switch to
on-demand loading on the client. This is the case for user-specific data,
pagination, or any data that changes rather frequently and might be outdated by
the time it reaches the user.” - &lt;em&gt;&lt;a href=&quot;https://css-tricks.com/build-a-dynamic-jamstack-app-with-gatsbyjs-and-faunadb/&quot;&gt;Build a dynamic JAMstack app with GatsbyJS and FaunaDB&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When analyzing the requirements for a Repo Catalogue, we can straight away
identify two categories of data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Data that does not change often or not at all (e.g., project name, logo, repo
URL, and the repo list itself - after all, only some projects have a special
place in our heart 😄, so it’s not &lt;em&gt;that&lt;/em&gt; often we need to add or delete a
repo from the catalogue.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Data that changes frequently (e.g., repository number of stars and forks)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The former, is in our &lt;em&gt;control&lt;/em&gt; and therefore well-suited to be stored in a
Fauna’s database. Moreover, it can then serve as a data source for any client
app we decide to build.&lt;/p&gt;
&lt;p&gt;The latter comes from a third-party source and changes often, so it’s not a good
candidate for database storage. It’s preferable to fetch it dynamically only
when it’s needed, making sure we’re always getting the current data.&lt;/p&gt;
&lt;p&gt;One important consideration to make, is that this does not imply that FaunaDB is
only appropriate for static data. Quite the contrary, FaunaDB is great for
highly dynamic data. So, it might seem an overkill to use FaunaDB for data that
doesn’t change often. However, we plan to, in a next segment, let people ‘like’
and comment on our catalogue repositories. For such dynamic data, FaunaDB is a
perfect fit and in the meantime, works absolutely fine for storing our
repository list.&lt;/p&gt;
&lt;p&gt;This data categorization may then lead us to question:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Do we really need to keep making the same request, to get the same data, take
those same results, run them against the same template, and only then, deliver
the page to the client?”.&lt;/li&gt;
&lt;li&gt;“What if we use the server-side build to fetch the repo collection, and serve
HTML and static assets to our site’s visitors? Does that mean we are bound to
fully static pages?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In fact, we’ll see that by combining a Jamstack approach in the build step with
client-side hydration, we’ll be able to enliven our static pages with highly
dynamic data.&lt;/p&gt;
&lt;p&gt;At the end, you’ll be able to take this example, adapt and apply it to your
specific use case, by identifying and categorizing your data accordingly.&lt;/p&gt;
&lt;h2 id=&quot;jamstack&quot;&gt;Jamstack&lt;/h2&gt;
&lt;p&gt;The concepts of Jamstack and “static-first” are not new and their advantages
have been &lt;a href=&quot;https://css-tricks.com/static-or-not/&quot;&gt;extensively&lt;/a&gt;
&lt;a href=&quot;https://meyerweb.com/eric/thoughts/2020/03/22/get-static/&quot;&gt;documented&lt;/a&gt;
&lt;a href=&quot;https://css-tricks.com/static-first-pre-generated-jamstack-sites-with-serverless-rendering-as-a-fallback/&quot;&gt;before&lt;/a&gt;.
Jamstack architectures allow us to build faster, more secure, more scalable
websites.&lt;/p&gt;
&lt;p&gt;With HTML being pre-rendered once and then statically served from a CDN, a
website has the potential for great performance. Fetching data at the build
stage - instead of each time a client requests a page, with minimum computing
overhead.&lt;/p&gt;
&lt;p&gt;The term “static” can be a bit misleading - that’s why we see “pre-rendered”
being used interchangeably. When we build a Jamstack app, it doesn’t mean we
have to compromise on dynamic content and features.&lt;/p&gt;
&lt;p&gt;We can build the site beforehand with the type of data that does not change
often, and augment it client-side, only if and when that’s needed.&lt;/p&gt;
&lt;p&gt;Moreover, the widespread of functionality APIs, makes way for common tasks -
such as authentication, e-commerce, and data storage - that used to be
implemented over and over, now be delegated to the professional service
providers.&lt;/p&gt;
&lt;h2 id=&quot;faunadb&quot;&gt;FaunaDB&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://fauna.com/&quot;&gt;Fauna&lt;/a&gt; is a globally distributed, low-latency database,
with native GraphQL support, that promises to be always consistent and always
secure.&lt;/p&gt;
&lt;p&gt;As a serverless database, FaunaDB allows applications to access data through a
secure API, in contrast to more “traditional” relational databases that require
you to open a connection. In that sense, FaunaDB is “connectionless” and rather
behaves like an API, which fits perfectly in a Jamstack architecture. There is
also no need to host and manage our own database. It requires zero server
configuration and supports seamless scalability out-of-the-box.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Because serverless technologies abstract away the problems I don’t want to
deal with (setting up servers, scaling them, hosting my logic etc.) and allow
me to just run my code whenever I need it to.” - &lt;em&gt;&lt;a href=&quot;https://tlakomy.com/why-im-excited-about-serverless&quot;&gt;Tomasz Łakomy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;From a developer’s perspective this is awesome, because it allows us to be more
productive and focus solely on the logic of the app we’re building.&lt;/p&gt;
&lt;h2 id=&quot;nuxtjs&quot;&gt;Nuxt.js&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt.js&lt;/a&gt; is an open-source web application framework built
on top of Vue.js. It is well known for its SSR capabilities, but it can also do
static.&lt;/p&gt;
&lt;p&gt;Instead of having a Node server process each client request - eventually
fetching data from an API or database in between, we’ll be using Nuxt as a
static site generator to do the heavy lifting during the build stage.&lt;/p&gt;
&lt;h2 id=&quot;goals&quot;&gt;Goals&lt;/h2&gt;
&lt;p&gt;What we’re setting to achieve in this tutorial:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;building a pre-rendered Repo Catalogue site with Nuxt.js&lt;/li&gt;
&lt;li&gt;building a helper app that we’ll use to seed Fauna’s database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although it’s not the main focus of the article, the supporting &lt;code&gt;fauna-seeder&lt;/code&gt;
app will allows us to populate the FaunaDB database with a single command from
the terminal. It’s just one a way of storing data in FaunaDB - in fact, you
could be doing this step in a different way of your choice.&lt;/p&gt;
&lt;h2 id=&quot;pre-requisites&quot;&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;Before we move on, I’d like to mention that although not mandatory, a working
knowledge of the following technologies is beneficial:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Vue.js/Nuxt.js&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before you begin, you’ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node, npm, and npx installed&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://dashboard.fauna.com/accounts/register&quot;&gt;FaunaDB account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without further ado, let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;modelling-our-data&quot;&gt;Modelling our data&lt;/h2&gt;
&lt;p&gt;First things first, we begin by specifying the data model. The goal is to store
a collection of repos in a Fauna database.&lt;/p&gt;
&lt;p&gt;Each repo is represented by the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;project &lt;strong&gt;name&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;repo URL&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;project &lt;strong&gt;logo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;project &lt;strong&gt;color&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;writing-the-graphql-schema&quot;&gt;Writing the GraphQL schema&lt;/h2&gt;
&lt;p&gt;In this section, we’ll be creating the helper app &lt;code&gt;fauna-seeder&lt;/code&gt; that will
populate the database.&lt;/p&gt;
&lt;p&gt;Inside this project, we’ll also store the GraphQL schema we’ll be writing to
define our repo data, The schema will be used in the next step to create the
database and specify what resources the database will provide.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“GraphQL is a specification for an API query language and a server engine
capable of executing such queries.” - &lt;em&gt;&lt;a href=&quot;https://book.productionreadygraphql.com/&quot;&gt;Production Ready GraphQL&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Create a directory for the project and navigate to it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;fauna-seeder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;fauna-seeder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mkdir fauna-seedercd fauna-seeder&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;From within the root directory, create a new git repo:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;init&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git init&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Configure git to ignore the &lt;code&gt;node_modules&lt;/code&gt; directory and the &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;node_modules&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.gitignore&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;.env&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.gitignore&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo &amp;quot;node_modules&amp;quot; &gt; .gitignoreecho &amp;quot;.env&amp;quot; &gt;&gt; .gitignore&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then, let’s initialize a Node project:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-y&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm init -y&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This creates a &lt;code&gt;package.json&lt;/code&gt; file where we can install the required
dependencies:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;dotenv&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;faunadb&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;simple-icons&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install dotenv faunadb simple-icons&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ve installed three dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;faunadb: JavaScript &lt;a href=&quot;https://github.com/fauna/faunadb-js&quot;&gt;driver&lt;/a&gt; for FaunaDB&lt;/li&gt;
&lt;li&gt;simple-icons: &lt;a href=&quot;https://simpleicons.org/&quot;&gt;Simple Icons&lt;/a&gt; npm package&lt;/li&gt;
&lt;li&gt;dotenv: to store and load Fauna’s secret key from a &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.fauna.com/fauna/current/api/fql/&quot;&gt;The Fauna Query Language&lt;/a&gt; (FQL)
is the native API for querying FaunaDB. &lt;a href=&quot;https://docs.fauna.com/fauna/current/drivers/&quot;&gt;Fauna
drivers&lt;/a&gt; (available for several
programming languages) abstract the FQL, allowing developers to programmatically
interact with FaunaDB databases.&lt;/p&gt;
&lt;p&gt;Simple Icons is a cool project that collects SVG icons and colors for popular
brands. We’ll be using their &lt;a href=&quot;https://github.com/simple-icons/simple-icons&quot;&gt;npm
package&lt;/a&gt; to get the SVG logo and
the hex color code of each project, when the seeder app runs.&lt;/p&gt;
&lt;p&gt;Let’s now write the GraphQL schema. Create a directory &lt;code&gt;graphql&lt;/code&gt; and a
&lt;code&gt;schema.gql&lt;/code&gt; file inside it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;graphql&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;graphql&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;schema.gql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mkdir graphql &amp;amp;&amp;amp; cd graphql &amp;amp;&amp;amp; touch schema.gql&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;graphql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;Repo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;projectName&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@unique&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;repoUrl&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;@unique&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;svgLogo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;String&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;colorHex&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;String&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;Query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;allRepos&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;Repo&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type Repo {  projectName: String! @unique  repoUrl: String! @unique  svgLogo: String  colorHex: String}type Query {  allRepos: [Repo!]!}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you may know, GraphQL uses a typed schema to specify entities and their
fields. We’ve declared the object type &lt;code&gt;Repo&lt;/code&gt; to represent an individual
repository in the collection.&lt;/p&gt;
&lt;p&gt;A repo has a project name, a repository URL, a SVG logo, and a color. The first
two fields are declared as non-nullable &lt;code&gt;!&lt;/code&gt; and unique &lt;code&gt;@unique&lt;/code&gt;. This
guarantees that a repo always has values for these required fields, and that
there are no repeated repos in the collection.&lt;/p&gt;
&lt;p&gt;We’ve also declared a query &lt;code&gt;allRepos&lt;/code&gt;, to list all the repos that are stored in
the collection.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-fauna-database&quot;&gt;Creating a Fauna database&lt;/h2&gt;
&lt;p&gt;Log in to your Fauna account.&lt;/p&gt;
&lt;p&gt;Visit the &lt;a href=&quot;https://dashboard.fauna.com/&quot;&gt;dashboard&lt;/a&gt; and create a new database,
named &lt;code&gt;repos&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create a new FaunaDB database&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2535&quot; height=&quot;835&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-new-database.CyPlMJno_ZllQlp.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;importing-the-schema&quot;&gt;Importing the schema&lt;/h2&gt;
&lt;p&gt;Now that the database is created, we can import the GraphQL schema into FaunaDB.&lt;/p&gt;
&lt;p&gt;When you import a GraphQL schema, FaunaDB will automatically make the
collections and indexes for you to support your queries and provide you with an
“instant” GraphQL endpoint to start querying.&lt;/p&gt;
&lt;p&gt;We can upload our &lt;code&gt;schema.gql&lt;/code&gt; file, via FaunaDB Console by clicking “GraphQL”
on the left sidebar:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Fauna GraphQL Playground&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2525&quot; height=&quot;796&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-graphql-playground.DOaoZrH0_inVSW.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then click the “Import Schema” button, which opens your browser’s file upload,
and select the &lt;code&gt;schema.gql&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;FaunaDB automatically created the necessary collection for the &lt;code&gt;Repo&lt;/code&gt; entity.&lt;/p&gt;
&lt;p&gt;Additionally, it also created the indexes that support the schema and interact
with the collection:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Fauna Database Overview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2523&quot; height=&quot;941&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-db-overview.CGUEZnA__cMcq6.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;At this point we have an empty database, ready to be populated with some repo
data.&lt;/p&gt;
&lt;h2 id=&quot;seeding-data-to-fauna&quot;&gt;Seeding data to Fauna&lt;/h2&gt;
&lt;p&gt;Inside a Fauna database, we have Collections, Indexes and Documents. FaunaDB is
a relational database that stores data in the JSON format.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A Collection is a categorized group of data. Each piece of data takes the
form of a Document. A Document is a “single, changeable record within a FaunaDB
database,” according to Fauna’s documentation. You can think of Collections as
a traditional database table and a Document as a row.” - &lt;em&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2019/10/bookmarking-application-faunadb-netlify-11ty/&quot;&gt;Bryan Robinson&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are four ways of interacting with Fauna data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fauna drivers&lt;/li&gt;
&lt;li&gt;Interactive Shell using FQL&lt;/li&gt;
&lt;li&gt;GraphQL Playground&lt;/li&gt;
&lt;li&gt;GraphQL API using a GraphQL client (e.g.,
&lt;a href=&quot;https://www.apollographql.com/client/&quot;&gt;Apollo&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Normally, after using a GraphQL schema to generate the collections and indexes -
as we did, you would use the GraphQL endpoint that’s automatically provided. For
learning purposes, I decided to try out a different approach and go with FQL.
Although this is not the official way to interact with the data, it also
simplifies our schema, avoiding the need for GraphQL mutations to define write
operations.&lt;/p&gt;
&lt;p&gt;We’ll use the JavaScript driver, that we’ve already installed in a previous
step.&lt;/p&gt;
&lt;p&gt;The driver requires a Fauna Admin Key in order to authenticate connections and
write data in the &lt;code&gt;repos&lt;/code&gt; database.&lt;/p&gt;
&lt;p&gt;From the database’s dashboard, go to “Security” on the left-hand sidebar, and
create a new key with “Admin” Role:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create a Fauna Admin Key&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2536&quot; height=&quot;1007&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-new-admin-key.BlOEWxNA_ZRBLtC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Copy the generated key and save it somewhere safe, as after you navigate away
from this page it will not be displayed again.&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the root directory of the &lt;code&gt;fauna-seeder&lt;/code&gt; app:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;..&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.env&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd ..touch .env&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Add the environment variable &lt;code&gt;FAUNA_ADMIN_KEY&lt;/code&gt; and paste the generated key right
after the variable’s name:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;FAUNA_ADMIN_KEY=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FAUNA_ADMIN_KEY=&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;From here, we just need to reference &lt;code&gt;process.env.FAUNA_ADMIN_KEY&lt;/code&gt; to access the
key from within our code.&lt;/p&gt;
&lt;p&gt;Let’s create a function that handles a client connection to Fauna:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;graphql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;db-connection.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd graphqltouch db-connection.js&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Add the following to &lt;code&gt;db-connection.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;dotenv&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;faunadb&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;faunadb&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; faunadb.query;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;createClient&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;process.env.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;FAUNA_ADMIN_KEY&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;FAUNA_ADMIN_KEY not found&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; faunadb.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Client&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;secret: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;FAUNA_ADMIN_KEY&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; client;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.client &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;createClient&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.query &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; query;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;require(&amp;quot;dotenv&amp;quot;).config();const faunadb = require(&amp;quot;faunadb&amp;quot;);const query = faunadb.query;function createClient() {  if (!process.env.FAUNA_ADMIN_KEY) {    throw new Error(&amp;quot;FAUNA_ADMIN_KEY not found&amp;quot;);  }  const client = new faunadb.Client({    secret: process.env.FAUNA_ADMIN_KEY,  });  return client;}exports.client = createClient();exports.query = query;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The function will try do load the secret key, and in case of success, proceed
with creating and returning a connection to the database. Finally, the
&lt;code&gt;createClient&lt;/code&gt; function is exported, alongside the driver’s &lt;code&gt;query&lt;/code&gt; variable,
which will allow us to seed the data in FQL’s functional, composable style.&lt;/p&gt;
&lt;h2 id=&quot;repo-data&quot;&gt;Repo data&lt;/h2&gt;
&lt;p&gt;We’ll be using JSON to store the minimal set of repo data the seeder app
requires.&lt;/p&gt;
&lt;p&gt;Each repo is represented by three properties:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;projectName&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Vue.js&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;repoUrl&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;https://github.com/vuejs/vue&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;&quot;simpleIconsName&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Vue.js&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;quot;projectName&amp;quot;: &amp;quot;Vue.js&amp;quot;,  &amp;quot;repoUrl&amp;quot;: &amp;quot;https://github.com/vuejs/vue&amp;quot;,  &amp;quot;simpleIconsName&amp;quot;: &amp;quot;Vue.js&amp;quot;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;project &lt;strong&gt;name&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;GitHub &lt;strong&gt;repo URL&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Simple Icons &lt;strong&gt;brand title&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Create a &lt;code&gt;data.json&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;..&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;data.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd ..touch data.json&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Using the format above, add an array of repos that will be written to Fauna’s
database. You can either use the same
&lt;a href=&quot;https://github.com/ramigs/fauna-seeder/blob/master/data.json&quot;&gt;file&lt;/a&gt; I’ve used
or tweak it to feature your favorite projects.&lt;/p&gt;
&lt;p&gt;Make sure the &lt;code&gt;simpleIconsName&lt;/code&gt; value exists in the Simple Icons collection. You
can use the search feature on the &lt;a href=&quot;https://simpleicons.org/&quot;&gt;website&lt;/a&gt; to get the
correct names of the projects you’re adding.&lt;/p&gt;
&lt;h2 id=&quot;running-the-seeder-app&quot;&gt;Running the seeder app&lt;/h2&gt;
&lt;p&gt;Create a file named &lt;code&gt;seed.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;seed.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;touch seed.js&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is the code that will run to populate the &lt;code&gt;Repo&lt;/code&gt; collection:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;./graphql/db-connection&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;q&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; query;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;simpleIcons&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;simple-icons&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;reposData&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;./data.json&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repos&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; reposData.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;simpleIconsData&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; simpleIcons.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(r.simpleIconsName);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;r.svgLogo &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; simpleIconsData.svg;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;r.colorHex &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; simpleIconsData.hex;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; r.simpleIconsName;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; r;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Map&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;repos,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Lambda&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Collection&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Repo&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;), {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;data: q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Var&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(console.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Repos seeded successfully to FaunaDB&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; console.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Failed to seed repos to FaunaDB&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, err));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const { client, query } = require(&amp;quot;./graphql/db-connection&amp;quot;);const q = query;const simpleIcons = require(&amp;quot;simple-icons&amp;quot;);const reposData = require(&amp;quot;./data.json&amp;quot;);const repos = reposData.map((r) =&gt; {  const simpleIconsData = simpleIcons.get(r.simpleIconsName);  r.svgLogo = simpleIconsData.svg;  r.colorHex = simpleIconsData.hex;  delete r.simpleIconsName;  return r;});client  .query(    q.Map(      repos,      q.Lambda(        &amp;quot;repo&amp;quot;,        q.Create(q.Collection(&amp;quot;Repo&amp;quot;), {          data: q.Var(&amp;quot;repo&amp;quot;),        })      )    )  )  .then(console.log(&amp;quot;Repos seeded successfully to FaunaDB&amp;quot;))  .catch((err) =&gt; console.log(&amp;quot;Failed to seed repos to FaunaDB&amp;quot;, err));&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s review what we did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Import functions &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; from &lt;code&gt;./graphql/db-connection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Import &lt;code&gt;simple-icons&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;Import list of repos from &lt;code&gt;./data.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Go through each repo, get the SVG logo and the hex color code from
&lt;code&gt;simple-icons&lt;/code&gt; and add the properties accordingly&lt;/li&gt;
&lt;li&gt;Delete property &lt;code&gt;simpleIconsName&lt;/code&gt; from the repo, since we don’t want to write
it to the database&lt;/li&gt;
&lt;li&gt;Use the driver to map over the array of repos and create a new document for
each one, in the &lt;code&gt;Repo&lt;/code&gt; collection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice that &lt;code&gt;query&lt;/code&gt; operates as a transaction, which means that if an error
occurs, none of the repos will be written in the database.&lt;/p&gt;
&lt;p&gt;If everything goes as expected, we print a success message.&lt;/p&gt;
&lt;p&gt;We’re now ready to add documents to the &lt;code&gt;Repo&lt;/code&gt; collection:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;seed.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;node seed.js&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Navigate to “Collections” from the sidebar menu, and confirm that the data was
written successfully:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Fauna database seeded successfully&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2529&quot; height=&quot;993&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-seeded-success.CaWVbJuA_ZEFR8n.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;nuxt-repo-catalogue&quot;&gt;Nuxt Repo Catalogue&lt;/h2&gt;
&lt;p&gt;Now, let’s change gears and look at this tutorial’s core app.&lt;/p&gt;
&lt;p&gt;To get started quickly, we’ll initialize the project using Nuxt’s scaffolding
tool:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;create-nuxt-app&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;repo-catalogue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx create-nuxt-app repo-catalogue&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Go through the guide and select the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;axios and dotenv in the &lt;strong&gt;Nuxt.js modules&lt;/strong&gt; step&lt;/li&gt;
&lt;li&gt;Bulma in the &lt;strong&gt;UI framework&lt;/strong&gt; step, to style our app&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Create Nuxt app&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2532&quot; height=&quot;541&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-create-nuxt-app-options.0TTs-dhN_1WLe1y.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once the tool finishes creating our Nuxt app, install also the other required
dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;faunadb: JavaScript driver for FaunaDB&lt;/li&gt;
&lt;li&gt;slugify: we’ll use this &lt;a href=&quot;https://www.npmjs.com/package/slugify&quot;&gt;package&lt;/a&gt; to
generate slugs from repo names&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;faunadb&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;slugify&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install faunadb slugify&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;fauna-key&quot;&gt;Fauna key&lt;/h3&gt;
&lt;p&gt;The same way we did for the &lt;code&gt;fauna-seeder&lt;/code&gt; app, let’s create a new Fauna key -
this time with “Server” Role:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create a Fauna Server Key&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2537&quot; height=&quot;1003&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-new-server-key.BaZFWEOP_ZkRgiX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Edit the &lt;code&gt;.env&lt;/code&gt; file and paste the key you’ve just generated.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292e;--1:#e1e4e8&quot;&gt;FAUNA_SERVER_KEY=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FAUNA_SERVER_KEY=&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In the top of &lt;code&gt;nuxt.config.js&lt;/code&gt; require and configure dotenv:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;dotenv&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;require(&amp;quot;dotenv&amp;quot;).config();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;routes&quot;&gt;Routes&lt;/h2&gt;
&lt;p&gt;The Repo Catalogue website will respond in two types of routes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one home page, where all repos are listed&lt;/li&gt;
&lt;li&gt;several repo detail pages, one for each repo in the catalogue&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;/pages&lt;/code&gt; folder will look like this in Nuxt:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;index.vue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;repos&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;_slug.vue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;├── index.vue├── repos│   └── _slug.vue&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Since we want to pre-render the site’s pages, we need to tell Nuxt which routes
to &lt;a href=&quot;https://nuxtjs.org/api/configuration-generate&quot;&gt;generate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The routes for the individual repo pages have to be generated
&lt;a href=&quot;https://nuxtjs.org/guide/routing#dynamic-routes&quot;&gt;dynamically&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Nuxt, we do this by setting the generate.routes property to an array of
dynamic routes.&lt;/p&gt;
&lt;p&gt;When running &lt;code&gt;nuxt generate&lt;/code&gt;, Nuxt.js will use the configuration defined in the
&lt;code&gt;generate&lt;/code&gt; property, to pre-render the site.&lt;/p&gt;
&lt;p&gt;We’ll write a function &lt;code&gt;routes&lt;/code&gt; that reads the repo data from the database and
returns the array of routes to be generated.&lt;/p&gt;
&lt;p&gt;Let’s add the &lt;code&gt;generate&lt;/code&gt; property in &lt;code&gt;nuxt.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;async &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;routes&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;faunadb&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;faunadb&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; faunadb.query&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;slugify&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;slugify&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;q&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; query&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;process.env.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;FAUNA_SERVER_KEY&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;FAUNA_SERVER_KEY not found.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; faunadb.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Client&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;secret: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;FAUNA_SERVER_KEY&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; client.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Map&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Paginate&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Match&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Index&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;allRepos&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;))),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Lambda&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;X&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(q.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;Var&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;X&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repos&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; result.data.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;repo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repo.data)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;routes&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repos.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;repo&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repoUrlParts&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repo.repoUrl.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repoOwner&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repoUrlParts[repoUrlParts.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repoName&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repoUrlParts[repoUrlParts.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;slug&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;slugify&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(repoName, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;remove:&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#DBEDFF&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;[*+~.()&apos;&quot;!:@]&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;g&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;repo.slug &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; slug&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;repo.owner &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repoOwner&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;repo.name &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; repoName&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;route: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;/repos/&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; slug,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;payload: repo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;routes.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;route: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;payload: repos&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; routes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;generate: {  async routes() {    const faunadb = require(&amp;#x27;faunadb&amp;#x27;)    const query = faunadb.query    const slugify = require(&amp;#x27;slugify&amp;#x27;)    const q = query    if (!process.env.FAUNA_SERVER_KEY) {      throw new Error(&amp;#x27;FAUNA_SERVER_KEY not found.&amp;#x27;)    }    const client = new faunadb.Client({      secret: process.env.FAUNA_SERVER_KEY    })    const result = await client.query(      q.Map(        q.Paginate(q.Match(q.Index(&amp;#x27;allRepos&amp;#x27;))),        q.Lambda(&amp;#x27;X&amp;#x27;, q.Get(q.Var(&amp;#x27;X&amp;#x27;)))      )    )    const repos = result.data.map((repo) =&gt; repo.data)    const routes = repos.map((repo) =&gt; {      const repoUrlParts = repo.repoUrl.split(&amp;#x27;/&amp;#x27;)      const repoOwner = repoUrlParts[repoUrlParts.length - 2]      const repoName = repoUrlParts[repoUrlParts.length - 1]      const slug = slugify(repoName, {        remove: /[*+~.()&amp;#x27;&amp;quot;!:@]/g      })      repo.slug = slug      repo.owner = repoOwner      repo.name = repoName      return {        route: &amp;#x27;/repos/&amp;#x27; + slug,        payload: repo      }    })    routes.push({      route: &amp;#x27;/&amp;#x27;,      payload: repos    })    return routes  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It’s quite some code. So, let’s review the different steps of the snippet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Import the &lt;code&gt;faunadb&lt;/code&gt; driver from &lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Import the &lt;code&gt;slugify&lt;/code&gt; package from &lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Load the Fauna secret key from &lt;code&gt;.env&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Instantiate a Fauna client using the secret key&lt;/li&gt;
&lt;li&gt;Fetch the entire repo collection using the &lt;code&gt;allRepos&lt;/code&gt; Index&lt;/li&gt;
&lt;li&gt;Go through each repo, generate a slug and return an object with the route path
and the repo data as payload, that will be passed to the page&lt;/li&gt;
&lt;li&gt;Add the route for the home page, passing the repo collection as payload&lt;/li&gt;
&lt;li&gt;Return the array of routes that should be generated&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;creating-the-pages&quot;&gt;Creating the pages&lt;/h2&gt;
&lt;p&gt;Let’s being with the homepage &lt;code&gt;/pages/index.vue&lt;/code&gt;. This is the page that lists
the repo collection.&lt;/p&gt;
&lt;p&gt;Delete the default CSS inside &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; so we can start with a blank slate.&lt;/p&gt;
&lt;p&gt;Replace the content of &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;asyncData&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { repos: payload };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;script&gt;export default {  asyncData({ payload }) {    return { repos: payload };  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ve used Nuxt’s &lt;code&gt;asyncData&lt;/code&gt; to instantiate the variable &lt;code&gt;repos&lt;/code&gt; with the
payload from the &lt;code&gt;generate&lt;/code&gt; configuration.&lt;/p&gt;
&lt;p&gt;Now that have access to the data, replace the existing &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{ marginBottom: &apos;5rem&apos; }&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title has-text-centered is-size-1&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;Repo Catalogue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;columns is-multiline&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-for&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo in repos&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:key&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo.projectName&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;card column is-3&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{ backgroundColor: &apos;#&apos; + repo.colorHex }&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;card-image&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:href&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;`/repos/${repo.slug}`&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;figure&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{ maxWidth: &apos;20%&apos;, margin: &apos;0 auto&apos;, padding: &apos;2em 0&apos; }&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-html&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo.svgLogo&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;card-content&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;media&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;media-content&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;{{ repo.projectName }}&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;subtitle&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:href&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo.repoUrl&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;GitHub&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;section class=&amp;quot;section&amp;quot;&gt;    &lt;div class=&amp;quot;container&amp;quot;&gt;      &lt;h1        :style=&amp;quot;{ marginBottom: &amp;#x27;5rem&amp;#x27; }&amp;quot;        class=&amp;quot;title has-text-centered is-size-1&amp;quot;      &gt;        Repo Catalogue      &lt;/h1&gt;      &lt;div class=&amp;quot;columns is-multiline&amp;quot;&gt;        &lt;div          v-for=&amp;quot;repo in repos&amp;quot;          :key=&amp;quot;repo.projectName&amp;quot;          class=&amp;quot;card column is-3&amp;quot;        &gt;          &lt;div            :style=&amp;quot;{ backgroundColor: &amp;#x27;#&amp;#x27; + repo.colorHex }&amp;quot;            class=&amp;quot;card-image&amp;quot;          &gt;            &lt;a :href=&amp;quot;&amp;#x60;/repos/${repo.slug}&amp;#x60;&amp;quot;&gt;              &lt;figure                :style=&amp;quot;{ maxWidth: &amp;#x27;20%&amp;#x27;, margin: &amp;#x27;0 auto&amp;#x27;, padding: &amp;#x27;2em 0&amp;#x27; }&amp;quot;                v-html=&amp;quot;repo.svgLogo&amp;quot;              &gt;&lt;/figure&gt;            &lt;/a&gt;          &lt;/div&gt;          &lt;div class=&amp;quot;card-content&amp;quot;&gt;            &lt;div class=&amp;quot;media&amp;quot;&gt;              &lt;div class=&amp;quot;media-content&amp;quot;&gt;                &lt;h3 class=&amp;quot;title&amp;quot;&gt;{{ repo.projectName }}&lt;/h3&gt;                &lt;a class=&amp;quot;subtitle&amp;quot; :href=&amp;quot;repo.repoUrl&amp;quot;&gt;GitHub&lt;/a&gt;              &lt;/div&gt;            &lt;/div&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/section&gt;&lt;/template&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In the template above, we’ve gone through each repo and displayed it as a Bulma
Card.&lt;/p&gt;
&lt;p&gt;Let’s move on to the individual repo detail page. Create a new file
&lt;code&gt;/pages/repos/_slug.vue&lt;/code&gt; and replace the existing &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;asyncData&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (payload) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { repo: payload };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;script&gt;export default {  asyncData({ payload }) {    if (payload) return { repo: payload };  },};&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now that have access to the data, replace the existing &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{ backgroundColor: &apos;#&apos; + repo.colorHex }&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;hero has-text-centered&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;hero-body&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;figure&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;:style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;{ maxWidth: &apos;10%&apos;, margin: &apos;0 auto&apos; }&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;v-html&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;repo.svgLogo&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;figure&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;title has-text-light is-size-1&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{{ repo.projectName }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;template&gt;  &lt;div&gt;    &lt;section      :style=&amp;quot;{ backgroundColor: &amp;#x27;#&amp;#x27; + repo.colorHex }&amp;quot;      class=&amp;quot;hero has-text-centered&amp;quot;    &gt;      &lt;div class=&amp;quot;hero-body&amp;quot;&gt;        &lt;div class=&amp;quot;container&amp;quot;&gt;          &lt;figure            :style=&amp;quot;{ maxWidth: &amp;#x27;10%&amp;#x27;, margin: &amp;#x27;0 auto&amp;#x27; }&amp;quot;            v-html=&amp;quot;repo.svgLogo&amp;quot;          &gt;&lt;/figure&gt;          &lt;h1 class=&amp;quot;title has-text-light is-size-1&amp;quot;&gt;            {{ repo.projectName }}          &lt;/h1&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/section&gt;  &lt;/div&gt;&lt;/template&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In the template above, we’ve created a Bulma Hero to display the repo data.&lt;/p&gt;
&lt;h2 id=&quot;running-nuxt-generate&quot;&gt;Running Nuxt generate&lt;/h2&gt;
&lt;p&gt;Now that we’ve created the page templates, we have everything we need to build
our website, with dynamically generated routes, using Fauna data.&lt;/p&gt;
&lt;p&gt;Build your Nuxt.js Repo Catalogue:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;generate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm run generate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And that’s it! 👏 You have now a working static site in the &lt;code&gt;dist&lt;/code&gt; folder, that
can be served directly from a CDN.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Repo Catalogue&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2537&quot; height=&quot;1344&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-repo-catalogue.DoJmO-vg_2fPhu0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;To test it locally run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;serve&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;dist&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx serve dist&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;adding-dynamic-content-to-our-repo-catalogue&quot;&gt;Adding dynamic content to our Repo Catalogue&lt;/h2&gt;
&lt;p&gt;Perhaps the main objection to static sites is “I don’t want to have to rebuild
the entire site every time something changes in the database”.&lt;/p&gt;
&lt;p&gt;It’s a totally valid argument - a nuanced one nonetheless. For example, a
&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; hosted website won’t have any downtime,
while the build/deploy of a new version takes place.&lt;/p&gt;
&lt;p&gt;So what is the &lt;strong&gt;real&lt;/strong&gt; downside? Maybe the time it takes to rebuild a website
with large amounts of content. And even in that domain, we’re starting to see
amazing progress being made, e.g. Gatsby’s recently announcing &lt;a href=&quot;https://www.gatsbyjs.org/blog/2020-04-22-announcing-incremental-builds/&quot;&gt;incremental
builds&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But still, there are certainly some scenarios where constantly rebuilding the
site is not viable.&lt;/p&gt;
&lt;p&gt;Going back to our Repo Catalogue, suppose we want to add some dynamic data to
the detail pages, such as description, number of stars, and number of forks.&lt;/p&gt;
&lt;p&gt;Clearly, it’s not practical to rebuild an entire website whenever any of this
data changes.&lt;/p&gt;
&lt;p&gt;In this section, we’ll be adding some dynamic data to the Repo detail page.
We’ll be adding an asynchronous JavaScript API call to the GitHub API to get the
repo’s information.&lt;/p&gt;
&lt;p&gt;The request for this data will be made client-side and we’ll rely on Vue’s
reactivity to display it.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;/pages/repos/_slug.js&lt;/code&gt;, declare a &lt;code&gt;repoData&lt;/code&gt; object to hold the response
data:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; { repoData: {} }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;data() {  return { repoData: {} }},&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The GitHub API provides an endpoint &lt;code&gt;GET /repos/:owner/:repo&lt;/code&gt; that returns a
repo’s info. Use Vue’s &lt;code&gt;mounted&lt;/code&gt; hook to call the GitHub API from the client,
with axios:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;mounted&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;$nextTick&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repoOwner&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.repo.owner&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;repoName&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.repo.name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.$axios.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;$get&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;`https://api.github.com/repos/${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;repoOwner&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;}/${&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;repoName&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;.repoData &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mounted() {  this.$nextTick(async () =&gt; {    const repoOwner = this.repo.owner    const repoName = this.repo.name    const result = await this.$axios.$get(      &amp;#x60;https://api.github.com/repos/${repoOwner}/${repoName}&amp;#x60;    )    this.repoData = result  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Under the Hero &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, create a container to display the dynamic data:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;{ paddingTop: &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&apos;2rem&apos;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;span class=&quot;is-size-5&quot;&amp;gt;Description:&amp;lt;/span&amp;gt; {{ repoData.description }}&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;span class=&quot;is-size-5&quot;&amp;gt;Stars:&amp;lt;/span&amp;gt; {{ repoData.stargazers_count }}&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;span class=&quot;is-size-5&quot;&amp;gt;Forks:&amp;lt;/span&amp;gt; {{ repoData.forks_count }}&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;div class=&amp;quot;container&amp;quot; :style=&amp;quot;{ paddingTop: &amp;#x27;2rem&amp;#x27; }&amp;quot;&gt;  &lt;p&gt;&lt;span class=&amp;quot;is-size-5&amp;quot;&gt;Description:&lt;/span&gt; {{ repoData.description }}&lt;/p&gt;  &lt;p&gt;&lt;span class=&amp;quot;is-size-5&amp;quot;&gt;Stars:&lt;/span&gt; {{ repoData.stargazers_count }}&lt;/p&gt;  &lt;p&gt;&lt;span class=&amp;quot;is-size-5&amp;quot;&gt;Forks:&lt;/span&gt; {{ repoData.forks_count }}&lt;/p&gt;&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, tell Nuxt to generate the site again, so that the GitHub API call is
included in the app’s bundle:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;generate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm run generate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And we’re done! 🎉&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt.js detail page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2524&quot; height=&quot;913&quot; src=&quot;https://ramigs.dev/_astro/2020-07-14-fauna-nuxt-detail-page.v0SXsYy9_7mkiz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A dynamic website that loads data in the frontend as the user visits the repo
detail page.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we’ve built a Repo Catalogue static website that you can now
deploy on a host of your choice.&lt;/p&gt;
&lt;p&gt;The intent was to point out that it doesn’t always have to be a matter of A/B
decision. We can aim for a “hybrid” solution whenever possible, where we
pre-render the most we can, and asynchronously fetch just the data we need.&lt;/p&gt;
&lt;p&gt;We began by writing a GraphQL schema to model our repo data. Then, we used
FaunaDB to create a cloud database and, by simply importing the schema, we
instantly got a full-featured data backend.&lt;/p&gt;
&lt;p&gt;Just like that! No need to deal with any server/database hosting and
configurations, we were able to quickly start building our Repo Catalogue.&lt;/p&gt;
&lt;p&gt;Another cool benefit we get with a database like Fauna, is that it allows us to
have a unique source of truth to represent both the data model and the API that
interacts with it.&lt;/p&gt;
&lt;p&gt;Then, we used Nuxt to implement the app’s pages and configured it to fetch the
repo data from the database, using it to build a pre-rendered app.&lt;/p&gt;
&lt;p&gt;Finally, we added dynamic data from the GitHub API to our static pages.&lt;/p&gt;
&lt;p&gt;The code for this tutorial can be found in the following GitHub repos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ramigs/fauna-seeder&quot;&gt;&lt;code&gt;fauna-seeder&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ramigs/repo-catalogue&quot;&gt;&lt;code&gt;repo-catalogue&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-to-do-next&quot;&gt;What to do next&lt;/h3&gt;
&lt;p&gt;Here are a couple of ideas to further explore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hosting the Repo Catalogue on Netlify and configuring it to trigger a new
&lt;code&gt;repo-catalogue&lt;/code&gt; build/deploy every time there’s a push to &lt;code&gt;master&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Finding a way to trigger a new &lt;code&gt;repo-catalogue&lt;/code&gt; build/deploy whenever content
changes in Fauna’s database&lt;/li&gt;
&lt;li&gt;Adding a loader in the repo detail page, while the GitHub API is being
requested&lt;/li&gt;
&lt;li&gt;Implementing error handling for database and API requests&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>How to dynamically change the order of HTML elements</title><link>https://ramigs.dev/blog/dynamic-order-change-html/</link><guid isPermaLink="true">https://ramigs.dev/blog/dynamic-order-change-html/</guid><description>Changing the order of HTML elements between mobile and desktop layouts</description><pubDate>Fri, 08 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s say you’re working on a page that has two main components - &lt;strong&gt;Element A&lt;/strong&gt;
and &lt;strong&gt;Element B&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Suppose you had to implement a responsive layout with the following requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Desktop: &lt;strong&gt;Element A&lt;/strong&gt; should be positioned on top of &lt;strong&gt;Element B&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Mobile: &lt;strong&gt;Element B&lt;/strong&gt; should be positioned on top of &lt;strong&gt;Element A&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this tutorial, we’ll look at two different approaches to solve these
requirements.&lt;/p&gt;
&lt;p&gt;Here’s what we’ll be setting to achieve:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;html elements order change based on layout&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2621&quot; height=&quot;1236&quot; src=&quot;https://ramigs.dev/_astro/2020-05-08-dynamic-order-change-html.RQCNN3Ec_Z2qN8s2.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;before-we-begin&quot;&gt;Before we begin&lt;/h2&gt;
&lt;p&gt;It’s important to clarify some pre-conditions and set the right expectations as
to what the end result will exactly be.&lt;/p&gt;
&lt;p&gt;We assume that both elements are siblings in the DOM - i.e., both are direct
descendants of the same parent element:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;parent&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;element-a&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;HTML Element A&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;element-b&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;element&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;HTML Element B&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--0:#1E7734;--1:#85E89D&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;section class=&amp;quot;parent&amp;quot;&gt;  &lt;div id=&amp;quot;element-a&amp;quot; class=&amp;quot;element&amp;quot;&gt;    &lt;h2&gt;HTML Element A&lt;/h2&gt;  &lt;/div&gt;  &lt;div id=&amp;quot;element-b&amp;quot; class=&amp;quot;element&amp;quot;&gt;    &lt;h2&gt;HTML Element B&lt;/h2&gt;  &lt;/div&gt;&lt;/section&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ll look at two different solutions. Both accomplish the requirements
&lt;strong&gt;visually&lt;/strong&gt;. However, there are some nuances that can make you decide for one
or the other.&lt;/p&gt;
&lt;p&gt;Here are some quick remarks for each solution, so you can jump right away to the
one that better fits your use case.&lt;/p&gt;
&lt;h3 id=&quot;solution-1&quot;&gt;Solution 1:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The parent element has to be a flex container&lt;/li&gt;
&lt;li&gt;Achieved using &lt;strong&gt;CSS&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Does not actually change the DOM order of the elements&lt;/li&gt;
&lt;li&gt;Less implementation steps&lt;/li&gt;
&lt;li&gt;Breaks keyboard navigation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;solution-2&quot;&gt;Solution 2:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Achieved using &lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Changes the DOM order of the elements&lt;/li&gt;
&lt;li&gt;More implementation steps&lt;/li&gt;
&lt;li&gt;Does not break keyboard navigation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;solution-1-flex-direction&quot;&gt;Solution 1: flex-direction&lt;/h2&gt;
&lt;p&gt;As you may have guessed from the title, we’ll be using flexbox. The parent
element has to be a flex container. This is how we make it one:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.parent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;display&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;flex&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;flex-direction&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;column&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;.parent {  display: flex;  flex-direction: column;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We’ve also used &lt;code&gt;flex-direction&lt;/code&gt; to set the main axis and define how child
elements are placed inside the parent container.&lt;/p&gt;
&lt;p&gt;By default, flex items are displayed in the same order as they appear in the
document.&lt;/p&gt;
&lt;p&gt;Now, for the mobile layout we want to reverse the order in which the elements
are displayed. The value &lt;code&gt;column-reverse&lt;/code&gt; does precisely this. Let’s go ahead
and add a media query to reverse the &lt;code&gt;flex-direction&lt;/code&gt; whenever the display area
has a maximum width of 767 pixels:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;max-width&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;767&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;.parent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;flex-direction&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;column-reverse&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@media (max-width: 767px) {  .parent {    flex-direction: column-reverse;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And we’re done, that’s all we need!&lt;/p&gt;
&lt;p&gt;It is important to bear in mind that this solution creates a &lt;a href=&quot;https://tink.uk/flexbox-the-keyboard-navigation-disconnect/&quot;&gt;disconnect&lt;/a&gt; between
the visual presentation and the DOM order.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“This will adversely affect users experiencing low vision navigating with the aid
of assistive technology such as a screen reader. If the visual (CSS) order is
important, then screen reader users will not have access to the correct reading
order.” - &lt;em&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction#Accessibility_Concerns&quot;&gt;MDN web docs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have more than two child elements and would like to have more control
over their individual display order, checkout the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Ordering_Flex_Items&quot;&gt;order
property&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;solution-2-dom-manipulation&quot;&gt;Solution 2: DOM manipulation&lt;/h2&gt;
&lt;p&gt;We’ll be using JavaScript - via &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API&quot;&gt;HTML DOM
API&lt;/a&gt; - to access
the document and its elements.&lt;/p&gt;
&lt;p&gt;The strategy is to select the element that should be on top - based on the
maximum width of the display area, and insert it as the first child of the
parent element.&lt;/p&gt;
&lt;p&gt;First, let’s create a variable to represent our media query:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;mobile&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;(max-width: 767px)&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const mobile = &amp;quot;(max-width: 767px)&amp;quot;;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Window&lt;/code&gt; interface provides the method &lt;code&gt;matchMedia()&lt;/code&gt; - which returns a
media query list, matching a specified media query string.&lt;/p&gt;
&lt;p&gt;We can then check whether our variable &lt;code&gt;mobile&lt;/code&gt; matches with the current state
of the document.&lt;/p&gt;
&lt;p&gt;So let’s define a function that conditionally sets &lt;strong&gt;Element A&lt;/strong&gt; or &lt;strong&gt;Element
B&lt;/strong&gt; as first child of the parent element:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;setFirstChild&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;matched&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; window.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;matchMedia&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(mobile).matches;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;topElement&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; matched&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;element-b&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;element-a&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; topElement.parentNode;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;parent.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;insertBefore&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(topElement, parent.firstChild);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function setFirstChild() {  const matched = window.matchMedia(mobile).matches;  const topElement = matched    ? document.getElementById(&amp;quot;element-b&amp;quot;)    : document.getElementById(&amp;quot;element-a&amp;quot;);  const parent = topElement.parentNode;  parent.insertBefore(topElement, parent.firstChild);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that there was no need to explicitly remove it from the DOM, store it in
a temporary variable, and append it again.&lt;/p&gt;
&lt;p&gt;Since it already exists in the document, &lt;code&gt;insertBefore()&lt;/code&gt; moves it from its
current position to the new position.&lt;/p&gt;
&lt;p&gt;Now, we attach the function we’ve just created to the load event, so it runs
when the document is loaded:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;window.onload &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; setFirstChild;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;window.onload = setFirstChild;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally, we need to watch for media query changes, so that if the user resizes
the browser the order updates accordingly:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;window.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;matchMedia&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(mobile).&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;change&quot;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, setFirstChild);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;window.matchMedia(mobile).addEventListener(&amp;quot;change&amp;quot;, setFirstChild);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can now test that everything is working as expected by reloading and
resizing the browser.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;We’ve seen two ways to dynamically change the order of HTML elements based on
the display width. Neither is necessarily &lt;em&gt;better&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Solution 1 is arguably more practical. However, it breaks keyboard navigation.&lt;/p&gt;
&lt;p&gt;Solution 2 manipulates the DOM, which is operationally more intensive than just using
media queries.&lt;/p&gt;
&lt;p&gt;You can reference the
&lt;a href=&quot;https://github.com/ramigs/dynamic-order-change-html&quot;&gt;code&lt;/a&gt; I used to create
this tutorial, which includes examples for both solutions.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://stackoverflow.com/users/528507/hemlock&quot;&gt;Hemlock&lt;/a&gt; for
&lt;a href=&quot;https://stackoverflow.com/questions/4699594/change-div-order-in-css-or-javascript&quot;&gt;mentioning&lt;/a&gt;
a way to move a DOM element without having to remove and append it again to the
DOM.&lt;/p&gt;
</content:encoded></item><item><title>Three months of Nuxt.js in Production - A Retrospective</title><link>https://ramigs.dev/blog/nuxt-review/</link><guid isPermaLink="true">https://ramigs.dev/blog/nuxt-review/</guid><description>My experience with Nuxt.js in a continuous delivery production setting</description><pubDate>Sat, 18 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, I want to reflect and share my experience working with
&lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt.js&lt;/a&gt;, over the past three months, pretty much on a
daily basis, in a continuous delivery production setting.&lt;/p&gt;
&lt;p&gt;Now that the project is approaching the finish line, it’s time to pause and
review its centerpiece tool and how it contributed to its successful completion.&lt;/p&gt;
&lt;p&gt;This won’t be a Nuxt.js technical tutorial. There are lot of excellent resources
around. I’m not going to examine it in depths, I just want to focus on my
journey as a developer, experimenting with the framework for the first time and
using it right away in a &lt;em&gt;real-world&lt;/em&gt; project.&lt;/p&gt;
&lt;p&gt;Hopefully, I’ll also be able to reignite my writing habit and get back on track,
as I haven’t had much opportunity to do so lately.&lt;/p&gt;
&lt;h2 id=&quot;what-led-me-to-nuxtjs&quot;&gt;What led me to Nuxt.js&lt;/h2&gt;
&lt;p&gt;Three months ago, I began working with a new client, where I was asked to choose
the frontend stack for a project that was about to begin.&lt;/p&gt;
&lt;p&gt;My client’s end-client is a media platform, and the goal was to revamp their
website, giving it a more modern/responsive look and feel. The project had two
top-level requirements. One, was to allow them to showcase their huge media
catalogue. The other, was to feature a new area, something very similar to a
classical TV guide, scheduling the airing of their programmes.&lt;/p&gt;
&lt;p&gt;At the time, I had been reading and learning about the concept of
&lt;a href=&quot;https://ramigs.dev/blog/how-the-jamstack-inspired-me-to-start-blogging/&quot;&gt;JAMstack&lt;/a&gt;.
I had built a couple of personal projects - such as this website, just to test
the waters. Maybe this could be the opportunity to apply it professionally for
the first time.&lt;/p&gt;
&lt;p&gt;The media catalogue seemed an appropriate candidate to be &lt;a href=&quot;https://joshwcomeau.com/gatsby/a-static-future/&quot;&gt;statically
built&lt;/a&gt;. The content would
probably not change that much over time. Could we pass on the heavy lifting to
the build process and serve a blazing fast static site from a CDN?&lt;/p&gt;
&lt;p&gt;What about the TV guide feature? We’d certainly have to call some API for that.
But what if the data changes too often? We wouldn’t want to keep re-building the
website all the time. This was the exploration phase, and besides top-level
requirements, almost everything else was unclear. There were a lot of questions
and not so many answers. I knew we should obviously decouple frontend and
backend, but not much more than that.&lt;/p&gt;
&lt;p&gt;Although the end-client did not mention it initially, I was already starting to
anticipate that &lt;strong&gt;web analytics&lt;/strong&gt; and &lt;strong&gt;SEO&lt;/strong&gt; (Search Engine Optimization)
would be very important, so at that point I was already leaning towards a static
or SSR approach.&lt;/p&gt;
&lt;p&gt;By happy chance, in the meanwhile, I also started to participate in a project
alongside the amazing &lt;a href=&quot;https://freecodecamplisbon.org/&quot;&gt;freecodecamp Lisbon&lt;/a&gt;
community, where I was introduced to Nuxt.js. It couldn’t have come at a better
time!&lt;/p&gt;
&lt;p&gt;I started to learn more about Nuxt, going through some tutorials, and asking
for help and tips. I was from the get-go very impressed with how fast I was
prototyping and building.&lt;/p&gt;
&lt;p&gt;I have to admit I was a bit apprehensive to see how it would handle the
complexities of a &lt;em&gt;real project&lt;/em&gt;. I didn’t have the time to fully explore it,
and I had to make a decision. I also didn’t have all the answers I needed to
fully commit to a static solution.&lt;/p&gt;
&lt;p&gt;Well, Nuxt could do that and could also do the &lt;em&gt;safer&lt;/em&gt; SSR approach. And so,
Nuxt it was.&lt;/p&gt;
&lt;h2 id=&quot;what-is-nuxtjs-quick-overview&quot;&gt;What is Nuxt.js? Quick Overview&lt;/h2&gt;
&lt;p&gt;Nuxt.js is an MIT-licensed, open-source web application framework built on top
of Vue.js.&lt;/p&gt;
&lt;p&gt;Vue.js is a JavaScript library for building web interfaces. Even though Vue’s
main tagline is “The Progressive JavaScript Framework”, its official
&lt;a href=&quot;https://vuejs.org/&quot;&gt;website&lt;/a&gt; also describes it as “An incrementally adoptable
ecosystem that scales between a library and a full-featured framework”.&lt;/p&gt;
&lt;p&gt;Without getting further into the discussion of whether Vue’s correct
categorization should be &lt;a href=&quot;https://www.freecodecamp.org/news/the-difference-between-a-framework-and-a-library-bd133054023f/&quot;&gt;library or
framework&lt;/a&gt;,
for the remainder of this article I’ll be referring to it as in its core library
facet.&lt;/p&gt;
&lt;p&gt;Frontend JavaScript libraries are supercool! They brought SPAs (Single Page
Applications), and with them a whole new level of dynamism and user
interactivity to the web.&lt;/p&gt;
&lt;p&gt;In order to stay lightweight and performant, libraries need to make firm
decisions in terms of their core functionality. They also need to be flexible
and not enforce too much conventions, that would make them unusable or not
easily integrated into existing projects. This is why the core Vue library does
not include routing or global state management. To handle those, you’ll have to
install and configure other Vue libraries.&lt;/p&gt;
&lt;p&gt;Nuxt, contrarily, is a framework. In this regard, it can more freely abstract,
manage and provide tools for common everyday tasks and configurations associated
with web development - thus, allowing developers to focus on the logic of
the app they’re building.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“There’s always this routine when starting a new Vue project that Nuxt helps
alleviate while also applying some tried-and-true best practices to your
project &lt;em&gt;free of charge&lt;/em&gt;.” -
&lt;em&gt;&lt;a href=&quot;https://dev.to/codespent/building-a-sidebar-with-nuxt-vuex-239j&quot;&gt;Patrick Hanford&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Client-side security and unfitness for SEO are perhaps two of the most common
&lt;a href=&quot;https://adamsilver.io/articles/the-disadvantages-of-single-page-applications/&quot;&gt;criticisms of
SPAs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Although there are some strategies to mitigate security concerns and make SPAs
more SEO-friendly, their intrinsic nature wouldn’t make them the most immediate
choice for such requirements. For such requirements, developers will generally
lean more to a server-side rendering approach.&lt;/p&gt;
&lt;p&gt;Nuxt comes to fill in this gap, powering our Vue.js apps with server-side
capabilities. It’s important to note however, that SSR is not the only
difference between Nuxt and Vue CLI. Nonetheless, this difference may typically
be the main decision factor when choosing between one and the other.&lt;/p&gt;
&lt;h3 id=&quot;understanding-server-side-rendering&quot;&gt;Understanding Server-Side Rendering&lt;/h3&gt;
&lt;p&gt;Contrary to more modern &lt;strong&gt;SPA&lt;/strong&gt; solutions, where JavaScript is responsible for
generating HTML on the client’s browser, &lt;strong&gt;SSR&lt;/strong&gt; (Server-side Rendering) is the
more &lt;em&gt;traditional&lt;/em&gt; method of rendering a web page. When the client requests a
page, the origin server is responsible for executing the code (possibly fetching
data from a database or API, in between), running the retrieved data against a
template and returning the resulting HTML to the client.&lt;/p&gt;
&lt;p&gt;One of the most argued disadvantages of SPAs is their inadequacy for efficient
SEO. Search engines need to fetch the content of a
page in order to index and rank it. Since SPAs fetch their data asynchronously,
after page load, search engines have more trouble crawling the content, and thus
end up not favouring SPA websites as much.&lt;/p&gt;
&lt;p&gt;Generally speaking, server-side rendered websites are SEO-friendly by default.
When the page is delivered to the client (be it a browser or a search engine
crawler), all the content is already &lt;em&gt;there&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In terms of &lt;strong&gt;performance&lt;/strong&gt;, under similar conditions, a SSR website will
typically initially be perceived as faster. Once the HTML is delivered to the
client, the user will already start to see, get familiarized and interact with
the DOM, even before the download of JavaScript and other assets is completed.&lt;/p&gt;
&lt;p&gt;Of course, all this is very subjective and dependent on the specificities of
each project. For example, if there’s data to be retrieved, a SSR website will
only deliver the page after fetching it asynchronously. So, if the database
takes long to respond, that will also have impact. (This is not to say that a
SPA will not be affected by such latency, but at least we can &lt;em&gt;distract&lt;/em&gt; the
user with a colorful/spinning loader, while the request takes place.)&lt;/p&gt;
&lt;p&gt;A SPA website, on the other hand, may have a slower first-initial load, as the
whole JavaScript bundle has to be downloaded and the page rendered before the
user can interact with it. However, from there on, navigating between routes is
typically noticeably faster, offering a more fluid experience to the user.&lt;/p&gt;
&lt;p&gt;In terms of &lt;strong&gt;memory management&lt;/strong&gt;, normally with a SSR website you won’t have to
worry as much as with a SPA. A SSR website has the advantage of each
route access translating to a new server request. This allows the browser to
free memory and &lt;em&gt;start&lt;/em&gt; again from the beginning.&lt;/p&gt;
&lt;p&gt;If not taken care of, a SPA can easily experience performance degradation,
especially after a lot of navigation and user interaction within the same
session.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Part of the bargain we struck when we switched from building server-rendered
websites to client-rendered SPAs is that we suddenly had to take a lot more
care with the resources on the user’s device.” - &lt;em&gt;&lt;a href=&quot;https://nolanlawson.com/2020/02/19/fixing-memory-leaks-in-web-applications/&quot;&gt;Nolan
Lawson&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One last point about performance. SPAs will usually ship the bundle for the
entire site at once - big bundle issue™, which can be noticeable specially in
mobile devices.&lt;/p&gt;
&lt;p&gt;Web development frameworks - such as Nuxt - are able to implement mechanisms of
automatic code splitting, where each route gets just the code it requires,
keeping the size of JavaScript more controlled.&lt;/p&gt;
&lt;h3 id=&quot;vue-cli-vs-nuxtjs&quot;&gt;Vue CLI vs. Nuxt.js&lt;/h3&gt;
&lt;p&gt;In the early stages of my Nuxt journey, I would ask myself whether Nuxt was
simply a SSR version of Vue CLI. Well, now I know the answer is a nuanced no.&lt;/p&gt;
&lt;p&gt;For starters, yes, Vue CLI apps are intrinsically SPAs. However, you can also
build SPAs with Nuxt. Additionally, with Nuxt, you can also pre-render your
pages before they get to the client’s browser, whether that’s achieved on the
server (SSR) or during the build process, by generating a static site. Whichever
strategy is used, when the page is delivered to the client, your site can still
benefit from the interactive nature of Vue, since it “hydrates” the static
markup, once it is loaded.&lt;/p&gt;
&lt;p&gt;So, is rendering &lt;code&gt;mode&lt;/code&gt; the only difference between the two?&lt;/p&gt;
&lt;p&gt;No. Nuxt.js is a more opinionated, higher abstraction level framework. Indeed,
anything you can build with Vue CLI can be built with Nuxt, plus you also get
some extra features added on top.&lt;/p&gt;
&lt;p&gt;With Nuxt, you don’t need to think about how to structure your code, everything
has its own place already pre-established. Also, no need to install and
configure Vue &lt;strong&gt;routing&lt;/strong&gt;. Just place your files in the &lt;code&gt;pages&lt;/code&gt; folder and Nuxt
will automatically generate the routes according to the folder structure.&lt;/p&gt;
&lt;p&gt;Vuex &lt;strong&gt;state management&lt;/strong&gt; also comes installed by default. Add your modules
under &lt;code&gt;store&lt;/code&gt; and you’re good to go. Finally, HTML &lt;strong&gt;metadata&lt;/strong&gt; management is
also available, with &lt;code&gt;vue-meta&lt;/code&gt; operating under the hood.&lt;/p&gt;
&lt;p&gt;With these extra features in mind, even if you don’t need a SSR website, these
are still benefits of using Nuxt. I’d probably almost always go with Nuxt,
unless it was a really small-sized SPA (couple of routes only) with no SEO
requirements.&lt;/p&gt;
&lt;p&gt;Another scenario where you’d not want use Nuxt - which does not apply to a Nuxt
statically generated site - would be if you didn’t want to deal with
infrastructure and the potential costs of running a a Node.js server. Vue CLI
apps can be considered easier to deploy, since they typically compile down to
static assets, and thus be served from any common HTTP server or CDN.&lt;/p&gt;
&lt;p&gt;This being said, both have their own set of more appropriate use cases, so it’s
not so much as Vue CLI vs. Nuxt, but more about choosing which will best suit
your requirements. If you need faster initial rendering on first-load or SEO,
then Nuxt is for you. If you don’t need to worry about SEO and your app is
light, then Vue CLI will work perfectly.&lt;/p&gt;
&lt;h2 id=&quot;developer-experience&quot;&gt;Developer Experience&lt;/h2&gt;
&lt;p&gt;Nuxt has an official scaffolding tool, &lt;code&gt;create-nuxt-app&lt;/code&gt;, that guides you
through some options and setups a new project, so you can quickly start
developing.&lt;/p&gt;
&lt;p&gt;This is when the app’s &lt;code&gt;mode&lt;/code&gt; (SSR or SPA) is specified. There are also other
options available, where you can choose to integrate other frameworks
(server-side/UI/ testing). Linting and code formatting are also other features
the tool can add to your project.&lt;/p&gt;
&lt;p&gt;Being able to start a project without having to deal with the typical setup and
configuration is great!&lt;/p&gt;
&lt;p&gt;Out-of-the-box asset bundling - through Webpack - and code transpiling - through
Babel - worked flawlessly, and we didn’t need to extend the default build
configuration, nor did we run into any browser compatibility issue during the
whole project!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nuxt.config.js&lt;/code&gt; is the central point of a Nuxt app. It lives at the project
root and allows you to customize a set of features that Nuxt provides.&lt;/p&gt;
&lt;p&gt;Having a standard, predefined folder structure, increases the team’s
productivity. Everything has its place, no need tinkering about where to place
files. By being layout-based, Nuxt also helps avoiding code repetition.&lt;/p&gt;
&lt;p&gt;In dev mode, hot-reloading allows you to instantly view the results of source
code changes reflected on the browser.&lt;/p&gt;
&lt;p&gt;Asynchronously fetching data is highly facilitated through the combination of
&lt;code&gt;axios&lt;/code&gt; and the &lt;code&gt;asyncData&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Finally, building the app for production is as straightforward as &lt;code&gt;npm run build&lt;/code&gt; followed by &lt;code&gt;npm run start&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Our project runs on v2.10.2, which proved to be reliable and stable. Current
version, at the time of this writing, is v2.12.2.
I found Nuxt to be a robust, developer-friendly environment to work in.&lt;/p&gt;
&lt;h3 id=&quot;technical-struggles-&quot;&gt;Technical struggles 😰&lt;/h3&gt;
&lt;p&gt;The fact that I had to make an effort to remember any major issues faced,
already speaks for itself in terms of my positive experience using Nuxt.&lt;/p&gt;
&lt;p&gt;The only obstacles I can recall - mainly related to my incompetence with Nuxt at
the time - were a few tricky DOM-related errors, such as &lt;code&gt;The client-side rendered virtual DOM tree is not matching server-rendered content.&lt;/code&gt; and
&lt;code&gt;Mismatching childNodes vs. VNodes&lt;/code&gt;. I came to learn that these errors mostly
manifest when trying to use Vue.js libraries that don’t support SSR, and
therefore should only be instantiated client-side.&lt;/p&gt;
&lt;p&gt;In the end, I was able to fix all these errors and warnings with lengthy debug
sessions, by essentially trying to isolate the faulty components and applying
some combination of &lt;code&gt;&amp;lt;client-only&amp;gt;&lt;/code&gt; in the templates, and &lt;code&gt;ssr: false&lt;/code&gt; in the
plugin instantiation in &lt;code&gt;nuxt.config.js&lt;/code&gt;. Note to self: be more watchful of the
console, specially when adding a new library, that way you can detect if
something is wrong as soon as you introduce it.&lt;/p&gt;
&lt;p&gt;I also came to realize the importance of understanding the separate stages of
client/server execution and how Nuxt and Vue &lt;a href=&quot;https://dev.to/lilianaziolek/understanding-nuxt-vue-hooks-and-lifecycle-part-1-48lc&quot;&gt;hooks and
lifecycle&lt;/a&gt;
relate to each other.&lt;/p&gt;
&lt;p&gt;If you’re new to Nuxt, take some time to study its core concepts, as it can save
you a lot of headaches, for example when trying to figure out why you’re getting
&lt;code&gt;undefined&lt;/code&gt; when accessing the &lt;code&gt;window&lt;/code&gt; object or why you can only query and
manipulate the DOM in certain hooks.&lt;/p&gt;
&lt;p&gt;This schema from the &lt;a href=&quot;https://nuxtjs.org/guide&quot;&gt;official docs&lt;/a&gt; is an essential
resource to learn the sequence of steps that take place after the server
receives a request:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nuxt.js schema&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;460&quot; height=&quot;600&quot; src=&quot;https://ramigs.dev/_astro/2020-03-21-nuxt-schema.CjHzSMqk_ZKm1h.svg&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Something I came to discover, while trying to fix the previously mentioned
errors, was that we were writing some invalid HTML in our code, such as &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;
elements inside of &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; elements. Although in the end it proved to be
unrelated, some of the errors mentioned invalid HTML as a possible cause.&lt;/p&gt;
&lt;p&gt;Later, with the help of a &lt;a href=&quot;https://validator.w3.org/&quot;&gt;validator&lt;/a&gt;, we were able
to identify and fix almost all the invalid HTML. I wonder if this is a feature
that would make sense to have in dev mode. Maybe integrating with an already
existing plugin or tool? Who knows, if this could be my first contribution to
Nuxt 😃.&lt;/p&gt;
&lt;h2 id=&quot;community-and-plugin-ecosystem&quot;&gt;Community and Plugin Ecosystem&lt;/h2&gt;
&lt;p&gt;Nuxt is backed up by a strong active community. Its
&lt;a href=&quot;https://nuxtjs.org/guide/modules/&quot;&gt;modular&lt;/a&gt; architecture is ideal for the
emergence of extensions that add on to the framework’s core functionality. Plus,
the entire Vue plugin ecosystem is close at hand - just make sure it supports
SSR, if that’s your app’s &lt;code&gt;mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These are some modules and plugins that made our life so much easier, helping us
deliver faster and better:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://auth.nuxtjs.org/&quot;&gt;@nuxtjs/auth&lt;/a&gt; - Authentication and Authorization&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://axios.nuxtjs.org/&quot;&gt;@nuxtjs/axios&lt;/a&gt; - Axios integration&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nuxt-community/dotenv-module/&quot;&gt;@nuxtjs/dotenv&lt;/a&gt; - Loading &lt;code&gt;.env&lt;/code&gt; vars&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@nuxtjs/google-analytics&quot;&gt;@nuxtjs/google-analytics&lt;/a&gt; - Google Analytics&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nuxt-community/gtm-module&quot;&gt;@nuxtjs/gtm&lt;/a&gt; - Google Tag Manager&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@nuxtjs/toast&quot;&gt;@nuxtjs/toast&lt;/a&gt; - Cool little toasts&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/nuxt-lazy-load/v/latest&quot;&gt;nuxt-lazy-load&lt;/a&gt; - Effortless lazy-loading&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aceforth/nuxt-optimized-images&quot;&gt;@aceforth/nuxt-optimized-images&lt;/a&gt; - Image size optimization during build&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.surmon.me/vue-awesome-swiper/&quot;&gt;vue-awesome-swiper&lt;/a&gt; - Swiper component&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nightcatsama.github.io/vue-slider-component/#/&quot;&gt;vue-slider-component&lt;/a&gt; - Slider component&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/vue-youtube&quot;&gt;vue-youtube&lt;/a&gt; - Youtube wrapper&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/vue-loading-overlay&quot;&gt;vue-loading-overlay&lt;/a&gt; - Full-screen loading indicator&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/vue-js-modal&quot;&gt;vue-js-modal&lt;/a&gt; - Handy modal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, don’t miss out on this &lt;a href=&quot;https://github.com/nuxt-community/awesome-nuxt&quot;&gt;curated list&lt;/a&gt; of
awesome things related to Nuxt.js.&lt;/p&gt;
&lt;h2 id=&quot;was-it-worth-it-verdict&quot;&gt;Was it worth it? Verdict&lt;/h2&gt;
&lt;p&gt;Yes, absolutely!&lt;/p&gt;
&lt;p&gt;Just recently got the news from the marketing team, and last month we doubled
the number of users in comparison to the previous month, with a forecast of
reaching a total of 100k 🚀 users by the end of this month 🎉.&lt;/p&gt;
&lt;p&gt;I think Nuxt.js is an amazing, production-ready framework for modern web
development. If your website requires SSR, I definitely suggest you give it a
try.&lt;/p&gt;
&lt;p&gt;From the way it simplifies the setup of a project, to the solid build process,
the opinionated defaults and best practices, the built-in mechanisms for
asynchronously fetching data, and last but not the least, the ecosystem of
available plugins and the active community - all reasons that make me really
happy to have made the decision to go with Nuxt.&lt;/p&gt;
&lt;p&gt;On a more personal note, I learned a lot during the course of this project. It
was a period of massive evolution, where I had to do things I’d never done
before.&lt;/p&gt;
&lt;p&gt;There are of course, some things I would have done differently, if I was
starting the project again, knowing what I know today, but they are more related
to CSS and Vue, and not so much to Nuxt specifically.&lt;/p&gt;
&lt;p&gt;That’s it, hopefully I was able to give a comprehensible rundown of my first
steps getting to know and working with Nuxt 💚.&lt;/p&gt;
</content:encoded></item><item><title>Finding the array element that appears once</title><link>https://ramigs.dev/blog/finding-the-element-that-appears-once/</link><guid isPermaLink="true">https://ramigs.dev/blog/finding-the-element-that-appears-once/</guid><description>JavaScript solution to Finding the element that appears once in an array problem</description><pubDate>Sun, 24 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A few days ago, during a job interview, I was asked to live code three exercises
in JavaScript:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Palindrome check&lt;/li&gt;
&lt;li&gt;Find the element that appears once&lt;/li&gt;
&lt;li&gt;Fizz Buzz&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Exercises 1 and 3 went pretty well. I was able to implement them correctly, even
though, for Exercise 1, my initial answer didn’t cover all the edge cases
(forgot about space characters and upper/lower case).&lt;/p&gt;
&lt;p&gt;Exercise 2 was a bit trickier for me.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers, all the elements appear twice, except one element
that appears only once. Write an algorithm to find that element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The most obvious, brute force solution, consists of two nested loops, where each
element in the array is compared with all the other elements, in order to find
which element is not repeated. &lt;strong&gt;Time complexity&lt;/strong&gt; of this solution is O(n^2).&lt;/p&gt;
&lt;p&gt;I wanted to avoid an answer with such time complexity - also didn’t want to
write two nested &lt;code&gt;for&lt;/code&gt; loops. So, my first instinct was to look for a higher
order function, such as, &lt;code&gt;Array.prototype.find()&lt;/code&gt; or &lt;code&gt;Array.prototype.filter()&lt;/code&gt;,
to which I could pass a function that counted the number of occurrences of an
element in the array.&lt;/p&gt;
&lt;p&gt;Since I was allowed to check the web for syntax and built-in methods, I started
searching for such a method.&lt;/p&gt;
&lt;p&gt;I realized there’s no built-in method that does this in JavaScript and wasn’t
finding a simple and elegant solution.&lt;/p&gt;
&lt;p&gt;As I decided to implement a working solution, and worry about optimization
later, the interviewer rightfully commented about the time complexity of the
algorithm I was writing.&lt;/p&gt;
&lt;p&gt;In fact, this approach also has time complexity O(n^2).&lt;/p&gt;
&lt;p&gt;The interviewer proceeded to suggest creating an object and using the array
elements as its properties, to which the corresponding values would keep a
counter on the number of occurrences.&lt;/p&gt;
&lt;p&gt;I immediately remembered doing something similar before, so I knew
&lt;code&gt;Array.prototype.reduce()&lt;/code&gt; was the way to go.&lt;/p&gt;
&lt;p&gt;As I started to implement, I took a bit too much time to figure up the function
I needed to pass to &lt;code&gt;reduce()&lt;/code&gt; and I didn’t get the chance to
finish.&lt;/p&gt;
&lt;p&gt;So, here I am to complete this challenge and improve my understanding on how
&lt;code&gt;reduce()&lt;/code&gt; operates 😉.&lt;/p&gt;
&lt;p&gt;This solution has time complexity O(n) and consists of using a hash map to store
the count of each element. Then, it iterates through the keys and returns the
key which has count &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;findElementOnce&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;arr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; hash &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; arr.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;acc&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;acc.&lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(value) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; acc[value]&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; acc[value] &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; acc;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}, {});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; hash) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (hash[key] &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; key;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function findElementOnce(arr) {  let hash = arr.reduce((acc, value) =&gt; {    acc.hasOwnProperty(value) ? acc[value]++ : acc[value] = 1;    return acc;  }, {});  for (const key in hash) {    if (hash[key] === 1) {      return key;    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Important notes about this solution, which became now, clearer to me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the use of method &lt;code&gt;Object.prototype.hasOwnProperty()&lt;/code&gt; to check whether the
object already has the specified element as property.&lt;/li&gt;
&lt;li&gt;the function that’s passed to &lt;code&gt;reduce()&lt;/code&gt; has to return the accumulator.&lt;/li&gt;
&lt;li&gt;the second parameter of &lt;code&gt;reduce()&lt;/code&gt;, an empty object &lt;code&gt;{}&lt;/code&gt;, as
the initial value that is assigned to the accumulator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;During my research for this article, I’ve
&lt;a href=&quot;https://algorithms.tutorialhorizon.com/find-the-only-element-in-array-which-appears-only-once/&quot;&gt;discovered&lt;/a&gt;
that this challenge can also be solved efficiently, with time complexity O(n),
using the operator XOR.&lt;/p&gt;
&lt;p&gt;In fact, it can even be considered more efficient, since in terms of &lt;strong&gt;space
complexity&lt;/strong&gt; it has O(1), whilst the hashing solution has O(n).&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;findElementOnce&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#AE4B07;--1:#FFAB70&quot;&gt;arr&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;(arr.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; xor &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; arr[&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; arr.&lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; ; i&lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;xor &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;^=&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; arr[i];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#BF3441;--1:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; xor;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function findElementOnce(arr) {  if(arr.length == 0) return;  let xor = arr[0];  for (let i = 1; i &lt; arr.length ; i++) {    xor ^= arr[i];  }  return xor;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We know that &lt;code&gt;A XOR A = 0&lt;/code&gt;. If we XOR all the elements in the array, the
elements which are repeated twice will become &lt;code&gt;0&lt;/code&gt;, while the element which
is appearing only once will remain.&lt;/p&gt;
&lt;p&gt;There’s also a more complex version of this problem, where every element appears
three times instead of twice, but I’ll leave it for you to dive deeper 🌊.&lt;/p&gt;
</content:encoded></item><item><title>Creating a Pull Request on GitHub</title><link>https://ramigs.dev/blog/creating-a-pull-request-on-github/</link><guid isPermaLink="true">https://ramigs.dev/blog/creating-a-pull-request-on-github/</guid><description>Step-by-step guide on how to open a Pull Request on GitHub</description><pubDate>Fri, 01 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Pull requests allow you to let others know about features and fixes that you’d
like to add to a &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; project repository.&lt;/p&gt;
&lt;p&gt;Once you open a pull request, you’ll be able to discuss and review your proposed
changes with other collaborators, adding more commits if necessary, before your
changes are merged into the base branch.&lt;/p&gt;
&lt;p&gt;With a pull request, your changes are proposed in a new branch, which ensures
that the master branch only contains finished and approved work.&lt;/p&gt;
&lt;p&gt;In this short guide, I’ll describe the basic process of submitting a pull
request on GitHub.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Basic knowledge of &lt;code&gt;git&lt;/code&gt; via command line&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;A project you’d like to contribute to&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fork-the-repository&quot;&gt;Fork the repository&lt;/h2&gt;
&lt;p&gt;Sign-in to your GitHub account and fork the repository of the project you’d like
to contribute to:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Fork the repository&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2560&quot; height=&quot;1217&quot; src=&quot;https://ramigs.dev/_astro/2019-11-01-fork_repo.D25Aigsa_Z1C9Oe4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This creates a new repository copy, separate from the original codebase, owned
by you. Modify it as you please, it will not interfere with the original
project.&lt;/p&gt;
&lt;h2 id=&quot;clone-the-repository&quot;&gt;Clone the repository&lt;/h2&gt;
&lt;p&gt;Download a local project codebase, by cloning the repository you’ve forked:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://ramigs.dev/_astro/ec.blnl5.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://ramigs.dev/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;clone&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;https://github.com/ramigs/JavaScript30-1.git&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git clone https://github.com/ramigs/JavaScript30-1.git&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can get the URL from here:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Clone the repository&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2560&quot; height=&quot;1243&quot; src=&quot;https://ramigs.dev/_astro/2019-11-01-clone_url.BrHtcWVX_3oMz4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Navigate to the project folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;JavaScript30-1/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cd JavaScript30-1/&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;create-a-new-branch&quot;&gt;Create a new branch&lt;/h2&gt;
&lt;p&gt;A git branch is simply a divergent line of development, a pointer to a different
version of the codebase.&lt;/p&gt;
&lt;p&gt;Create a new branch where you´ll make your changes. Give it a suggestive name,
related to what the pull request intends to fix:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;checkout&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-b&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;fix-challenge-12-cornify-https&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git checkout -b fix-challenge-12-cornify-https&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;add-your-changes&quot;&gt;Add your changes&lt;/h2&gt;
&lt;p&gt;Go ahead and implement your fix or new feature locally.&lt;/p&gt;
&lt;h2 id=&quot;confirm-build-tests-and-docs&quot;&gt;Confirm build, tests and docs&lt;/h2&gt;
&lt;p&gt;Make sure the changes you’ve made, still keep the build process running
correctly. Run tests, if there are any, and update/regenerate the documentation,
if necessary.&lt;/p&gt;
&lt;p&gt;Most importantly, follow the contributing guidelines of the project.&lt;/p&gt;
&lt;h2 id=&quot;confirm-updated-files&quot;&gt;Confirm updated files&lt;/h2&gt;
&lt;p&gt;Check which files have local changes pending:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;status&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git status&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Validate the exact lines that were changed in each file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;diff&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git diff&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;commit-the-changes-locally&quot;&gt;Commit the changes locally&lt;/h2&gt;
&lt;p&gt;Commit the changes to your local repository:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git add .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;commit&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#005CC5;--1:#79B8FF&quot;&gt;-m&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;&quot;Replacing http by https in cornify.js import, to avoid insecure mixed content issues in some hosting providers&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git commit -m &amp;quot;Replacing http by https in cornify.js import, to avoid insecure mixed content issues in some hosting providers&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;push-your-branch-to-github&quot;&gt;Push your branch to GitHub&lt;/h2&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#6F42C1;--1:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;origin&lt;/span&gt;&lt;span style=&quot;--0:#24292E;--1:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#032F62;--1:#9ECBFF&quot;&gt;fix-challenge-12-cornify-https&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git push origin fix-challenge-12-cornify-https&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When the push executes, browse to your forked repo on GitHub, where GitHub will
recognize the branch you’ve just pulled.&lt;/p&gt;
&lt;p&gt;Go ahead and click &lt;strong&gt;Compare &amp;amp; Pull Request&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Push your branch to GitHub&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2560&quot; height=&quot;1271&quot; src=&quot;https://ramigs.dev/_astro/2019-11-01-compare_and_pull_request.G9ciEefh_2axjmy.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;open-pull-request&quot;&gt;Open pull request&lt;/h2&gt;
&lt;p&gt;One last confirmation to the changes you’re adding, to the subject and body of
your message, and you’re ready to open your pull request:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create Pull Request&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2560&quot; height=&quot;1324&quot; src=&quot;https://ramigs.dev/_astro/2019-11-01-create_pull_request.C4gApRTu_Z1rppHC.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Congratulations 🎉! You’ve just submitted your pull request.&lt;/p&gt;
&lt;p&gt;A notification was sent to the owner of the repository, with a request to
&lt;strong&gt;merge&lt;/strong&gt; the changes.&lt;/p&gt;
&lt;p&gt;Now, the owner of the repository will review your changes, and if everything
goes well, merge them with the main branch of the project.&lt;/p&gt;
</content:encoded></item><item><title>How the JAMstack inspired me to start blogging</title><link>https://ramigs.dev/blog/how-the-jamstack-inspired-me-to-start-blogging/</link><guid isPermaLink="true">https://ramigs.dev/blog/how-the-jamstack-inspired-me-to-start-blogging/</guid><description>Blogging with traditional monolithic CMSs vs. modern JAMstack web architectures</description><pubDate>Wed, 21 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is the story about how discovering and exploring the
&lt;a href=&quot;https://JAMstack.org/&quot;&gt;JAMstack&lt;/a&gt; has inspired me to finally kick off my
blogging ventures.&lt;/p&gt;
&lt;p&gt;I’ll also be giving an overview of what the JAMstack is - main concepts,
benefits of such architectures, and how they can foster the use of modern
development workflows.&lt;/p&gt;
&lt;p&gt;This article does not intend to convey that the JAMstack is the &lt;em&gt;be all end all&lt;/em&gt;
solution for every software architecture use case out there. It does not mean to
express that we should immediately be ditching all our legacy projects,
replacing them with JAMStack applications.&lt;/p&gt;
&lt;p&gt;As in most questions regarding software architecture (and life for that matter),
&lt;em&gt;depends&lt;/em&gt; usually is the better answer. Each case should be evaluated according
to its specific requirements. Here, I’ll be referring to my blogging use case.&lt;/p&gt;
&lt;p&gt;Many times throughout my developer path I’ve fiddled with the idea of starting a
tech-related blog. The motivation mostly derived from the frustration caused by
not having a systematic approach that allowed me to save useful commands,
configurations, or certain &lt;em&gt;aha moments&lt;/em&gt; about a language/tool I’d be learning
or using at the time. I’d end up just saving stuff in a bunch of random text
files that would eventually get lost.&lt;/p&gt;
&lt;p&gt;I realized that over the years, I’ve been doing and learning so many things. All
the projects I’ve worked on, the knowledge I’ve exchanged with the teams I was
part of; but no reference or online trace of it, besides a couple of bullet
points on my LinkedIn profile. Besides, it’s high time I start giving back in
return to the tech community, which has given me so much.&lt;/p&gt;
&lt;p&gt;That’s why I decided to start this blog, as a way to somehow condense,
materialize, and share my discoveries.&lt;/p&gt;
&lt;p&gt;Also, as far as I know, there’s no better way of solidifying knowledge about a
topic than to present and explain it to others. It kind of forces us to find out
exactly what we know and establish clear mental models about it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“When you face problems that you’ve solved in the past, you don’t always
remember exactly what the solution was. When you are blogging frequently, you
can always search through your blog and find the answer.” - &lt;em&gt;&lt;a href=&quot;https://buttercms.com/blog/building-your-personal-brand-with-your-developer-blog&quot;&gt;Paweł
Dąbrowski&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this post, I’ll explain how opting for a JAMstack approach to build and
deploy my website (and blog) frees me up, and allows me to focus on what’s
really important, which is creating content to the best of my abilities.&lt;/p&gt;
&lt;h2 id=&quot;looking-back-for-insight&quot;&gt;Looking back for insight&lt;/h2&gt;
&lt;p&gt;Reflecting upon my avoidance to start a blog, I’ve recently came to terms with
the reasons.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“For the longest time, I wanted to know how to make my OWN blog - not rely on
Blogger, or WordPress(.com) hosting, but something I hosted myself with my own
design - not someone elses theme. But how? I didn’t know how and it was
immensely frustrating.” - &lt;em&gt;&lt;a href=&quot;https://www.taniarascia.com/everything-i-know-as-a-software-developer-without-a-degree/&quot;&gt;Tania Rascia&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;the-era-of-monolithic-cmss&quot;&gt;The era of monolithic CMSs&lt;/h3&gt;
&lt;p&gt;There is this saying we’ve all seen somewhere about how
&lt;a href=&quot;https://wordpress.org/&quot;&gt;Wordpress&lt;/a&gt; &lt;em&gt;powers 30 percent of the web&lt;/em&gt;. Is it true?
Is it false? Who knows. Though one thing is for sure: CMSs (Content management
systems) deserve recognition for making content publishing much more accessible
to non-technical authors.&lt;/p&gt;
&lt;p&gt;Around 2008 or 2009, I remember trying to set up a blog. I wanted to learn how
to host it myself. I had this noisy old computer in my room, running
&lt;a href=&quot;https://ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;, where I started to do some experiments with
&lt;a href=&quot;https://www.joomla.org/&quot;&gt;Joomla&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let me pause for a moment and try to recall the steps I had to take:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Secure_Shell&quot;&gt;SSH&lt;/a&gt; installation - so I could login
and update the site from anywhere&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/LAMP_(software_bundle)&quot;&gt;LAMP&lt;/a&gt; installation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/&quot;&gt;Apache&lt;/a&gt; configuration&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mysql.com/&quot;&gt;MySQL&lt;/a&gt; configuration&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joomla.org/&quot;&gt;Joomla&lt;/a&gt; installation&lt;/li&gt;
&lt;li&gt;Dynamic IP to static hostname configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After all the pieces were finally connected, I went on a theme-browsing spree.
Nothing seemed to fit with what I was looking for. When I tried to change or
customize something, somehow I always ended with a broken site.&lt;/p&gt;
&lt;p&gt;Mind you, I have to admit I was very inexperienced as a developer at the time.
Nevertheless, it didn’t feel as if setting up a blog should be that difficult.&lt;/p&gt;
&lt;p&gt;Throughout my professional journey I’ve encountered numerous Wordpress sites.
I’ve seen and been involved in projects where it was being used for diverse use
cases. In many, it seemed like Wordpress was being selected without much
consideration - besides market popularity - in terms of what the project
actually needed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Regardless of how much experience you have, while designing a system, your
priority should be meeting all the requirements with the least complexity.” -
&lt;em&gt;&lt;a href=&quot;https://simpleprogrammer.com/modern-software-design/&quot;&gt;Zlatin Stanimirovv&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For some of the projects, which simply served as brochure sites, Wordpress’s
complexity and extended functionality was a clear overkill.&lt;/p&gt;
&lt;h3 id=&quot;drawbacks-of-having-content-stored-in-a-database&quot;&gt;Drawbacks of having content stored in a database&lt;/h3&gt;
&lt;p&gt;Within the context of a CMS, content can take form in many different ways:
posts, comments, users, roles, permissions, settings, and version control - if
there’s any. Typically, with traditional monolithic CMSs, content is stored in a
database. The database introduces an additional layer of complexity.&lt;/p&gt;
&lt;p&gt;For each and every request a client makes to the CMS, content has to be
retrieved from the database. Then, through the template engine, it’s rendered
into HTML. Finally, the response is sent across the network to the browser that
requested it.&lt;/p&gt;
&lt;p&gt;To lighten the overhead, many web architectures end up resorting to caching
mechanisms, so that the load on the database can be reduced. Well implemented
caching schemes require complex setups. Improvement in performance comes at the
cost of added &lt;strong&gt;complexity to the development process&lt;/strong&gt;. Also, if for whatever
reason you decide to migrate to a new CMS, you’d have to take into account the
&lt;strong&gt;technical cost&lt;/strong&gt; of exporting, transforming and importing the data
to the new CMS.&lt;/p&gt;
&lt;p&gt;With this type of architectures, web/application servers &lt;strong&gt;repeatedly&lt;/strong&gt; need to
consult the database and build the page for each request. But, what if the
&lt;strong&gt;content didn’t even change&lt;/strong&gt;? Should we really be taking all these steps to
produce the resulting HTML every time? In a CMS, for example, posts are not
expected to change that much. Is there any way to improve &lt;strong&gt;performance&lt;/strong&gt;, by
avoiding the repetition of these steps when it’s not required?&lt;/p&gt;
&lt;h3 id=&quot;dealing-with-infrastructure&quot;&gt;Dealing with infrastructure&lt;/h3&gt;
&lt;p&gt;I’ve mentioned how deciding to go the self-hosting route forces us to deal with
the associated required setup and infrastructure.&lt;/p&gt;
&lt;p&gt;All of those things take away a lot of time that should be put into crafting and
delivering great websites and applications, not on server setup and
administration.&lt;/p&gt;
&lt;p&gt;Unless we find ways to delegate/outsource such tasks and &lt;em&gt;stand on the shoulders
of giants&lt;/em&gt;, automating and streamlining our development workflows for better
productivity will be much more complicated.&lt;/p&gt;
&lt;p&gt;Fortunately, JAMstack architectures integrate wonderfully with the rising PaaS
(Platform as a Service) and IaaS (Infrastructure as a Service) ecosystems.&lt;/p&gt;
&lt;h2 id=&quot;towards-the-jamstack&quot;&gt;Towards the JAMstack&lt;/h2&gt;
&lt;p&gt;JAMstack is a modern web development architecture that delivers better
performance, higher security, and lower cost of scaling.&lt;/p&gt;
&lt;p&gt;It’s not defined by specific technologies or standards - although it encourages
us to leverage the progressing capabilities of client-side JavaScript.&lt;/p&gt;
&lt;p&gt;The JAMstack is more like a movement towards an architectural pattern, a set of
best practices and development workflows that combine well together and improve
the experience for both users and developers.&lt;/p&gt;
&lt;p&gt;JAMstack stands for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JavaScript&lt;/strong&gt; as runtime&lt;/li&gt;
&lt;li&gt;Reusable HTTP &lt;strong&gt;APIs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Prebuilt &lt;strong&gt;Markup&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This site falls under the JAMstack umbrella. Let’s take a look at the basic
steps of a typical JAMstack workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The source is hosted in a repository that stores &lt;strong&gt;content and code
together&lt;/strong&gt; as editable text files.&lt;/li&gt;
&lt;li&gt;Whenever a change is pushed to the repository, a build process is triggered,
the site is pre-rendered, and the final HTML is created from layouts and content.&lt;/li&gt;
&lt;li&gt;The pre-built site and prepared assets are published globally on a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Content_delivery_network&quot;&gt;CDN&lt;/a&gt; (Content
Delivery Network), putting them as close to end users as physically possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;content-delivery-network&quot;&gt;Content Delivery Network&lt;/h3&gt;
&lt;p&gt;A CDN consists of a series of servers distributed all around the globe, linked
together. In order to improve response speed - reducing latency - a CDN
distributes website assets (HTML, JavaScript, CSS, and media) so that they are
reasonably physically near - to every user that might want to access the
website.&lt;/p&gt;
&lt;h3 id=&quot;static-site-generators&quot;&gt;Static Site Generators&lt;/h3&gt;
&lt;p&gt;Typically, the build process of a JAMstack website will be executed by a SSG
(Static Site Generator).&lt;/p&gt;
&lt;p&gt;A SSG retrieves both (1) frontend code (CSS/JavaScript assets) and (2) content
from regular text files (in some structured format, such as
&lt;a href=&quot;https://mozilla.github.io/nunjucks/&quot;&gt;Nunjucks&lt;/a&gt; or
&lt;a href=&quot;https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet&quot;&gt;Markdown&lt;/a&gt;),
and builds a &lt;em&gt;static&lt;/em&gt; site.&lt;/p&gt;
&lt;p&gt;It’s important to not misunderstand the meaning of &lt;em&gt;static&lt;/em&gt; in this context. It
should not be interpreted as in &lt;em&gt;static&lt;/em&gt; vs &lt;em&gt;dynamic&lt;/em&gt; user interfaces, but more
as in straight HTML/CSS/JavaScript, that doesn’t need any application server or
database, in order to run properly. A simple web server is enough.&lt;/p&gt;
&lt;p&gt;With the disassembling of monolithic architectures and the separation of build,
deploy, and runtime - SSGs started to gain prominence, mainly through
&lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt;,
&lt;a href=&quot;https://www.11ty.io/&quot;&gt;11ty&lt;/a&gt;, &lt;a href=&quot;https://www.gatsbyjs.org/&quot;&gt;Gatsby&lt;/a&gt;, and
&lt;a href=&quot;https://www.staticgen.com&quot;&gt;others&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;additional-functionality-through-microservices&quot;&gt;Additional functionality through microservices&lt;/h3&gt;
&lt;p&gt;Even though JAMstack architectures promote the use of client browsers as
runtime, there are certain tasks and logic we’d prefer to run server-side.&lt;/p&gt;
&lt;p&gt;Advanced search, payments, and authentication are examples of such services.
Also, security-wise, API keys should not be shipped with the JavaScript we
deliver to the client.&lt;/p&gt;
&lt;p&gt;One solution is to proxy these requests through &lt;strong&gt;microservices&lt;/strong&gt;. Microservice
architectures allow developers to build applications out of modular, smaller
components and integrate with third-party services.&lt;/p&gt;
&lt;p&gt;Frontend JavaScript acts as the glue, orchestrating microservices together, and
giving us the ability to enrich our applications with additional functionality,
that was generally provided through plugin ecosystems, inside monolithic CMSs.&lt;/p&gt;
&lt;p&gt;By separating different services into smaller microservices, with well-defined
purposes, we can better comprehend the system globally, instead of having to
understand the inner complexities of each individual service.&lt;/p&gt;
&lt;p&gt;Need image processing added to your workflow? Search functionality? E-commerce?
The pervasiveness of service APIs allows us to outsource and delegate these
responsibilities to expert &lt;a href=&quot;https://serverless.css-tricks.com/services/major/&quot;&gt;service
providers&lt;/a&gt;, instead of having
to write our own implementations.&lt;/p&gt;
&lt;h3 id=&quot;headless-cmss-as-editor-friendly-uis&quot;&gt;Headless CMSs as editor-friendly UIs&lt;/h3&gt;
&lt;p&gt;While it’s easy to picture developers editing text files locally and pushing
them to GitHub through the command-line, what about content editors who aren’t
developers and might not be familiar with Git and Markdown? For non-technical
users, such workflows may not be the best solution at all.&lt;/p&gt;
&lt;p&gt;The JAMstack has fathered a new generation of content editing
&lt;a href=&quot;https://headlesscms.org/&quot;&gt;tools&lt;/a&gt; with intuitive interfaces, that look and
function like traditional CMSs, but actually push changes into version control
repositories.&lt;/p&gt;
&lt;p&gt;In this way, everyone can participate in the same workflow, enjoying the
benefits of modern version control software — even if unaware about what’s
happening behind the scenes.&lt;/p&gt;
&lt;h2 id=&quot;benefits-of-using-a-jamstack-architecture&quot;&gt;Benefits of using a JAMstack architecture&lt;/h2&gt;
&lt;p&gt;Let’s examine some of the advantages of the JAMstack.&lt;/p&gt;
&lt;h3 id=&quot;less-infrastructure-costs&quot;&gt;Less infrastructure costs&lt;/h3&gt;
&lt;p&gt;Discussing project costs is certainly very subjective, as each one has to be
analyzed according to its specificities. Nonetheless, hosting infrastructure is
definitely a major aspect to consider.&lt;/p&gt;
&lt;p&gt;A JAMstack site can be served from a CDN - with all the mentioned benefits this
brings - while a traditional monolithic site needs some server that builds the
page every time it’s requested.&lt;/p&gt;
&lt;p&gt;By pre-rendering a website at build time, the infrastructure costs are
significantly diminished. The runtime technology cost simply becomes the cost of
serving static HTML/CSS/JavaScript files.&lt;/p&gt;
&lt;p&gt;This surely doesn’t mean that applications and services are now suddenly running
on the ether, and not on physical servers. You’re probably familiar with the
running joke about how the cloud is just “someone else’s computer”.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Now we have an architectural pattern that utilizes a compute model that
abstracts away infrastructure management, allowing developers to focus
primarily on business logic by (at most) writing code that consumes other
services.” - &lt;em&gt;&lt;a href=&quot;https://www.jeremydaly.com/stop-calling-everything-serverless/&quot;&gt;Jeremy
Daly&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The important aspect, in my opinion, is that we can now delegate infrastructure
management as on-demand services (network, operating systems, storage, security,
and scaling). This way, we are able to focus only on solving the business requirements
of our projects, and significantly improve effort allocation of dev teams.&lt;/p&gt;
&lt;h3 id=&quot;performance&quot;&gt;Performance&lt;/h3&gt;
&lt;p&gt;Performance is very important. The widespread of mobile has made us more
impatient and eager for immediacy. We expect sites to load very fast, and
quickly dismiss slow pages.&lt;/p&gt;
&lt;p&gt;We also know that, for at least the last ten years, search engines have been
incorporating &lt;a href=&quot;https://webmasters.googleblog.com/2010/04/using-site-speed-in-web-search-ranking.html&quot;&gt;site speed&lt;/a&gt;
factors in their ranking algorithms.&lt;/p&gt;
&lt;p&gt;With monolithic architectures and server-side rendering, all layers of the stack
are involved - every time the user makes a request to a site or application.&lt;/p&gt;
&lt;p&gt;So, instead of having each HTTP request build the entire page on the fly, we can
instead deliver it directly to the client. This is a great way to minimize our
&lt;strong&gt;time to first byte&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Through the &lt;strong&gt;asynchronous capabilities of JavaScript&lt;/strong&gt;, we can start
to think in a more modular way, having greater control over the data flow of our
applications.&lt;/p&gt;
&lt;h3 id=&quot;security&quot;&gt;Security&lt;/h3&gt;
&lt;p&gt;Securing a traditional monolithic CMS involves continuous monitoring and effort.
The server/infrastructure needs to be managed and kept up-to-date. Security
patches need to be applied to Wordpress sites, each time a new security issue is
announced.&lt;/p&gt;
&lt;p&gt;JAMstack applications benefit from a smaller and simpler stack, when compared to
traditional architectures - with their various servers and databases. By
minimizing the number of layers, we also narrow down the attack surface area. If
&lt;em&gt;there is no&lt;/em&gt; backend, there is much less that can go wrong.&lt;/p&gt;
&lt;h3 id=&quot;workflow-flexibility&quot;&gt;Workflow flexibility&lt;/h3&gt;
&lt;p&gt;Monolithic applications can undermine our ability to integrate with third-party
technology, and impede changes that could benefit our development workflows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Monolithic applications, by definition, are a single unit. This means that
deploying a monolith to production is an all or nothing proposition.” - &lt;em&gt;&lt;a href=&quot;https://www.jeremydaly.com/an-introduction-to-serverless-microservices/&quot;&gt;Jeremy
Daly&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A poor development experience can be devastating for a project. It can impede
progress and bring uncertainty. Undesired side-effects and maintenance
implications.&lt;/p&gt;
&lt;p&gt;Every developer will inevitably run into a legacy project or some old codebase,
where everything just resembles a castle of cards, in danger of collapsing at
any moment. No one wants to take take risks and try to innovate in such
projects.&lt;/p&gt;
&lt;p&gt;How does it feel when you jump on a project and it’s really easy to get
everything running seamlessly on your machine? Pretty amazing, right?&lt;/p&gt;
&lt;p&gt;Decoupling frontend from server functionality allows for better productivity, as
different teams can focus on different parts of the project.&lt;/p&gt;
&lt;p&gt;Decoupling build, deploy, and runtime offers a clear separation between the
workflow processes - making it much easier to develop and maintain.&lt;/p&gt;
&lt;p&gt;What I like the most about these type of workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easy local dev environment&lt;/strong&gt;. Simply consists of cloning the repository,
installing the dependencies, and running a local web server.&lt;/li&gt;
&lt;li&gt;Integration with &lt;strong&gt;continuous deployment tools&lt;/strong&gt;, HTTPS and domain
configuration, all in the &lt;strong&gt;same workflow&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Working with text files&lt;/strong&gt;, which allows full control over content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atomic deploys&lt;/strong&gt;. The new version only goes live when everything is ready
and all the assets can be served. No more error-prone FTP uploads. Trivial to
roll back to any state, at any time. Complex staging environments are no
longer needed, as previewing and testing changes can be done through Git’s
branching system and Netlify’s workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;netlify-and-workflow-automation&quot;&gt;Netlify and workflow automation&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; is an awesome CD/CI platform I’ve been
exploring lately. It lets me automate the entire workflow for my frontend web
projects.&lt;/p&gt;
&lt;p&gt;In a nutshell, a Netlify site is connected to a Git repository. Every time a
change is pushed, a build tool (such as &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;gulp&lt;/code&gt;) is triggered. A new
version of the website is generated, and Netlify automatically deploys and
publishes it through a CDN.&lt;/p&gt;
&lt;p&gt;Add Netlify to your workflow and no more wrestling with hosting, deploy
rollbacks, securing, and scaling. A simple push to Git and it just takes care of
itself. Really cool!&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The JAMstack contributes to a better developer experience, which leads to higher
productivity, happier teams, and a more stable ground for innovation at all
dimensions of a project.&lt;/p&gt;
&lt;p&gt;As a developer, I chose to go with the JAMstack approach, which gives me total
workflow flexibility and ownership over my content.&lt;/p&gt;
&lt;p&gt;At the end of the day, striving for better content creation is easier when we
have full control. The JAMstack makes this possible - and as a bonus, it also
contributes to a faster, more stable and secure web experience for both users
and developers.&lt;/p&gt;
&lt;p&gt;If you’re interested to learn more about the JAMstack, I recommend a great book
called &lt;a href=&quot;https://www.netlify.com/oreilly-JAMstack/&quot;&gt;Modern Web Development on the
JAMstack&lt;/a&gt;, by &lt;a href=&quot;https://github.com/biilmann&quot;&gt;Mathias
Biilmann&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://www.hawksworx.com/&quot;&gt;Phil
Hawksworth&lt;/a&gt;. It provides real world use cases of the
JAMstack.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Before ending my &lt;em&gt;official&lt;/em&gt; first blog post ever 🚀, I want to give a shout-out 📣 to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.taniarascia.com&quot;&gt;Tania Rascia&lt;/a&gt;, for the inspiration in terms of
writing and presentation style.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.webstoemp.com/&quot;&gt;Webstoemp&lt;/a&gt;, for the amazing &lt;a href=&quot;https://www.webstoemp.com/blog/switching-to-gulp4/&quot;&gt;Gulp
pipeline&lt;/a&gt;, which I’m using
as a boilerplate for building this site.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item></channel></rss>