<?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: Rita</title>
    <description>The latest articles on DEV Community by Rita (@rita).</description>
    <link>https://dev.to/rita</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%2F601080%2Fe03277f2-10de-4cd4-94b7-18b85398a6fc.jpg</url>
      <title>DEV Community: Rita</title>
      <link>https://dev.to/rita</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rita"/>
    <language>en</language>
    <item>
      <title>MCPs everywhere, wth is that?</title>
      <dc:creator>Rita</dc:creator>
      <pubDate>Tue, 14 Apr 2026 17:43:38 +0000</pubDate>
      <link>https://dev.to/rita/mcps-everywhere-wth-is-that-41e0</link>
      <guid>https://dev.to/rita/mcps-everywhere-wth-is-that-41e0</guid>
      <description>&lt;p&gt;I got tasked with connecting Figma to our UI Kit via MCP&lt;/p&gt;

&lt;p&gt;Starting with just documentation, it looks super simple, even LLM like Claude can do that for me and suddenly I can tell it to read a Figma file and create some code from it. Just a magic black box doing something cool for me.&lt;/p&gt;

&lt;p&gt;I don't like black boxes, so let's do a little bit of unboxing. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is an MCP in general?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; is an open-source standard for connecting AI applications to external systems. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So basically it's some kind of protocol to tell LLM &lt;em&gt;how&lt;/em&gt; to do stuff with external application. &lt;/p&gt;

&lt;p&gt;For example, as for my task, it's Figma MCP. I can tell Claude to look at the component, and it can run something like "make a screenshot" call. Then Figma will do an actual screenshot and turn it back to Claude which then can process it however it likes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does the protocol look?
&lt;/h2&gt;

&lt;p&gt;I like to break things down to be a little bit like real world (or not so real) examples. So let's imagine two towers.&lt;/p&gt;

&lt;p&gt;First tower is where queen lives, and her main focus these days is to figure out how to overcome a disease which is torturing her little kingdom.&lt;/p&gt;

&lt;p&gt;Second tower is where magician lives, he explores a library of endless books to find a proper solution and make everyone healthy. The key problem here is that both of them are stuck in their towers, because if they come outside they inevitably become sick, so their only way to cooperate is to send carrier pigeons.&lt;/p&gt;

&lt;p&gt;It's a &lt;a href="https://modelcontextprotocol.io/docs/learn/architecture" rel="noopener noreferrer"&gt;MCP Architecture&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queen&lt;/strong&gt;: MCP Client + LLM, like a Claude Code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Magician&lt;/strong&gt;: MCP Server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Library&lt;/strong&gt;: some source of data, like a Figma mock or whatever else&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pigeons&lt;/strong&gt;: exchange protocol, which in the case of MCP standard is JSON RPC.&lt;/li&gt;
&lt;/ul&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%2Finbunjeokhd8co1ncg39.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%2Finbunjeokhd8co1ncg39.png" alt="MCP" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Story begins
&lt;/h3&gt;

&lt;p&gt;This is actually a flow from the docs, I didn't make it up, see &lt;a href="https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle" rel="noopener noreferrer"&gt;MCP Lifecycle&lt;/a&gt;. Also here is a &lt;a href="https://modelcontextprotocol.io/specification/2025-11-25/server/tools#message-flow" rel="noopener noreferrer"&gt;Message Flow Diagram&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Alright, so they just figured that there's a disease and need to start sending pigeons.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Initialization
&lt;/h4&gt;

&lt;p&gt;First thing Queen does is to try to send a first one, just to see that they are coming through the wind and are capable to overcome the path as well as let the Magician know that she's reaching out and going to continue to do so over the pigeons.&lt;/p&gt;

&lt;p&gt;Or, as magician would call it "Capability Negotiation Handshake Spell".&lt;/p&gt;

&lt;p&gt;Alright, that worked out, pigeon came to the Magician and he writes back like "Hey Queen, I got you, nothing changed since last time we have spoken, lmk how can I help?".&lt;/p&gt;

&lt;p&gt;Queen also got the message, and just because she is very very very nervous and wants this to work out the best for the kingdom, writes back: "Cool, now we can use this as our communication channel".&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%2F4ohk6m53ge80jbuaciq3.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%2F4ohk6m53ge80jbuaciq3.png" alt="MCP" width="800" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stepping back out of the story a bit, other than initialization, there's also an ability to send Notifications back and forth. For example, if Server has something new and wants to notify a Client, it can send a Notification. More about that &lt;a href="https://modelcontextprotocol.io/docs/learn/architecture#why-notifications-matter" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Tool Discovery
&lt;/h4&gt;

&lt;p&gt;Next, the Queen wants to know what Magician can do to help. She sends a pigeon to ask: "What can you do to save all my people? Any spells, potions, books?". That's a &lt;code&gt;tools/list&lt;/code&gt; request.&lt;/p&gt;

&lt;p&gt;Magician responds: "IDK anything about the symptoms, so as for now I can only try to find it in the books, hence: can search and read".&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Communication
&lt;/h4&gt;

&lt;p&gt;Queen now knows what Magician is capable of and they start to send pigeons back and forth. She tells him the symptoms, asks to find them in the books, he is researching and reading books to figure it all out.&lt;/p&gt;

&lt;p&gt;Eventually after multiple messages, they do find the cure and everyone is happy.&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%2Fld5gy3898fpl0n9kchcg.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%2Fld5gy3898fpl0n9kchcg.png" alt="MCP" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That was a very simplified version of how MCP works as a protocol.&lt;/p&gt;

&lt;p&gt;There are also other things that can be fetched, the full list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt;: Pre-defined templates or instructions that guide language model interactions (or kind of example messages that Queen can write)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt;: Structured data or content that provides additional context to the model (or books content that Magician can send)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Executable functions that allow models to perform actions or retrieve information (Actionables: as Magician can read and search for special books)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Digging a real world MCP
&lt;/h2&gt;

&lt;p&gt;So that's the story version, now let's see what this actually looks like in practice.&lt;/p&gt;

&lt;p&gt;As I mentioned before, my task was to integrate Figma MCP into the development flow. Let's look at what it sends back.&lt;/p&gt;

&lt;p&gt;I will use &lt;a href="https://github.com/modelcontextprotocol/inspector" rel="noopener noreferrer"&gt;MCP Inspector&lt;/a&gt; for it.&lt;/p&gt;

&lt;p&gt;Super easy to install and launch with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @modelcontextprotocol/inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks pretty easy to understand and going through tabs all the requests can be run and in the bottom there's a history of what was sent and what came back.&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%2Fk6h3o8ykf33moq32skw5.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%2Fk6h3o8ykf33moq32skw5.png" alt="MCP" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools
&lt;/h3&gt;

&lt;p&gt;There's a bunch of things to play around with, but for this exact MCP, the most useful is the tools part.&lt;/p&gt;

&lt;p&gt;When clicking on the tools list, several tools can be seen, such as get screenshot, get context of a selection, get some additional data.&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%2Fq26j4dl93xnai73rgsnn.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%2Fq26j4dl93xnai73rgsnn.png" alt="MCP" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think if I had edit rights in this file, I'd also get some editing tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/live/R9mBpeiCMM0?si=mFTagS8b1viHumvL" rel="noopener noreferrer"&gt;Video &lt;br&gt;
Figma x Claude Code Live: Roundtrip workflows with Figma MCP&lt;/a&gt; explains what can be done very well. I was surprised that coders are not the only ones to benefit from this tool. Designers can be as powerful while using LLM to edit stuff. Worth watching.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tool call response (I got a prompt back?!)
&lt;/h3&gt;

&lt;p&gt;After running a &lt;code&gt;get_design_context&lt;/code&gt; tool over a little nav button, something curious happened. I got an array of strings.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Layout JSX
&lt;/h4&gt;

&lt;p&gt;First of all, how interesting is that, that the answer for the tool is JSX markup with Tailwind as a styling choice. I haven't sent anything indicating React stack, so that must be defaults.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgShape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3845/assets/1c9afae144c1f480a7116bc13f7dd58532373935.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;NavigationIconsMenu&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"relative size-full"&lt;/span&gt; &lt;span class="na"&gt;data-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"navigation icons/menu 3"&lt;/span&gt; &lt;span class="na"&gt;data-node-id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"I670:158196;876:3599"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"absolute h-[12px] left-[2px] top-[6px] w-[20px]"&lt;/span&gt; &lt;span class="na"&gt;data-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Shape"&lt;/span&gt; &lt;span class="na"&gt;data-node-id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"I670:158196;876:3599;3262:830"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"absolute block inset-0 max-w-none size-full"&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;imgShape&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does it mean that Figma MCP works the best for React + Tailwind stack? Probably. Though my project is not using Tailwind, nor React, I do understand it's the most popular stack right now. &lt;/p&gt;

&lt;h4&gt;
  
  
  2, 3, 4. Prompts
&lt;/h4&gt;

&lt;p&gt;I was surprised.&lt;/p&gt;

&lt;p&gt;My initial thought was that Figma would return me just a raw JSON with data about the components. Ok, JSX. But prompts?&lt;/p&gt;

&lt;p&gt;Let's look closer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUPER CRITICAL: The generated React+Tailwind code MUST be converted to match the target project's technology stack and styling system.
1. Analyze the target codebase to identify: technology stack, styling approach, component patterns, and design tokens
2. Convert React syntax to the target framework/library
3. Transform all Tailwind classes to the target styling system while preserving exact visual design
4. Follow the project's existing patterns and conventions
DO NOT install any Tailwind as a dependency unless the user instructs you to do so.

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node ids have been added to the code as data attributes, e.g. `data-node-id="1:2"`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;stored&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;localhost&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Clients&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;these&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="nx"&gt;directly&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;way&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;same&lt;/span&gt; &lt;span class="nx"&gt;way&lt;/span&gt; &lt;span class="nx"&gt;they&lt;/span&gt; &lt;span class="nx"&gt;would&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt; &lt;span class="nx"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Images&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;SVGs&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;stored&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3845/assets/10c13ac1a228a365cb98a0064b1d5afbc84887b2.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;These&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; This is true for both images and SVGs, so you can use the same approach for both types of assets&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IMPORTANT: After you call this tool, you MUST call get_screenshot to get a screenshot of the node for context.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was a pretty big insight for me. So tools here are not just a convenient way to run some requests to some resources and work on the response, they can actually give back more instructions.&lt;/p&gt;

&lt;p&gt;What if that were an instruction to push my company's repo to some other origin, or steal my personal data?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP responses can be treated as commands to LLM and they are prone to prompt injection.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;That was a quick investigation of MCPs, to demystify a black box.&lt;/p&gt;

&lt;p&gt;It's a pretty simple protocol of establishing a connection between a client and a server, which allows exchanging data and running certain server actions.&lt;/p&gt;

&lt;p&gt;Super cool that we can have LLMs run them automatically and enhance productivity. &lt;/p&gt;

&lt;p&gt;Though it comes with a price, if the MCP is not from some trusted source, I'd suggest to never run it. Do it in a sandbox env if you really need to.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>mcp</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>How to keep an element fixed at the bottom, even when the keyboard is open</title>
      <dc:creator>Rita</dc:creator>
      <pubDate>Fri, 09 Aug 2024 23:28:12 +0000</pubDate>
      <link>https://dev.to/rita/how-to-keep-an-element-fixed-at-the-bottom-even-when-the-keyboard-is-open-n0m</link>
      <guid>https://dev.to/rita/how-to-keep-an-element-fixed-at-the-bottom-even-when-the-keyboard-is-open-n0m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Hey devs! I discovered this while working on my note-taking app. &lt;br&gt;
&lt;a href="https://jotnoted.com/public/159" rel="noopener noreferrer"&gt;Here's a post using my app.&lt;/a&gt; &lt;br&gt;
&lt;a href="https://x.com/rita_romen" rel="noopener noreferrer"&gt;Sharing the progress on X (Twitter)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Have you ever been surprised that CSS isn't working the way you expected? &lt;br&gt;
That happened to me (again) when I set an element to be fixed at the bottom and then opened the keyboard on my iPhone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"fixed bottom-0"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I've seen is that element is not visible at all. &lt;br&gt;
Because it's fixed. To the bottom. Behind the keyboard.&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%2Fjotnoted.imgix.net%2Fimages%2Fd19c6759-e4aa-4910-9f5c-d70b17ce0278.webp" 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%2Fjotnoted.imgix.net%2Fimages%2Fd19c6759-e4aa-4910-9f5c-d70b17ce0278.webp" alt="Crying in CSS" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seems like to fix the &lt;code&gt;fixed&lt;/code&gt; we need some JS.&lt;/p&gt;
&lt;h2&gt;
  
  
  VisualViewport
&lt;/h2&gt;

&lt;p&gt;There's a browser API with good support that can be used for these purposes: &lt;code&gt;VisualViewport&lt;/code&gt;. &lt;br&gt;
It returns the width and height of the actual visible viewport. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport" rel="noopener noreferrer"&gt;MDN link to docs.&lt;/a&gt; &lt;br&gt;
However, do your own investigation to see if it's supported for the versions you're targeting.&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%2Fpnknjbh97d175p1pssek.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%2Fpnknjbh97d175p1pssek.png" alt="Sketch" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Math
&lt;/h2&gt;

&lt;p&gt;Basically, we need to handle the position of the element with respect to the visual viewport, as well as the scroll position and the element's height. Let's do the math.&lt;/p&gt;

&lt;p&gt;Also, since the math is much simpler this way, it makes sense to use the top parameter instead of the bottom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;top = viewport height + scroll - element height
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;I'll use React. For any other framework, you can just copy the content of the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;classNames&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classnames&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useDebounce&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use-debounce&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// elem. height in pixels&lt;/span&gt;
&lt;span class="c1"&gt;// It's also a good idea to calculate it dynamically via ref&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FixedBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// top postion -&amp;gt; the most important math result goes here&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// viewport height&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewportHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visualViewport&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// math&lt;/span&gt;
      &lt;span class="nf"&gt;setTop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;viewportHeight&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;elementHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// run first time to initialize &lt;/span&gt;
    &lt;span class="nf"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// subscribe to events which affect scroll, or viewport position&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visualViewport&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visualViewport&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;touchmove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// unsubscribe&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visualViewport&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visualViewport&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;touchmove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resizeHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;debouncedScroll&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;classNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute left-0 top-0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- attention, it's absolute&lt;/span&gt;
          &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;    &lt;span class="c1"&gt;// while calculating, we don't need to show it &lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`translateY(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;debouncedTop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        I am fixed
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final results
&lt;/h3&gt;

&lt;p&gt;I also needed to add some animations and hide my block on scroll, but you don't have to do that, and it will always be visible.&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%2Fg0j2y77jl2k9o92cv8c8.jpg" 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%2Fg0j2y77jl2k9o92cv8c8.jpg" alt=" " width="590" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>css</category>
      <category>react</category>
    </item>
    <item>
      <title>Yesterday, I released something on Hacker News for the first time ever. Lesson learned.</title>
      <dc:creator>Rita</dc:creator>
      <pubDate>Wed, 07 Aug 2024 08:37:18 +0000</pubDate>
      <link>https://dev.to/rita/yesterday-i-released-something-on-hacker-news-for-the-first-time-ever-5487</link>
      <guid>https://dev.to/rita/yesterday-i-released-something-on-hacker-news-for-the-first-time-ever-5487</guid>
      <description>&lt;p&gt;I've been working on my note-taking app with Excalidraw sketches for the past two weeks. I set a boundary for myself: I had only two weeks to work on it, then I had to stop and release it somewhere, even though I didn't know where. I had no plans to make a ton of money; I just wanted to have a project like this for myself and to get a feel for how solopreneurship works.&lt;/p&gt;

&lt;p&gt;First, huge kudos to Marc Lou for his post: &lt;a href="https://marclou.beehiiv.com/p/how-to-launch-a-startup-on-hacker-news" rel="noopener noreferrer"&gt;How to launch a startup on Hacker News&lt;/a&gt;. I didn't even know that I should name my post in a specific way. To launch there, you need to start the title of the post with &lt;code&gt;Show HN&lt;/code&gt;. It also seems like HN users prefer short, straight-to-the-point titles.&lt;/p&gt;

&lt;p&gt;One insight I gained is that &lt;em&gt;people are not very happy about sharing their emails or going through a sign-up process&lt;/em&gt;. This wasn't obvious to me until I saw a video review from one user who basically said, "sorry, but no" after seeing the login screen. Lesson learned: I'll create demo pages for all my future projects.&lt;/p&gt;

&lt;p&gt;What lessons have you learned from launching your side projects?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=41175702" rel="noopener noreferrer"&gt;Link to the launch post, if you're curious&lt;/a&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I'm developing a minimalistic note-taking web app with custom widgets. Can you suggest any widgets you would like to see?</title>
      <dc:creator>Rita</dc:creator>
      <pubDate>Sat, 03 Aug 2024 19:47:41 +0000</pubDate>
      <link>https://dev.to/rita/im-developing-a-minimalistic-note-taking-web-app-with-custom-widgets-can-you-suggest-any-widgets-you-would-like-to-see-5764</link>
      <guid>https://dev.to/rita/im-developing-a-minimalistic-note-taking-web-app-with-custom-widgets-can-you-suggest-any-widgets-you-would-like-to-see-5764</guid>
      <description>&lt;p&gt;Hi everyone! I'm currently working on a note-taking app. The idea is to add the ability to insert cool, useful widgets directly into the notes. I've already added a must-have feature for me: drawing with Excalidraw.&lt;/p&gt;

&lt;p&gt;Another feature I'm considering is a habit tracker in a GitHub history-like style.&lt;/p&gt;

&lt;p&gt;Is there anything you would love to see in the app that would make you consider using it?&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%2Fgoiuv0ijachw8c7wnbkp.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%2Fgoiuv0ijachw8c7wnbkp.png" alt="Example of the note" width="800" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>productivity</category>
      <category>startup</category>
    </item>
    <item>
      <title>Share code between React Native and React Web</title>
      <dc:creator>Rita</dc:creator>
      <pubDate>Wed, 14 Dec 2022 22:55:16 +0000</pubDate>
      <link>https://dev.to/rita/share-code-between-react-native-and-react-web-1343</link>
      <guid>https://dev.to/rita/share-code-between-react-native-and-react-web-1343</guid>
      <description>&lt;p&gt;This article explains a coexisting of react native and react web apps with similar to monorepo workspaces behavior, but without sharing &lt;code&gt;node_modules&lt;/code&gt; dependencies. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All web workspaces remain workspaces, mobile just &lt;em&gt;acts&lt;/em&gt; like workspace.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've had an existing huge web monorepo. &lt;a href="https://classic.yarnpkg.com/blog/2018/02/15/nohoist/" rel="noopener noreferrer"&gt;Yarn's &lt;code&gt;nohoist&lt;/code&gt; setup&lt;/a&gt;, or editing metro configuration wasn't working for me because this monorepo contains a lot of dependencies incompatible with react native. &lt;strong&gt;But it might work for you&lt;/strong&gt; and might be a better solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You need to update metro config to handle sources outside of react native project.&lt;/li&gt;
&lt;li&gt;Setup mobile project's babel config with aliases to shared folders.&lt;/li&gt;
&lt;li&gt;Enjoy the magic ✨&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/romenkova/react-native-monorepo-example" rel="noopener noreferrer"&gt;Minimal working example [repo]&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This article expects that you know how to create yarn workspaces monorepo. If not, please, &lt;a href="https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/" rel="noopener noreferrer"&gt;read docs here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, I have &lt;a href="https://github.com/romenkova/react-native-monorepo-example" rel="noopener noreferrer"&gt;example repo&lt;/a&gt; with mobile and web sharing some code.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;1. Create folder which needs to be shared
&lt;/h2&gt;

&lt;p&gt;Let's say, we have our workspaces in the folder &lt;code&gt;projects&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── projects
│   ├── web
│   └── ...  (means here can be lots of files)
├── package.json
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a new workspace, which will contain shared files for both mobile and web.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  ├── projects
&lt;span class="gi"&gt;+ |   ├── shared
+ |   |   ├── src
+ |   |   ├── index.js
+ |   |   └── package.json
&lt;/span&gt;  │   ├── web
  │   └── ...
  ├── package.json
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shared"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sayHello&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/sayHello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// src/sayHello.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;2. Add &lt;code&gt;shared&lt;/code&gt; to other workspaces
&lt;/h2&gt;

&lt;p&gt;Now we need to add our shared folder into &lt;code&gt;package.json&lt;/code&gt; files of other workspaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;web/package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  "name": "web",
  "scripts": {
    ...
  },
  "dependencies": {
&lt;span class="gi"&gt;+   "shared": "*" 
&lt;/span&gt;    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and same of all other workspaces, where we want to use &lt;code&gt;shared&lt;/code&gt;.&lt;br&gt;
Then, to let yarn know what we did, run &lt;code&gt;yarn install&lt;/code&gt; or just &lt;code&gt;yarn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// projects/web/src/somefile.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sayHello&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;3. Create react native application
&lt;/h2&gt;

&lt;p&gt;React Native setup guide does a better job at explaining how to set up a new mobile app, or maybe you have your existing one. I'll skip this part, if you're not sure how to do this, &lt;a href="https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer"&gt;docs are here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You need to create a mobile app inside &lt;code&gt;projects&lt;/code&gt; folder like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  └── projects
      ├── shared
      |   ├── src
      |   ├── index.ts
      |   └── package.json
      ├── web
&lt;span class="gi"&gt;+     └── mobile
+         |   ├── src
+         |   ...
+         ├── metro.config.js
+         ├── babel.config.js
+         └── package.json
&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And now the most important part&lt;/strong&gt;.&lt;br&gt;
We need to tell the metro where to find source files. If we don't do that, it'll only look inside the &lt;code&gt;mobile&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// store path to workspace root, in our case, one level above /projects&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workspaceRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;getTransformOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;experimentalImportSupport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;inlineRequires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="c1"&gt;// watch not only our mobile folder, but also root's folders&lt;/span&gt;
  &lt;span class="c1"&gt;// this will include @common&lt;/span&gt;
  &lt;span class="na"&gt;watchFolders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;workspaceRoot&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;nodeModulesPaths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// Tell metro to resolve modules in /mobile folder&lt;/span&gt;
      &lt;span class="c1"&gt;// and if not found, then try to find modules in workspace&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workspaceRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="c1"&gt;// And to make thing above work:&lt;/span&gt;
    &lt;span class="na"&gt;disableHierarchicalLookup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what happens above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;we tell metro to look for files everywhere (meaning in root dir)&lt;/li&gt;
&lt;li&gt;resolve &lt;code&gt;node_modules&lt;/code&gt; from workspace root as well. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Second part is needed, because at some point &lt;code&gt;shared&lt;/code&gt; code will use some packages, and they will be in root's &lt;code&gt;node_modules&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Okay, now metro sees codes from the &lt;code&gt;shared&lt;/code&gt; folder, how to import them into a mobile project?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;4. Import files from &lt;code&gt;shared&lt;/code&gt; into mobile
&lt;/h2&gt;

&lt;p&gt;Remember how we imported it on the web?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sayHello&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is possible, because &lt;code&gt;shared&lt;/code&gt; is a workspace. It's like having yet another node module.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;mobile&lt;/code&gt; doesn't treat it as a workspace, we will import files directly. And to have similar experience as in web, we can use babel aliases:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn add -D babel-plugin-module-resolver&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// mobile/babel.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module:metro-react-native-babel-preset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module-resolver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// needed alias&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And now we can do imports like this in mobile as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sayHello&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;At this point you'll be able to run mobile and web, and see how changes in &lt;code&gt;shared&lt;/code&gt; code reflect on both.&lt;/p&gt;

&lt;p&gt;I also recommend to add this line to root &lt;code&gt;package.json&lt;/code&gt;, to have mobile packages installed from &lt;code&gt;yarn&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  "scripts": {
&lt;span class="gi"&gt;+   "postinstall": "cd ./projects/mobile &amp;amp;&amp;amp; yarn"
&lt;/span&gt;  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/romenkova/react-native-monorepo-example" rel="noopener noreferrer"&gt;Minimal working example [repo]&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Do you see any downsides to this approach? Please, let me know in the comments.&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>webdev</category>
      <category>monorepo</category>
    </item>
  </channel>
</rss>
