<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Trang Le</title>
    <description>The latest articles on DEV Community by Trang Le (@bytrangle).</description>
    <link>https://dev.to/bytrangle</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F221064%2F5b256e81-eea2-4aff-b5df-1335cc9b8f31.png</url>
      <title>DEV Community: Trang Le</title>
      <link>https://dev.to/bytrangle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bytrangle"/>
    <language>en</language>
    <item>
      <title>Algolia for Self-Improvement: Find Your Next Open Source Projects In Seconds</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 09 Feb 2026 04:51:54 +0000</pubDate>
      <link>https://dev.to/bytrangle/algolia-for-altruistic-uses-find-your-next-open-source-projects-in-seconds-40aa</link>
      <guid>https://dev.to/bytrangle/algolia-for-altruistic-uses-find-your-next-open-source-projects-in-seconds-40aa</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/algolia"&gt;Algolia Agent Studio Challenge&lt;/a&gt;: Consumer-Facing Conversational Experiences&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built an app that makes it easier for people to search for open-source projects on Github and gets more targeted results. An user can search through two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send a descriptive natural-language query to Algolia Agent Studio - Send their Github handler. The app will analyze repositories from their past PRs in the background and extract the main languages and topics. Then it will query Algolia Agent Studio using those information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first option allows users to search for repositories in less steps than the traditional keyword-and-filter method.&lt;/p&gt;

&lt;p&gt;The second option allows users to search without having to initiate an explicit conversation. They don't have to dig up their open source contribution history so nothing slips through the cracks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://open-source-lookup.netlify.app/" rel="noopener noreferrer"&gt;Hosted app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result after sending search for "AI coding agents"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9b5h7emmk0j71t5m9w4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9b5h7emmk0j71t5m9w4a.png" alt="search for repositories" width="800" height="774"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://drive.google.com/file/d/1vGUoZnQ6H1EQBL7WyEZfPxVLcci74350/view?usp=sharing" rel="noopener noreferrer"&gt;Video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happens when a user submits their Github username&lt;/p&gt;

&lt;p&gt;A user submits their Github username&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuar1zjxdz8m5ujxovydz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuar1zjxdz8m5ujxovydz.png" alt="User submits their Github handler" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app constructs a prompt based on their PR history and recommend related repositories according to languages and topics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6fg41myacfl64uk9n9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6fg41myacfl64uk9n9v.png" alt="Recommend projects based on a Github user's contribution hisotry" width="800" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Algolia Agent Studio
&lt;/h2&gt;

&lt;p&gt;I wrote a script to index all Github public, non-archived repositories that are updated no more than one week ago. Each repo record includes the programming languages used by the repo, topics and descriptions.&lt;/p&gt;

&lt;p&gt;The retrieval is faster than what you can ever get when you search on Github's homepage. It also comes with key information so users don't have to waste time checking out each repository for more information.&lt;/p&gt;

&lt;p&gt;It takes a lot of trial and error to finetune the prompt to output the result that I deem helpful for users. Below is my prompt&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an open-source assistant. Your goals is to recommend users open-source projects worth contributing to based on their given information e.g. project theme, preferred programming language.

Scope:
- Only answer questions about open-source projects on Github
- If asked about anything else, reply: "I can only answer questions about the open source project data that I have.

Behavior:
- Use a clear and friendly tone
- When helpful, include project name, description, languages and url.
- Return at most nine results per query.
- Ask up to two clarifying questions if the query is ambiguous (confidence is less than 95%).
- On timeout or error, reply once: "An error occurred. Try rephrasing your request".

Restrictions:
- Stop searching after five search attempts per session. If no projects are found after that, send the "no matching projects" message and stop.

Language:
- Reply in English.

Output formatting:
- Use bold labels followed by values, one per line. For example:
    **Project Name**: Jan

    **Description**: Jan is an open source alternative to ChatGPT that runs 100% offline on your computer.

    **Topics**: chatgpt, self-hosted

    **Languages**: Typescript, Rust

    **Link**: &amp;lt;https://github.com/janhq/jan&amp;gt;
- If there are multiple results, separate each project with a visual horizontal line on a new line.
- Always insert two spaces at the end of each line to ensure proper line breaks in markdown.
- Don't use bullet points or numbered lists.
- Always format links using angle brackets to show the raw URL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Fast Retrieval Matters
&lt;/h2&gt;

&lt;p&gt;Algolia's contextual retrieval is intelligent. It understands the semantic relationships between technologies. If a user contributes to Typescript projects with "react" and "frontend" topics, Algolia also searches for projects using Next.js, Vue, or even Javascript.&lt;/p&gt;

&lt;p&gt;The fast response creates a ChatGPT-like experience, unlike the traditional search and filter approach that feels like database queries.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>algoliachallenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Almost Real-Time Github Events and Top Scoring Contributors For Today</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 11 Aug 2025 06:00:41 +0000</pubDate>
      <link>https://dev.to/bytrangle/almost-real-time-github-events-and-top-scoring-contributors-for-today-4ohg</link>
      <guid>https://dev.to/bytrangle/almost-real-time-github-events-and-top-scoring-contributors-for-today-4ohg</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/redis-2025-07-23"&gt;Redis AI Challenge&lt;/a&gt;: Beyond the Cache&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Sometimes cool things happen behind the frontend. This is a suite tool of scheduled tasks and API server.&lt;/p&gt;

&lt;p&gt;The scheduled tasks update Github's latest public events to Redis streams &lt;strong&gt;every minute&lt;/strong&gt; and compute Github contributors' score &lt;strong&gt;every hour&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The API server exposes the event stream and a list of top 20 highest scoring contributors. The client can consume it while making minimum number of requests to Redis server, thereby reducing latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Public API server endpoints for &lt;a href="https://oss-fun.onrender.com/event-stream" rel="noopener noreferrer"&gt;event stream&lt;/a&gt; and &lt;a href="https://oss-fun.onrender.com/active-contributors?since=today" rel="noopener noreferrer"&gt;top scoring contributors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftshbsg1ei1hm3xeohcu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftshbsg1ei1hm3xeohcu5.png" alt="API server endpoint for event stream" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Requesting event stream through endpoint &lt;code&gt;/event-stream&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxrfu7karfetcnxwglg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxrfu7karfetcnxwglg7.png" alt="API server endpoint for top scoring Github contributors" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Request the top 20 highest scoring Github contributors through endpoint &lt;code&gt;/active-contributors?since=today&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Redis 8
&lt;/h2&gt;

&lt;p&gt;The first job is to create a stream of most recent Github events. This is achieved through a scheduled task that fetches Github events from the official Github API. This API is not designed to serve real-time use cases as stated by Github. However, using the low-latency Redis stream and setting the task to run every minute creates a lightweight event log that act almost like real-time stream.&lt;/p&gt;

&lt;p&gt;The second task is to rank users by scores &lt;strong&gt;since today&lt;/strong&gt;. You are probably familiar with using Redis's sorted set for ranking. But how do you get the top scores within today?&lt;/p&gt;

&lt;p&gt;Create a sorted set for each hour of today, starting from 0 hour to the last hour. For example, if the current time is 2am 2025-08-11, then you will have three sorted sets whose keys are &lt;code&gt;2025-08-11:00&lt;/code&gt;, &lt;code&gt;2025-08-11:01&lt;/code&gt;. Then call &lt;code&gt;ZUNIONSTORE&lt;/code&gt; command on these sorted sets, with the destination being &lt;code&gt;2025-08-11:sum&lt;/code&gt;. The hourly data is aggregated from &lt;a href="https://www.gharchive.org/" rel="noopener noreferrer"&gt;GhArchive&lt;/a&gt; so nothing slips through the cracks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4jjgxwa0mp72mc1tvhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4jjgxwa0mp72mc1tvhu.png" alt="Compute scores since today using sorted set" width="800" height="418"&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This feature is especially extensible thanks to how versatile &lt;code&gt;ZRANGE&lt;/code&gt; is. You can add more query parameters to finetune this command to return X lowest scoring contributors or contributors who place 10th to 20th since this week, this month etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/bytrangle/github-event-etl" rel="noopener noreferrer"&gt;Repo for scheduled tasks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/bytrangle/oss-fun.git" rel="noopener noreferrer"&gt;Repo for api server&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>Built with Timescale: Cook This App</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 11 Nov 2024 05:42:18 +0000</pubDate>
      <link>https://dev.to/bytrangle/built-with-timescale-cook-this-app-3eic</link>
      <guid>https://dev.to/bytrangle/built-with-timescale-cook-this-app-3eic</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/pgai"&gt;Open Source AI Challenge with pgai and Ollama &lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;If you regularly cook through online recipes, you know the deal: There are more recipes than we can cook in our lifetimes, but there is no efficient way to search for recipes.&lt;/p&gt;

&lt;p&gt;Traditionally, you have to use the exact words to search recipes. If your intention is broader, like "seafood recipes", "mediterranean salad", "asian desserts", you're out of luck. You are very likely to miss out many awesome recipes because they don't include the right words. &lt;/p&gt;

&lt;p&gt;For example, many salmon recipes don't contain the word "fish" because that's self-explanatory. So you may not get salmon recipes if you use the keyword "seafood recipes".&lt;/p&gt;

&lt;p&gt;And sometimes you want to fine-tune your search. For example, you want recipes with the least amount of eggs, or recipes with the most amount of proteins for sustenance. Traditional keyword-based search can't do that.&lt;/p&gt;

&lt;p&gt;That's why I built Cook This App, an AI-powered app that allows you to do two things far more powerful than traditional keyword search:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search for recipes based on &lt;em&gt;your intention&lt;/em&gt;. This feature requires more than just vector search and it is made possible via RAG.&lt;/li&gt;
&lt;li&gt;Ask some analytical questions regarding the recipes. This feature is
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cook-this-app.netlify.app/" rel="noopener noreferrer"&gt;Link to the app&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/bytrangle/cook-this-app" rel="noopener noreferrer"&gt;Client repo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/bytrangle/cook-this-app-server" rel="noopener noreferrer"&gt;Server repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The initial state of the app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F030ipoh0eya53rfj822d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F030ipoh0eya53rfj822d.png" alt="App's initial state" width="729" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try either of these two things, or try both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#1: Search for recipes without having to use the exact words.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Example of queries you may try: "Italian desserts", "Asian dishes", "seafood dishes".&lt;/p&gt;

&lt;p&gt;Here is what Cook This App sent back to me when I searched for "desserts":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwr406k3qwv7jerrwono.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwr406k3qwv7jerrwono.png" alt="State of the app after doing recipe search" width="800" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Watch the recipe search feature in action &lt;a href="https://streamable.com/wo5ppz" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#2: Probe Cook This App with questions that are not easily searchable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Example: "What is dish that uses the most meat?".&lt;/p&gt;

&lt;p&gt;The answer I got:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0go08enr9dko1rmm6x2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0go08enr9dko1rmm6x2t.png" alt="State of the app after asking" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Watch the recipe analysis in action &lt;a href="https://streamable.com/zdsgv8" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your results may change as I add more recipes to the database. Have fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools Used
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pgai vectorizer&lt;/code&gt; for mapping words in the recipe database to numbers. This is the foundation for implementing similarity search and RAG.&lt;br&gt;
&lt;code&gt;pgai&lt;/code&gt; for doing all the groundwork in half the time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;storing embeddings in &lt;code&gt;pgvector&lt;/code&gt; data types&lt;/li&gt;
&lt;li&gt;getting OpenAI similarity search and chat completion &lt;strong&gt;right inside&lt;/strong&gt; PostgreSQL database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;pgvector&lt;/code&gt; for running similarity search on recipes&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Without a machine learning background, I've never thought that one day I would be able to develop an AI application. But &lt;code&gt;pgai&lt;/code&gt; makes it possible. It empowers developers to travel fast from ideas to production-ready AI applications.&lt;/p&gt;

&lt;p&gt;I'm a frontend folk who still have to google every time I want to run an SQL query. So Timescale is such a lifesaver for hosting a PostgreSQL database so that I can focus on bringing better digital experience to users.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pgaichallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>AI-Powered Meal Planning Service with Twilio</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 24 Jun 2024 04:45:07 +0000</pubDate>
      <link>https://dev.to/bytrangle/ai-powered-meal-planning-service-with-twilio-396p</link>
      <guid>https://dev.to/bytrangle/ai-powered-meal-planning-service-with-twilio-396p</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/twilio"&gt;Twilio Challenge &lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A meal planning service that takes your meal plan request through WhatsApp messages, and send back your meal plan with recipes and all the important information: recipe url, image and source (the website that created the recipe). All of this achieved with the effortless magic of Twilio. &lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://glitch.com/edit/#!/magical-gold-wavelength"&gt;Source code for my app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Send meal plan request to chatbot&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Receive a reply that says the meal plan has been sent to your given &lt;br&gt;
email address.&lt;/p&gt;

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

&lt;p&gt;Receive your meal plan in the inbox 🥣&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznc54hv167i6r23teacm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznc54hv167i6r23teacm.png" alt="Receive your meal plan in the inbox" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how you can try out this app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send a WhatsApp message to number &lt;code&gt;+14155238886&lt;/code&gt; with code &lt;code&gt;family-main&lt;/code&gt;. This is Twilio's verified sandbox number.&lt;/li&gt;
&lt;li&gt;Send a meal plan request in this format: &lt;code&gt;Your meal plan &amp;lt;your email&amp;gt;&lt;/code&gt;. For example, this message has been tested successfully
&lt;code&gt;paleo vegan meal plan for 1 week &amp;lt;janedoe@gmail.com&amp;gt;&lt;/code&gt;
Make sure that your message includes the greater than and less than symbols, and your email address is enclosed between them. You can omit "paleo vegan", or change to "x days", where x is a number less than 7, because Edamam only allows a certain number of recipes in each request. I'm only allocated 30 requests per day, so please try the above message once so that many people can enjoy this service.&lt;/li&gt;
&lt;li&gt;You should get a success message. Wait for your meal plan to arrive in your inbox. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Twilio and AI
&lt;/h2&gt;

&lt;p&gt;Meal plan is complicated and time-consuming. Each person has a certain preferences and dietary need. Making a meal plan service that can please many different human beings is a near impossible task.&lt;/p&gt;

&lt;p&gt;You can look up online meal planning services and most of them will send the same plan to every one, unless you are prepared to pay a premium price.&lt;/p&gt;

&lt;p&gt;How about leverage AI to make meal plan more accessible? There's an API on the market that does just that: the &lt;a href="https://www.edamam.com/ai-chatbot-assistant/"&gt;chatbot assistant&lt;/a&gt; from Edamam.&lt;/p&gt;

&lt;p&gt;A diagram of the communication between WhatsApp user, this app and Edamam.&lt;/p&gt;

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

&lt;p&gt;You don't see the name Twilio in the diagram, because it is the silent magician that does all the plumbing work. It allows me to process WhatsApp messages, respond to WhatsApp users and send helpful emails to them (a really big deal in the age of spams and frauds).&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Twilio Times Two&lt;/em&gt;: I used two Twilio APIs, one for WhatsApp and the other for Sendgrid.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Impactful Innovators&lt;/em&gt;: I believe this online meal planning service will free people from that dreadful question comes every weeknight: What's for dinner?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Entertaining Endeavors&lt;/em&gt;: On the other hand, this meal planning service is not production ready yet. It may suggest that you have ice cream or rosemary oil for dinner. Besides, many food websites branch out into housekeeping. Occasionally, you may get recipes for furniture polish, or mulled-cider sachets. The Meal Planning API from Edamam is unable to tell if a recipe is safe for human consumption or not. While we wait for the Edamam API to mature, let's treat this app like something lighthearted to lighten up your Sunday blues.&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- Thanks for participating! →&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>twiliochallenge</category>
      <category>ai</category>
      <category>twilio</category>
    </item>
    <item>
      <title>Cache-Control, Netlify-CDN-Cache-Control, Cache Invalidation, Oh My</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 13 May 2024 05:44:43 +0000</pubDate>
      <link>https://dev.to/bytrangle/cache-control-netlify-cdn-cache-control-cache-invalidation-oh-my-56n2</link>
      <guid>https://dev.to/bytrangle/cache-control-netlify-cdn-cache-control-cache-invalidation-oh-my-56n2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/netlify"&gt;Netlify Dynamic Site Challenge&lt;/a&gt;: Clever Caching&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A website that demos how &lt;code&gt;cache-control&lt;/code&gt;, &lt;code&gt;Netlify-CDN-Cache-Control&lt;/code&gt; and cache tags play together.&lt;/p&gt;

&lt;p&gt;In my reading of caching, I realize that it's so confusing to the uninitiated for several seasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are many directives that come into affecting response caching. Changing one may change the response an end user will receive.&lt;/li&gt;
&lt;li&gt;The interplay between these directives are not clear.&lt;/li&gt;
&lt;li&gt;It's hard to demonstrate the effects of these directives. Browsers and CDNs work these cache directives opaquely, which is a good thing, but the downside is that developers may not put caching to the best use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://static-to-dynamic.netlify.app"&gt;Link to my Netlify app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bytrangle/netlify-caching"&gt;Link to the repo&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo &lt;code&gt;cache-control&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This demo is inspired by Imgur. After you land on the home page, you get a welcome message. If you refresh the page within 60 seconds, the message remains the same. If you refresh after the 60-second interval, you'll get a new message.&lt;br&gt;
This is possible by setting &lt;code&gt;max-age&lt;/code&gt; directive to 60 in the &lt;code&gt;Cache-Control&lt;/code&gt; field of the response header.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;max=age=60&lt;/code&gt; tells browser to cache the response for 60 seconds. After this time frame, the response is stale. For assurance, I also add &lt;code&gt;must-revalidate&lt;/code&gt; to &lt;code&gt;Cache-Control&lt;/code&gt; to tell browsers that once the cached response has become stale, it must not be used without revalidation.&lt;/p&gt;

&lt;p&gt;Here is the response of the request to &lt;a href="https://static-to-dynamic.netlify.app/cache-control"&gt;the cache control page&lt;/a&gt; at 12:56:52.&lt;/p&gt;

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

&lt;p&gt;The clock on the bottom right is 12:56:57 because my hand couldn't hit the "take screenshot" button fast enough!&lt;/p&gt;

&lt;p&gt;Response at 12:57:39.&lt;/p&gt;

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

&lt;p&gt;Notice that the clock on the bottom right is 12:57:39, but the response I received is the same as the last one. Browser was using a cached response!&lt;/p&gt;

&lt;p&gt;Response at 12:57:58.&lt;/p&gt;

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

&lt;p&gt;This is more than 60 seconds since the 12:56:52 timestamp. The response has changed!&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo for &lt;code&gt;Netlify-CDN-Cache-Control&lt;/code&gt; and cache invalidation
&lt;/h3&gt;

&lt;p&gt;For this demo, if you go to the &lt;a href="https://static-to-dynamic.netlify.app/cache-tags"&gt;cache-tags page&lt;/a&gt; then refresh repeatedly, you'll likely get the same response.&lt;/p&gt;

&lt;p&gt;I said "likely" because even though Netlify CDN was told to cache the response for 1 year, it was also instructed to always revalidate the response.&lt;/p&gt;

&lt;p&gt;If you can't wait for the TTL (time to live) to expire, you can click the Purge button to get directed to the home page, then click the &lt;code&gt;cache-tags&lt;/code&gt; page again to see the latest updated content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://streamable.com/yzglvk"&gt;Link to video of the demo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform Primitives
&lt;/h2&gt;

&lt;p&gt;I leverage the &lt;code&gt;Netlify-CDN-Cache-Control&lt;/code&gt; field in order to make Netlify CDN cache the response for up to a year. This is particularly useful on calling serverless functions that don't need to provide real-time updates.&lt;/p&gt;

&lt;p&gt;If you have many requests to a serverless functions within a short time, only the first request calls the function. For subsequent requests, the users get cached response and the function is not called unnecessarily.&lt;/p&gt;

&lt;p&gt;I also used &lt;code&gt;cache-tags&lt;/code&gt; to label the cached content for one of my page. The I use the &lt;code&gt;purge&lt;/code&gt; API to selectively purge by &lt;code&gt;cache-tags&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>netlifychallenge</category>
      <category>devchallenge</category>
      <category>webdev</category>
      <category>caching</category>
    </item>
    <item>
      <title>Manage issues with hundreds of comments</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 06 Dec 2021 11:00:22 +0000</pubDate>
      <link>https://dev.to/bytrangle/manage-issues-with-hundreds-of-comments-ai0</link>
      <guid>https://dev.to/bytrangle/manage-issues-with-hundreds-of-comments-ai0</guid>
      <description>&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;

&lt;p&gt;Issues are a wonderful way to see where your project needs to improve, but what do you do when an issue has more than &lt;strong&gt;20&lt;/strong&gt; comments? Or maybe &lt;strong&gt;a hundred&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;They are daunting to read for newcomers. Even if you are an active participant, it may be hard to remember what it is all about. Heaven forbid that you come back to this issue after a vacation.&lt;/p&gt;

&lt;p&gt;Do long-winded issues like that have overstayed their usefulness? What do you do with them?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split into smaller issues and close this humongous banter? But are you sure you are not missing any important points raised in the comments?&lt;/li&gt;
&lt;li&gt;Convert it into a discussion? But how does this make things more manageable?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This action will check for the most reacted comments in the issue and add them to the issue's original body with corresponding issues.&lt;/p&gt;

&lt;p&gt;You can specify the maximum number of reacted comments to display.&lt;/p&gt;

&lt;p&gt;Say goodbye to trawling through walls of text to get the gist of a issue. Happy coding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Maintainer Must-Haves&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml File or Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/bytrangle"&gt;
        bytrangle
      &lt;/a&gt; / &lt;a href="https://github.com/bytrangle/most-reacted-comments"&gt;
        most-reacted-comments
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Collection of Github workflows to make the lives of open-source maintainer easier
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h2&gt;
Get mosted reacted comments&lt;/h2&gt;
&lt;p&gt;A simple workflow to make long-winded issues more useful. It checks for the most reacted comments and add them to the issue's original body&lt;/p&gt;
&lt;h2&gt;
Screenshot&lt;/h2&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://raw.githubusercontent.com/bytrangle/most-reacted-comments/main/action-get-most-reacted-comments.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ec1s0OqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/bytrangle/most-reacted-comments/main/action-get-most-reacted-comments.gif" alt="screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
What does this action do&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It is triggered on comment creation or deletion&lt;/li&gt;
&lt;li&gt;Get the issue number that contains the comment in which the action is run&lt;/li&gt;
&lt;li&gt;Get a list of comments for the given issue&lt;/li&gt;
&lt;li&gt;If the number of comments for the issue is greater than a certain value, create a list that contains all comments that receive at least one reaction&lt;/li&gt;
&lt;li&gt;If list length is greater than 0, rank the comments by the number of reactions they receive, in descending order.&lt;/li&gt;
&lt;li&gt;Only take the X most reacted comments. This X value is defined by the action user.&lt;/li&gt;
&lt;li&gt;Insert these comments into the issue's body.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;An example workflow to use this action may look like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Display&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/bytrangle/most-reacted-comments"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;This action is looking forward to be used by thoughtful open-source projects. If you are a maintainer of such projects, what are you waiting for?&lt;/p&gt;

&lt;p&gt;[Note:] # (Be sure to link to any open source projects that are using your workflow!)&lt;/p&gt;

&lt;p&gt;[Reminder]: # (Submissions are due on December 8th, 2021 (11:59 PM PT or 2 AM ET/6 AM UTC on December 9th).&lt;/p&gt;

</description>
      <category>actionshackathon21</category>
    </item>
    <item>
      <title>How to configure Eslint in Gatsby projects</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 14 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/bytrangle/how-to-configure-eslint-in-gatsby-projects-55k</link>
      <guid>https://dev.to/bytrangle/how-to-configure-eslint-in-gatsby-projects-55k</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EHc7KP_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-L2SMm8vU-Kn-BgW.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EHc7KP_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A-L2SMm8vU-Kn-BgW.jpeg" alt="close-up-shot-of-fibre-strand"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other day, I was grinding away at my Gatsby project until I had a painful epiphany: “I don’t want strings to be wrapped inside double quotes”.&lt;/p&gt;

&lt;p&gt;The solution, of course, is to enable EsLint. Gatsby starters supports Eslint setup out of the box, so I thought it also covers my small requirement. After all, it always diligently notifies me when I have unused vars.&lt;/p&gt;

&lt;p&gt;But that’s not the case. There’s nothing in the EsLint config Gatsby ships with that dictates how string quotes should be handled.&lt;/p&gt;

&lt;p&gt;The good thing is there’s so much things you can configure and extend in Gatsby to suit your need. So here’s how to do it, step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where is the EsLint config file in Gatsby starters
&lt;/h3&gt;

&lt;p&gt;Gatsby starters make it so easy to get up and running quickly with a serviceable website without spending hours on tooling. However, the downside is I start to take things for granted and forget how set up EsLint for my own sake.&lt;/p&gt;

&lt;p&gt;There is no eslint file in Gatsby starters, but there is a barebone EsLint loader. While you are running Gatsby, open the terminal window and you should see feedbacks for code improvement from that loader.&lt;/p&gt;

&lt;p&gt;If you add a custom Eslint config file to your Gatsby project, settings from that file will override the built-in EsLint loader.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a custom EsLint config file
&lt;/h3&gt;

&lt;p&gt;At the root of your project directory, create a .eslintrc.js file. You can use JSON or YAML files, but I keep forgetting Eslint rules so I prefer the Javascript extension so that I can add comments explaining certain decisions.&lt;/p&gt;

&lt;p&gt;Add the following code snippet to extend what’s already in EsLint loader.&lt;/p&gt;

&lt;p&gt;module.exports = { globals: { __PATH_PREFIX__: true, }, extends: &lt;code&gt;react-app&lt;/code&gt;, }&lt;/p&gt;

&lt;h3&gt;
  
  
  Specify a custom EsLint parser
&lt;/h3&gt;

&lt;p&gt;Now, if you switch to the terminal window, you’ll see this warning:&lt;/p&gt;

&lt;p&gt;“Failed to load babel-eslint declared in .eslintc”&lt;/p&gt;

&lt;p&gt;That’s because Gatsby uses Babel under the hood for transpiling Javascript codes for older browsers. Then the EsLint loader specifies babel-eslint as the parser that allows EsLint to run on those transformed codes. But now our new EsLint config file has taken precedence over the built-in Eslint loader and it can’t load babel-eslint because we haven’t installed it.&lt;/p&gt;

&lt;p&gt;This means we need to install babel-eslint. However, when you visit the repo for this plugin, you’ll see a notification that it has been deprecated and moved to &lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/eslint.&lt;/p&gt;

&lt;p&gt;So install this new plugin.&lt;/p&gt;

&lt;p&gt;npm i -D &lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/eslint-parser&lt;/p&gt;

&lt;p&gt;In the EsLint config file, specify this plugin as the parser.&lt;/p&gt;

&lt;p&gt;module.exports = { // ... parser: "&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/eslint-parser" }&lt;/p&gt;

&lt;p&gt;Now, you get another problem: “No Babel config file detected for …/eslintrc.js. Either disable config file or configure Babel blah blah blah.”&lt;/p&gt;

&lt;p&gt;So, which way to go? Gatsby starters do have a Babel config file, but it has been abstracted away, and the EsLint config can’t find it.&lt;/p&gt;

&lt;p&gt;To fix this, modify the parseOptions key:&lt;/p&gt;

&lt;p&gt;module.exports = { // ... parser: "&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/eslint-parser", parserOptions: { requireConfigFile: false } }&lt;/p&gt;

&lt;h3&gt;
  
  
  Install support plugins
&lt;/h3&gt;

&lt;p&gt;Checking the terminal output again, you get yet another error:&lt;/p&gt;

&lt;p&gt;“Support for the experimental syntax ‘jsx’ isn’t currently enabled. Add &lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/preset-react to the ‘presets’ section of your Babel config to enable transformation.”&lt;/p&gt;

&lt;p&gt;Thankfully, the warning this time is helpful and you know what you need to install.&lt;/p&gt;

&lt;p&gt;npm i -D &lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/preset-react&lt;/p&gt;

&lt;p&gt;Finally, you can add any formatting rules you like to your EsLint config. Then run lint command, or simply let VsCode autoformat your codes on save and say goodbye to the grunt work.&lt;/p&gt;

</description>
      <category>eslint</category>
      <category>gatsby</category>
      <category>linting</category>
      <category>babel</category>
    </item>
    <item>
      <title>Four reasons to build a command line application</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Sun, 30 May 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/bytrangle/four-reasons-to-build-a-command-line-application-1bdb</link>
      <guid>https://dev.to/bytrangle/four-reasons-to-build-a-command-line-application-1bdb</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sd9PSkIj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AfU32WJkWoZ5EG59K.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sd9PSkIj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AfU32WJkWoZ5EG59K.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@_imkiran?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Sai Kiran Anagani&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/linux?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first time I see a course on Linkedin Learning about building a CLI app with Node.js, I thought: “What for”. I’m all for building and breaking things, but I don’t lack ideas for things I’d like to build. If an app is useful and has wide application, I will have more motivation to continue if the process gets hard.&lt;/p&gt;

&lt;p&gt;Meanwhile, a CLI app seems to be too niched for an earthling who only use the command line for version control like me.&lt;/p&gt;

&lt;p&gt;That’s what I believed in until I finished the course. Now, I can say that building a CLI app is a very rewarding activity and I can’t wait to make get my first pull request to a CLI app like Gatsby, or Netlify accepted.&lt;/p&gt;

&lt;p&gt;So here I am, helping you decide if it is really worth building a CLI app. But first, what is a CLI app?&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a command line application
&lt;/h3&gt;

&lt;p&gt;A command line application is an app that you invoke from the command line. This type of application also goes by the name CLI, short for Command Line Interface.&lt;/p&gt;

&lt;p&gt;But what is so special about CLIs?&lt;/p&gt;

&lt;p&gt;They are at the heart of Unix philosophy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Do one thing, and do it well.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reach of a CLI can be near or far. The command you run may just do its work directly on the computer, for example a web bundler like Webpack.&lt;/p&gt;

&lt;p&gt;Other CLIs may reach out to a remote repository like Git.&lt;/p&gt;

&lt;p&gt;The most interesting and useful CLIs from my experience is those that reach out to a third-party APIs or servers over the internet.&lt;/p&gt;

&lt;p&gt;Of course, a CLI may do some combinations of all three.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasons to build a CLI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A CLI app aids a developer’s productivity
&lt;/h4&gt;

&lt;p&gt;You may not realize it, but you’ve probably used a CLI app. There’s one for every facet of a developer workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git for version control&lt;/li&gt;
&lt;li&gt;Curl for making Http request. Okay, I don’t use this tool frequently, but many tutorials for API use them, and that’s how I got semi-proficient in using Curl.&lt;/li&gt;
&lt;li&gt;Webpack for bundling&lt;/li&gt;
&lt;li&gt;Gatsby or Jekyll for building static websites&lt;/li&gt;
&lt;li&gt;Surge or Netlify for deploying Html web pages&lt;/li&gt;
&lt;li&gt;Cloud providers like AWS, Azure provide CLIs for interacting with their infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there are CLIs for non-development like &lt;a href="https://github.com/sachaos/todoist"&gt;Todist CLI&lt;/a&gt;, of which I’m a big fan, &lt;a href="https://https://imagemagick.org/script/command-line-tools.php"&gt;Imagemagick&lt;/a&gt; for image manipulation in the command line (yep, that’s a thing) or &lt;a href="https://brew.sh"&gt;Homebrew&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All other things being equal, using a CLI is usually faster than a browser-based app.&lt;/p&gt;

&lt;p&gt;If there’s a routine task that you perform every day, it’s time to check if there’s already a solution that makes it faster and repeatable. You will find that a lot of those solutions come in the form of a CLI.&lt;/p&gt;

&lt;h4&gt;
  
  
  A CLI can be used to integrate two systems together
&lt;/h4&gt;

&lt;p&gt;For example, you may want to post errors from your build server to a messaging platform like Slack. Having a command to post messages to your chat program would be a great way to integrate those systems together.&lt;/p&gt;

&lt;h4&gt;
  
  
  You may be making the next big thing
&lt;/h4&gt;

&lt;p&gt;Who knows, possibilities expand when you get down and build things. You will start to see ideas, opportunities for improvement that you can’t see just by reading and watching. Building even the most simple, basic CLI will equip you to turn those opportunities into realities.&lt;/p&gt;

&lt;h4&gt;
  
  
  Improve a programming language
&lt;/h4&gt;

&lt;p&gt;I don’t know why I get this idea, but I used to think that a CLI is synonymous with a desktop app, and it can only be built with a platform-specific language like Swift for MacOs or C++ for Windows.&lt;/p&gt;

&lt;p&gt;That’s not true. A CLi can be built with Node.js, Ruby, Python, Rust and so many other languages.&lt;/p&gt;

&lt;p&gt;You write your program in any of those languages, then turn it into an executable command that can be run from anywhere in the filesystem. How you do that is dependent on the language, but from my experience it’s the easiest part of building a CLI.&lt;/p&gt;

&lt;p&gt;This means all that is left to you is to go build a CLI now.&lt;/p&gt;

&lt;p&gt;If you don't have any idea, how about a tool that lets you post to &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt;, &lt;a href="https://medium.com"&gt;Medium&lt;/a&gt; or any of your favorite blogging platforms from the comfort of the command line, without ever opening the browser? Context switching for the win.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://bytrangle.surge.sh/insight/why-build-command-line-application/"&gt;&lt;em&gt;https://bytrangle.surge.sh&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on May 30, 2021.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>commandline</category>
      <category>cli</category>
      <category>desktopapp</category>
    </item>
    <item>
      <title>A vanilla Javascript game will help you do the bare minimum to stay fit</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 11 Jan 2021 04:26:21 +0000</pubDate>
      <link>https://dev.to/bytrangle/this-game-will-help-you-do-the-bare-minimum-to-stay-fit-45li</link>
      <guid>https://dev.to/bytrangle/this-game-will-help-you-do-the-bare-minimum-to-stay-fit-45li</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;A roulette game to help others do the bare minimum to stay (mildly) fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Program for the people&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://spinwheel-77agt.ondigitalocean.app/"&gt;https://spinwheel-77agt.ondigitalocean.app/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;When it comes to games, a video is worth a thousand screenshots. Here's a Vimeo video of the whole game experience.&lt;br&gt;
&lt;iframe src="https://player.vimeo.com/video/499069590" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p4SA0Wq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uwq54231bks5f336aj8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p4SA0Wq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uwq54231bks5f336aj8p.png" alt="Landing page"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HM4JHr_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u1q1a5c1slp2lihkoiwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HM4JHr_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u1q1a5c1slp2lihkoiwr.png" alt="After spinning"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M5FfDjko--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1znqdd6yepmhccy7easu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M5FfDjko--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1znqdd6yepmhccy7easu.png" alt="Timer is running"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Getting started is always the hardest part of cultivating a new habit. We could all use a bit of help with gamification. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;: Spin the roulette, and whatever exercise you get, just hit the &lt;em&gt;Start timer&lt;/em&gt; button. A timer will run for 45 seconds. Do the exercise for that amount of time.&lt;/p&gt;

&lt;p&gt;When the timer is up, click the &lt;em&gt;Spin again&lt;/em&gt; to do another exercise. Repeat as many time as you like. If you get burpees seven times in a row, do it anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/bytrangle/spinwheel"&gt;The project's Github&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/bytrangle/spinwheel/blob/main/LICENSE.txt"&gt;MIT License&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I'm inspired to make this roulette game after watching this &lt;a href="https://www.youtube.com/watch?v=hAxmqgAzxLw"&gt;video&lt;/a&gt; by fitness guru Casey Ho. It's an interesting, creative take on the same old workout routine.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;I've heard a lot of great things about Digital Ocean in general and I always enjoy its community posts, but this hackathon is the first time that I tried its app-deployment platform. The user onboarding is excellent and everything was a breeze.&lt;/p&gt;

&lt;p&gt;The list of new things and lessons I've learned during the making of this game is too many to name, but the most notable ones are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drawing with CSS, namely creating gradient, highlight, triangle shapes etc. To be honest, next time, I would have used SVG to speed up the drawing process.
(How did you utilize DigitalOcean’s App Platform? Did you learn something new along the way? Pick up a new skill?)&lt;/li&gt;
&lt;li&gt;CSS animation for displaying the exercise name, and running the timer. Yes, the timer animation was done entirely with CSS.&lt;/li&gt;
&lt;li&gt;How to reset animation. The animation property on the timer only runs once. I need to figure out a way to trigger it again when users click &lt;em&gt;Start timer&lt;/em&gt; for the umpteenth time.&lt;/li&gt;
&lt;li&gt;How to make flip card effect on button click.&lt;/li&gt;
&lt;li&gt;How to use custom data attribute to store the rotation degree for the roulette.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;There's one aspect that was much more time-consuming than I thought: How to maintain a consistent design. This is such a one-page app, but I spent so much time on choosing color, font size, font weight to convey hierarchy.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://refactoringui.com/book/"&gt;Refactoring UI book&lt;/a&gt; by Adam Wathan and Steve Schoger was of immense help to me.&lt;br&gt;
Here's another &lt;a href="https://www.youtube.com/watch?v=R_Plqh8j_Kg"&gt;Cassey Ho's video&lt;/a&gt; using the same spin wheel. Give it a try.&lt;/p&gt;

</description>
      <category>dohackathon</category>
      <category>javascript</category>
      <category>animation</category>
      <category>css</category>
    </item>
    <item>
      <title>In Search of a Competent Markdown Editor</title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Mon, 09 Sep 2019 07:40:54 +0000</pubDate>
      <link>https://dev.to/bytrangle/in-search-of-a-competent-markdown-editor-49eg</link>
      <guid>https://dev.to/bytrangle/in-search-of-a-competent-markdown-editor-49eg</guid>
      <description>

&lt;p&gt;Have you ever dreamed of writing more content in less time? One of the solutions is a Markdown editor. Let’s find the perfect one for you.&lt;/p&gt;

&lt;p&gt;I used to think that we all take notes the same way. Wrong. It wasn’t until I looked for a Markdown editor that I realized this truth: Everyone is very opinionated about what a note taking app should look like.&lt;/p&gt;

&lt;p&gt;In my case, I want a note taking app with Markdown support. Or a Markdown editor that allows me to take a variety of notes, not just programming ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh Markdown editor, where art thou?
&lt;/h2&gt;

&lt;p&gt;During my daunting search, I realized that I wasn’t specific enough. The clearer I get with my criteria, the less time it takes for me to find the right beau. I found myself asking a lot of questions that I hadn’t thought of:&lt;/p&gt;

&lt;p&gt;Do I want a WYSIWYG, or a no-nonsense Markdown editor? Simple tool is usually not versatile and customizable.&lt;/p&gt;

&lt;p&gt;Do I need cross platform?&lt;/p&gt;

&lt;p&gt;Can I dictate where my notes are stored?&lt;/p&gt;

&lt;p&gt;How much money am I willing to drop for Markdown app?&lt;/p&gt;

&lt;p&gt;What bells and whistles do I need in addition to the standard Markdown support? If all I do is writing codes and documentation, a simple app like &lt;a href="https://macdown.uranusjr.com/"&gt;Macdown&lt;/a&gt; would suffice.&lt;/p&gt;

&lt;p&gt;However, I also take a copious amount of study notes, and write online content fairly frequently. At the minimum, I need a nice option for file attachment.&lt;/p&gt;

&lt;p&gt;How important does UI rendering play in my decision? I thought I was easy going about UI, until I used SimpleNote.&lt;/p&gt;

&lt;p&gt;The list goes one and on, but below is my pick, in case you are scratching your head about what Markdown editor to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notion — Top well-rounded Markdown editor
&lt;/h3&gt;

&lt;p&gt;Okay, I know what you’re going to say. &lt;a href="http://notion.so/"&gt;Notion&lt;/a&gt; is pseudo Markdown editor. Indeed, if you google “markdown editor”, the name Notion will never come up.That’s because it can do many things: note taking, project management, life planning, big-picture review etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2EvHukX3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2At7GEgZpZndmLFbTQPzE-PQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2EvHukX3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2At7GEgZpZndmLFbTQPzE-PQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what really tipped the scale towards Notion is that its Markdown support is superb. Don’t be fooled by its WYSIWYG interface. You can write all your content without ever leaving the keyboard.&lt;/p&gt;

&lt;p&gt;I know many people use Notion to write their content and then publish them to their platform of choice. Actually, had it not been for them, I wouldn’t have thought of Notion as a Markdown editor. I’ve always found it overkill for my purpose.&lt;/p&gt;

&lt;p&gt;If you want an app to replace them all, Notion comes very close. I rearely come across an app that performs so consistently across all platforms: web, desktop, iOS, Android.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boostnote — Best free Markdown editor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--igg8OjIi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A2cn_YQ26TXtGAme4Pg9eUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--igg8OjIi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A2cn_YQ26TXtGAme4Pg9eUA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are plenty of free Markdown editors on the market, but why do I pick &lt;a href="https://boostnote.io/"&gt;Boostnote&lt;/a&gt;? Here are four reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is built especially for developers, so you are spoilt for choice with dozens of syntax highlighting themes.&lt;/li&gt;
&lt;li&gt;It has a local storage, and what’s even cooler is that I can specify the path directory. I’m weary of note taking apps that store my notes in some obscure servers, or in the treacherous Library folder on Mac.&lt;/li&gt;
&lt;li&gt;It is more than a basic Markdown editor. I’m also using Boostnote for writing my online content, and I’m very happy with it.&lt;/li&gt;
&lt;li&gt;It supports global search. I used to think that multi-level folders is a must have for a note-taking app, but not anymore. If an app features a good search engine like Boostnote, you can save yourself a lot of time in finding the exact information you want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That being said, &lt;a href="https://boostnote.io/"&gt;Boostnote&lt;/a&gt; is an open-source app and its UX is not clear. Besides, you would have to use third-party serivices like Dropbox for syncing. But Typora doesn't offer syncing either, so Boostnote makers have nothing to feel ashamed about.&lt;/p&gt;

&lt;p&gt;For now, I’m grateful that I can get so much out of a free app, thanks to a group of generous developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typora — Best WYSIWYG Markdown editor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://typora.io/"&gt;Typora&lt;/a&gt; is a minimal, distraction-free Macdown editor. If you are a writer, journalist, student etc, I have no doubt that you would love Typora.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--THEfpQQW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1010/1%2AljifcDHU1qlns9l28C6XuQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--THEfpQQW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1010/1%2AljifcDHU1qlns9l28C6XuQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You write Markdown as usual, and when you leave the current line, Typora renders your input. There is nothing I dislike about Typora, but I hesitate to commit to it, knowing that it is still a beta and there is no word on the future pricing model.&lt;/p&gt;

&lt;p&gt;After spending hours exploring and testing markdown editors, I’m reminded of this age-old wisdom:&lt;/p&gt;

&lt;h2&gt;
  
  
  Better the devil you know.
&lt;/h2&gt;

&lt;p&gt;That’s what I realized after spending a not-so-small amount of unproductive time on researching, exploring, and testing Markdown editors. And that’s not all. &lt;/p&gt;

&lt;p&gt;If you want to get the most out of an app, you need to spend time learning its shortcuts and configuring it to your liking, so that it becomes automatic. &lt;/p&gt;

&lt;p&gt;So, what is your favorite Markdown editor? I won’t get sidetracked by another shiny app, but I love to hear your thoughts.&lt;/p&gt;

</description>
      <category>contentwriting</category>
      <category>markdown</category>
      <category>notetaking</category>
      <category>noteapp</category>
    </item>
    <item>
      <title>What language/framework do I need to learn to build user registration? </title>
      <dc:creator>Trang Le</dc:creator>
      <pubDate>Fri, 30 Aug 2019 14:32:55 +0000</pubDate>
      <link>https://dev.to/bytrangle/what-language-framework-do-i-need-to-learn-to-build-user-registration-522a</link>
      <guid>https://dev.to/bytrangle/what-language-framework-do-i-need-to-learn-to-build-user-registration-522a</guid>
      <description>&lt;p&gt;Hi all. Please pardon my stupid question, but I'm still learning front end, so everything about the back end is mystifying to me. &lt;/p&gt;

&lt;p&gt;I've built an app for learning purpose, but it's just occurred to me that &lt;strong&gt;one day&lt;/strong&gt; I'd like to integrate user registration and authentication into it. So what language/framework/platform do I need to learn? Laravel, Mongdb, asp.net, AWS or anything else? &lt;/p&gt;

&lt;p&gt;I don't mind anything, but it's be a plus if it can integrate well with React or Vue, since it is what I'm more familiar with.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>backend</category>
      <category>firebase</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
