<?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: yteruel31</title>
    <description>The latest articles on DEV Community by yteruel31 (@yteruel31).</description>
    <link>https://dev.to/yteruel31</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%2F433540%2F233420c2-18f0-47d9-ab5c-5b0b2e935f78.jpeg</url>
      <title>DEV Community: yteruel31</title>
      <link>https://dev.to/yteruel31</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yteruel31"/>
    <language>en</language>
    <item>
      <title>I Built a JetBrains Plugin Without Knowing Kotlin, Thanks to Claude Code</title>
      <dc:creator>yteruel31</dc:creator>
      <pubDate>Fri, 20 Feb 2026 13:14:52 +0000</pubDate>
      <link>https://dev.to/yteruel31/i-built-a-jetbrains-plugin-without-knowing-kotlin-thanks-to-claude-code-4jkm</link>
      <guid>https://dev.to/yteruel31/i-built-a-jetbrains-plugin-without-knowing-kotlin-thanks-to-claude-code-4jkm</guid>
      <description>&lt;p&gt;If you use Git worktrees, you probably know the pain. You're deep in your IDE, focused, and then you need to create a new worktree or switch to another one. So you open a terminal, type &lt;code&gt;git worktree add&lt;/code&gt;, manually navigate to the new folder, open it in a new IDE window... and by the time you're set up, you've lost your flow.&lt;/p&gt;

&lt;p&gt;I've been using worktrees for a while now, and this back-and-forth with the terminal always bugged me. One day I checked and realized JetBrains has absolutely &lt;strong&gt;zero&lt;/strong&gt; native support for worktrees. No panel, no action, nothing. You'd think for an IDE that has amazing Git integration, worktree management would be in there somewhere. But nope 😅&lt;/p&gt;

&lt;p&gt;There is an existing plugin that handles worktrees, but some of its features are behind a paywall. I figured if I'm going to solve this problem, I might as well make it fully free and open source so other developers can benefit from it too.&lt;/p&gt;

&lt;p&gt;So I decided to build it myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: I don't know Kotlin
&lt;/h2&gt;

&lt;p&gt;Here's the thing. I'm a frontend developer. TypeScript, React, that's my world. I had never written a single line of Kotlin, never touched the IntelliJ Platform SDK, and had no idea how JetBrains plugins even work internally.&lt;/p&gt;

&lt;p&gt;Building an IDE plugin felt like a completely different universe. The IntelliJ SDK is massive, the documentation can be dense, and the patterns are very specific (extension points, services, message buses, thread management...). Not exactly a weekend side project for someone coming from the web world 😬&lt;/p&gt;

&lt;p&gt;But I had Claude Code on my side, and I had plans to push it further than usual.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Claude Code setup
&lt;/h2&gt;

&lt;p&gt;I've been using Claude Code for a while across different projects, so I'm pretty familiar with how to get the most out of it. For this plugin, I knew I needed to go beyond the default experience. The IntelliJ SDK is a niche domain, and I wanted Claude to be as specialized as possible.&lt;/p&gt;

&lt;p&gt;So I did two things:&lt;/p&gt;

&lt;h3&gt;
  
  
  A custom JetBrains expert subagent
&lt;/h3&gt;

&lt;p&gt;Claude Code lets you create &lt;a href="https://docs.anthropic.com/en/docs/claude-code/sub-agents" rel="noopener noreferrer"&gt;custom subagents&lt;/a&gt;. These are specialized agents with their own system prompts and tools. I created a &lt;code&gt;jetbrains-expert&lt;/code&gt; agent (&lt;code&gt;.claude/agents/jetbrains-expert.md&lt;/code&gt;) that acts as a dedicated IntelliJ Platform SDK expert.&lt;/p&gt;

&lt;p&gt;This agent knows about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin architecture and &lt;code&gt;plugin.xml&lt;/code&gt; structure&lt;/li&gt;
&lt;li&gt;Kotlin UI DSL v2 for building dialogs and settings panels&lt;/li&gt;
&lt;li&gt;Threading rules (never block the EDT!)&lt;/li&gt;
&lt;li&gt;Services, extension points, &lt;code&gt;MessageBus&lt;/code&gt; patterns&lt;/li&gt;
&lt;li&gt;VCS integration, process execution, persistence&lt;/li&gt;
&lt;li&gt;Common pitfalls and deprecated API migrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of Claude having general knowledge about "maybe how IntelliJ plugins work," this subagent has focused, structured knowledge about the exact patterns and APIs I needed. It made a massive difference in code quality from the very first prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  A google-research MCP plugin (instead of WebSearch)
&lt;/h3&gt;

&lt;p&gt;Claude Code has a built-in WebSearch tool, but I wasn't happy with it. The results were often shallow, and there's a security concern I cared about: with WebSearch, Claude directly processes raw web content. That means any prompt injection hidden in a web page could potentially influence Claude's behavior.&lt;/p&gt;

&lt;p&gt;So I built my own research plugin as part of my &lt;a href="https://github.com/yteruel31/claude-marketplace" rel="noopener noreferrer"&gt;Claude Code plugin marketplace&lt;/a&gt;. It's called &lt;strong&gt;google-research&lt;/strong&gt; and it works differently. Instead of Claude reading web pages directly, the plugin sends queries to Google Gemini with Google Search grounding enabled. Gemini does the searching, reads the pages, reasons over them with high-level thinking, and returns a synthesized report with inline citations. Claude only ever sees Gemini's output, never the raw web content.&lt;/p&gt;

&lt;p&gt;This gives me several things WebSearch doesn't. The search quality is better because Gemini actually reasons over the results instead of just returning links. Every claim in the report comes with inline citations mapped to specific sources, so I can verify what I'm reading. Grounding means the answers are based on real web content, not hallucinated. The content goes through sanitization (strips scripts, iframes, external images) and Gemini's safety filters before reaching Claude, which reduces the prompt injection surface. And I have full control over focus areas, output format, and the research even gets saved to disk automatically.&lt;/p&gt;

&lt;p&gt;I used it for everything during the plugin development: looking up IntelliJ SDK docs, researching best practices, checking how other plugin developers solved similar problems.&lt;br&gt;
Having this inside Claude Code means I never had to leave the terminal to go Google something. Claude could just search on its own and come back with grounded answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the development actually worked
&lt;/h2&gt;

&lt;p&gt;I didn't start from a template. Claude set up the entire project from scratch: Gradle config, &lt;code&gt;plugin.xml&lt;/code&gt;, project structure, the whole thing. I described what I wanted to build and it scaffolded everything.&lt;/p&gt;

&lt;p&gt;From there, features came one at a time. I started with the basics, just listing worktrees in a VCS tab. Then I thought "ok, what if I could create one from here?" Then sync files.&lt;br&gt;
Then PR checkout. The scope grew as I went. Every time I thought "it would be nice if..." I'd just describe it and Claude would build it.&lt;/p&gt;

&lt;p&gt;Claude Code wrote the majority of the plugin. I'm not going to pretend otherwise. But it wasn't just "generate code and paste it." It was more like having a senior Kotlin developer sitting next to me who also happened to know the IntelliJ SDK inside out.&lt;/p&gt;

&lt;p&gt;A typical cycle looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'd describe what I wanted: "I need a panel in the VCS tool window that lists all worktrees"&lt;/li&gt;
&lt;li&gt;Claude (via the jetbrains-expert subagent) would write the code, using the right IntelliJ APIs like &lt;code&gt;changesViewContent&lt;/code&gt; extension point, &lt;code&gt;Tree&lt;/code&gt; with &lt;code&gt;DefaultTreeModel&lt;/code&gt;, &lt;code&gt;ColoredTreeCellRenderer&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;I'd review it, test it in the sandbox IDE, and iterate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The IntelliJ SDK has a lot of "you need to know this exists" moments. Things like &lt;code&gt;CapturingProcessHandler&lt;/code&gt; for running CLI commands, &lt;code&gt;ProgressManager&lt;/code&gt; for background tasks, &lt;code&gt;MessageBus&lt;/code&gt; for event-driven UI updates. The subagent knew about all of these and used them correctly from the start. That saved me an insane amount of time compared to digging through docs and StackOverflow.&lt;/p&gt;

&lt;p&gt;What surprised me the most is that the code didn't feel like "AI-generated code." It followed IntelliJ conventions, used the right patterns, and didn't over-engineer things. I think the custom subagent prompt was key here. It had explicit guidelines like "prefer native IntelliJ Platform APIs" and "don't over-engineer."&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%2Fhumtv9t13nrf5cnqfqer.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%2Fhumtv9t13nrf5cnqfqer.png" alt="Claude code in action" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the plugin does
&lt;/h2&gt;

&lt;p&gt;The plugin adds a &lt;strong&gt;Worktrees tab&lt;/strong&gt; in the VCS tool window. From there, you can manage everything without touching the terminal:&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%2Fge0z64a6mt1xplljrxow.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%2Fge0z64a6mt1xplljrxow.png" alt="Worktree tab in VCS" width="558" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;create worktrees&lt;/strong&gt; by picking a path and creating a new branch (or using an existing one), with options to auto-sync files and run post-creation commands like &lt;code&gt;npm install&lt;/code&gt;. You can &lt;strong&gt;remove, lock, and move&lt;/strong&gt; worktrees directly from the UI. You can also &lt;strong&gt;open a worktree in a new window&lt;/strong&gt; with one click.&lt;/p&gt;

&lt;p&gt;One of the features I'm most happy with is &lt;strong&gt;file sync across worktrees&lt;/strong&gt;. It copies &lt;code&gt;.idea/&lt;/code&gt; settings, &lt;code&gt;.env&lt;/code&gt; files, or any custom paths you configure. You can set up exclusions too, so you don't accidentally sync &lt;code&gt;workspace.xml&lt;/code&gt; and break your window layout.&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%2Fa6xivx397b772szfpx3l.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%2Fa6xivx397b772szfpx3l.png" alt="Add a new worktree" width="570" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PR checkout&lt;/strong&gt; is another one. You enter a PR number and the plugin figures out the right refspec for GitHub, GitLab, or Bitbucket automatically. No need to remember if it's &lt;code&gt;pull/123/head&lt;/code&gt; or &lt;code&gt;merge-requests/123/head&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There's also a &lt;strong&gt;compare view&lt;/strong&gt; that shows a side-by-side table with branch, commit, and status for all your worktrees. And you can &lt;strong&gt;create a worktree from any commit&lt;/strong&gt; by right-clicking in the VCS Log.&lt;/p&gt;

&lt;p&gt;The plugin also decorates your IDE. The window title shows which worktree branch you're on (&lt;code&gt;[worktree: feature-branch]&lt;/code&gt;), and the project sidebar displays the branch name next to the root folder. Small details, but when you're juggling 3-4 worktrees across multiple windows, it makes a big difference.&lt;/p&gt;

&lt;p&gt;There's a full settings page under &lt;strong&gt;Tools &amp;gt; Git Worktree Tool&lt;/strong&gt; where you can configure default directories, sync behavior, .idea exclusions, custom sync paths, and post-creation hooks.&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%2Fy012o2sgawqk5dbcwi3k.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%2Fy012o2sgawqk5dbcwi3k.png" alt="Git worktree settings" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The tricky parts
&lt;/h2&gt;

&lt;p&gt;The development was mostly smooth. The subagent really did its job. But there were still some bumps.&lt;/p&gt;

&lt;p&gt;The biggest headache was &lt;strong&gt;threading&lt;/strong&gt;. IntelliJ is very strict about what runs on which thread. Git commands have to run in the background (otherwise the UI freezes), but UI updates have to happen on the EDT (Event Dispatch Thread). Sounds simple, but in practice we ran into issues where the worktree panel just wouldn't update after creating or removing a worktree. The data was there, the cache was refreshed, but the tree component wasn't picking it up. Turned out the events were being published on the wrong thread. We ended up using a &lt;code&gt;MessageBus&lt;/code&gt; topic (&lt;code&gt;WorktreeListChangedTopic&lt;/code&gt;) to properly notify the panel, and that fixed it. But it took a few iterations to get the threading dance right.&lt;/p&gt;

&lt;p&gt;Parsing &lt;code&gt;git worktree list --porcelain&lt;/code&gt; was more complex than expected too. The output is stateful, you read lines one by one and accumulate fields (path, head, branch, flags) until you hit the next &lt;code&gt;worktree&lt;/code&gt; line. Claude nailed the parser, but reviewing it required me to actually understand the git output format in detail.&lt;/p&gt;

&lt;p&gt;PR checkout across providers also had a lot of edge cases. GitHub uses &lt;code&gt;pull/123/head&lt;/code&gt;, GitLab uses &lt;code&gt;merge-requests/123/head&lt;/code&gt;, Bitbucket uses &lt;code&gt;pull-requests/123/from&lt;/code&gt;. The plugin detects which provider you're using by parsing the remote URL and builds the right refspec automatically. One of those features that sounds trivial but has more surface area than you'd think.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned from this
&lt;/h2&gt;

&lt;p&gt;Could I have built this plugin without Claude Code? Probably yes, eventually. But it would have taken me significantly longer. Kotlin isn't that far from TypeScript conceptually, and the IntelliJ SDK is well-documented. But the ramp-up time from "I've never written a plugin" to "I have a working VCS tab with a tree model and background threading"... that's where Claude was a massive accelerator.&lt;/p&gt;

&lt;p&gt;If I had to give advice to someone thinking about doing something similar, I'd say: invest time in the setup. Creating the specialized subagent was probably the single biggest factor in code quality. Generic AI produces generic code. When you give it focused knowledge about the specific SDK and patterns you're working with, the output is on a completely different level.&lt;/p&gt;

&lt;p&gt;You also still need to understand what you're building. I knew exactly what worktree features I wanted because I use them daily. Claude can write the code, but it can't tell you what to build.&lt;/p&gt;

&lt;p&gt;And review everything. I learned Kotlin patterns and IntelliJ APIs by reading what Claude produced, not by blindly shipping it. The generated code became my learning material.&lt;/p&gt;

&lt;p&gt;One last thing: having MCP plugins for research (like google-research) kept things moving. Being able to search docs without leaving the coding flow made a real difference, especially for a niche SDK where you need very specific, up-to-date information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;The plugin is available on the JetBrains Marketplace. Just search for &lt;strong&gt;"Git Worktree Manager"&lt;/strong&gt; in your IDE's plugin settings.&lt;/p&gt;

&lt;p&gt;It's also open source, so feel free to check the code, open issues, or contribute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔗 &lt;a href="https://plugins.jetbrains.com/plugin/30140-git-worktree-tool" rel="noopener noreferrer"&gt;JetBrains Marketplace&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/yteruel31/jetbrains-worktree-plugin" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The custom subagent is in the plugin repo under &lt;code&gt;.claude/agents/&lt;/code&gt;. And the google-research MCP plugin I mentioned is part of my &lt;a href="https://github.com/yteruel31/claude-marketplace" rel="noopener noreferrer"&gt;Claude Code plugin marketplace&lt;/a&gt;, where you can also find other plugins like Discord and Reddit integrations.&lt;/p&gt;

&lt;p&gt;If you use Git worktrees in your workflow, I'd love to hear your feedback. What features would you want to see next? And if you've pushed Claude Code with custom subagents or MCP plugins, I'm curious to hear what you've built 🙂&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>jetbrains</category>
    </item>
    <item>
      <title>I’ve built my Portfolio with NextJs and DatoCMS</title>
      <dc:creator>yteruel31</dc:creator>
      <pubDate>Tue, 06 Aug 2024 16:13:13 +0000</pubDate>
      <link>https://dev.to/yteruel31/ive-built-my-portfolio-with-nextjs-and-datocms-3pbj</link>
      <guid>https://dev.to/yteruel31/ive-built-my-portfolio-with-nextjs-and-datocms-3pbj</guid>
      <description>&lt;p&gt;Creating a portfolio website is, in my opinion, essential for any professional looking to showcase their work. While you can share your work through your GitHub profile, a portfolio can effectively demonstrate your skills as it serves as a good side project itself. 😄&lt;/p&gt;

&lt;p&gt;Personally, I’ve rebuilt my portfolio several times (maybe 4 times 😬) because I wanted to update the design and was never fully satisfied. But now, I’ve finally found a great fit for my design! :D&lt;/p&gt;

&lt;h2&gt;
  
  
  Design of my Portfolio
&lt;/h2&gt;

&lt;p&gt;I started by sketching out the layout and design elements that I wanted to include. I focused on creating a clean and modern look, with an emphasis on showcasing my projects and skills effectively.&lt;/p&gt;

&lt;p&gt;I've taken inspiration from the landing page of &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite.js&lt;/a&gt; and began sketching the header and hero section of my landing page on Figma. This approach helped me visualize the overall structure and ensure the design aligns with my goals.&lt;/p&gt;

&lt;p&gt;After that, I decided to take a break from sketching the full website because it already matched what I had in mind.&lt;/p&gt;

&lt;p&gt;Here you can see my sketching: &lt;a href="https://www.figma.com/design/LH9ntrVY3bGnD3qFxLeAtQ/PORTFOLIO" rel="noopener noreferrer"&gt;https://www.figma.com/design/LH9ntrVY3bGnD3qFxLeAtQ/PORTFOLIO&lt;/a&gt; (you can notice the design of my old portfolio; for that one, I wasn't lazy 😆)&lt;/p&gt;

&lt;p&gt;Next step was to think about the stack I wanted to use…&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture of my Portfolio
&lt;/h2&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%2Fgw9twhbkvpdqmprp7hbl.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%2Fgw9twhbkvpdqmprp7hbl.png" alt="architecture of my portfolio" width="790" height="987"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the frontend, I'm diving into &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt; to get familiar with the framework. For styling, I'm enjoying using &lt;a href="https://github.com/css-modules/css-modules" rel="noopener noreferrer"&gt;CSS Modules&lt;/a&gt;, and my frontend is comfortably hosted on &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a frontend developer, my main focus has been the frontend of my side project. I didn't build the backend from scratch. Instead, I'm using &lt;a href="https://www.datocms.com/" rel="noopener noreferrer"&gt;DatoCMS&lt;/a&gt;, a headless CMS, to easily manage my content, such as side projects and skills. I chose this CMS because it requires the use of &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt;, a technology I wanted to learn. They also have great documentation that's easy to follow and a good free tier plan 😃&lt;/p&gt;

&lt;p&gt;To retrieve data from DatoCMS into my frontend, I needed to use GraphQL. You can use the DatoCMS SDK to fetch data without building GraphQL queries, but I wanted to take this opportunity to learn GraphQL 😄&lt;/p&gt;

&lt;p&gt;I'm planning to go deeper into how I've structured my data in DatoCMS and what cool features it offers in another post...&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’ve Learned from It
&lt;/h2&gt;

&lt;p&gt;It was such an exciting project! I’ve learned so much 🙂 I've gained a deeper understanding of how to integrate a headless CMS with a frontend framework like NextJS. DatoCMS has an awesome SDK (&lt;code&gt;react-datocms&lt;/code&gt;) that includes the &lt;a href="https://www.datocms.com/docs/next-js/managing-images" rel="noopener noreferrer"&gt;Image&lt;/a&gt; component, making it easy to get optimized versions of images (just like the &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images" rel="noopener noreferrer"&gt;Image&lt;/a&gt; component from NextJS).&lt;/p&gt;

&lt;p&gt;Plus, learning and implementing GraphQL queries has been especially rewarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;I am happy with my portfolio, but there is always room for improvement. In the future, I want to add a section on the main page to show my last 3 blog articles (I still need to write two more 😜). I also plan to update the content and design regularly to show my new skills and projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a portfolio has been an invaluable experience, helping me grow both technically and creatively. Integrating various technologies and seeing the final product come to life has been immensely rewarding. I strongly encourage everyone to start this journey; it’s a great way to showcase your skills and passion.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/yteruel31/portfolio" rel="noopener noreferrer"&gt;source code&lt;/a&gt; and &lt;a href="//yteruel.fr"&gt;my portfolio&lt;/a&gt;! I'd love to hear any feedback you have. If you find it helpful or inspiring, please give it a star ⭐ — it means a lot to me!&lt;/p&gt;

&lt;p&gt;Thanks for reading this guide. I hope you found it useful in your own journey. Happy coding, and may your projects shine as brightly as the stars you earn!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>portfolio</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Setup a path mapping through ts-config</title>
      <dc:creator>yteruel31</dc:creator>
      <pubDate>Sun, 09 Jan 2022 16:08:22 +0000</pubDate>
      <link>https://dev.to/yteruel31/setup-a-path-aliasmapping-through-ts-config-1mlg</link>
      <guid>https://dev.to/yteruel31/setup-a-path-aliasmapping-through-ts-config-1mlg</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Today, I want to show you the way to avoid these ugly paths on your typescript projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpohqpfuuxygfxundqkru.supabase.in%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fblogs%2Fsetup_path_mapping_1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpohqpfuuxygfxundqkru.supabase.in%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fblogs%2Fsetup_path_mapping_1.png" alt="setup_path_mapping_1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To something more readable, maintainable and fancier:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpohqpfuuxygfxundqkru.supabase.in%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fblogs%2Fsetup_path_mapping_2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpohqpfuuxygfxundqkru.supabase.in%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fblogs%2Fsetup_path_mapping_2.png" alt="setup_path_mapping_2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Path mapping
&lt;/h2&gt;

&lt;p&gt;On Typescript project, we can use path mapping method through ts-config.json... &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But, what does it mean “path mapping” on a Typescript project?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;ts-config.json&lt;/code&gt; would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src"&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="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;must&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;specified&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paths"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@/components/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"components/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The values inside &lt;code&gt;paths&lt;/code&gt; property tell the transpiler: for any module import that matches the pattern &lt;code&gt;"@/components/*"&lt;/code&gt; (&lt;code&gt;*&lt;/code&gt; i.e. all values), to look in location &lt;code&gt;"components/*"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So now with these instructions in my .tsx file, if I import a new component :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Button&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;@/components/Button&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;When I compile, the transpiler knows where is this component in my project because during the build process the transpiler combines the &lt;code&gt;baseUrl&lt;/code&gt; with &lt;code&gt;components/*&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;baseUrl&amp;gt;/components/Button
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the Typescript documentation for information about this: &lt;a href="https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping" rel="noopener noreferrer"&gt;TypeScript: Documentation - Module Resolution (typescriptlang.org)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  tsconfig-paths
&lt;/h2&gt;

&lt;p&gt;If for some reason, you are working with node.js or some environment that doesn't use a module bundler like webpack or parcel you will additionally need &lt;a href="https://www.npmjs.com/package/tsconfig-paths" rel="noopener noreferrer"&gt;tsconfig-paths&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;This package will read the &lt;code&gt;paths&lt;/code&gt; from &lt;code&gt;tsconfig.json&lt;/code&gt; and convert node's module loading calls into physical file paths that node can load.&lt;/p&gt;

&lt;p&gt;To do this, you need to preload &lt;code&gt;tsconfig-paths/register&lt;/code&gt; in your node command :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-r&lt;/span&gt; tsconfig-paths/register main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Jest
&lt;/h2&gt;

&lt;p&gt;Jest is a little mischievous with paths-mapping of Typescript, you need to specify the module mapping to him. For example in your &lt;code&gt;jest.config.js&lt;/code&gt;, you can set &lt;code&gt;moduleNameMapper&lt;/code&gt; property:&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="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;moduleNameMapper&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;rootDir&amp;gt;/src/$1&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;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you were enjoyed reading this article. It’s my first time, be indulgent with me please :D Also, I learn English, so don’t hesitate to notify me if I did mistakes.&lt;br&gt;
You can follow me on my &lt;a href="https://github.com/yteruel31" rel="noopener noreferrer"&gt;Github&lt;/a&gt; and my &lt;a href="https://yteruel.fr/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt; (it’s under construction, but soon I will present it through a new article)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>node</category>
    </item>
  </channel>
</rss>
