<?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: Yuns</title>
    <description>The latest articles on DEV Community by Yuns (@yuns).</description>
    <link>https://dev.to/yuns</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%2F614448%2F2fa5e3b6-7b3e-426b-8008-b6ad8a3e22df.jpeg</url>
      <title>DEV Community: Yuns</title>
      <link>https://dev.to/yuns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuns"/>
    <language>en</language>
    <item>
      <title>A fullstack solution for structuring TailwindCSS classnames</title>
      <dc:creator>Yuns</dc:creator>
      <pubDate>Wed, 30 Aug 2023 15:12:29 +0000</pubDate>
      <link>https://dev.to/yuns/a-fullstack-solution-for-structuring-tailwindcss-classnames-cpb</link>
      <guid>https://dev.to/yuns/a-fullstack-solution-for-structuring-tailwindcss-classnames-cpb</guid>
      <description>&lt;p&gt;After a neither long nor short time for developing Next.js + TailwindCSS app, it is so annoyed at writing TailwindCSS classnames more and more big.&lt;/p&gt;

&lt;p&gt;A React example:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Demo&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="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;'flex flex-col items-start justify-start md:mt-24 md:flex-row md:items-center md:justify-center md:space-x-6'&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;'space-x-2 pb-8 pt-6 md:space-y-5'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'text-6xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 md:border-r-2 md:px-6 md:text-8xl md:leading-14'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        404
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'max-w-md'&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;p&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;'mb-4 text-xl font-bold leading-normal md:text-2xl'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Sorry we couldn't find this page.`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;p&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;'mb-8'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`But don't worry, you can find plenty of other things on our homepage.`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; How to make the code looks more nicer?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; After use the new born package &lt;a href="https://github.com/yunsii/tagged-classnames-free"&gt;tagged-classnames-free&lt;/a&gt;:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cls&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;tagged-classnames-free&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Demo&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="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="nx"&gt;cls&lt;/span&gt;&lt;span class="s2"&gt;`
      flex flex-col items-start justify-start 
      md:mt-24 md:flex-row md:items-center md:justify-center md:space-x-6
    `&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'space-x-2 pb-8 pt-6 md:space-y-5'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="s2"&gt;`
          text-6xl font-extrabold leading-9 tracking-tight text-gray-900
          dark:text-gray-100 
          md:border-r-2 md:px-6 md:text-8xl md:leading-14 
        `&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        404
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'max-w-md'&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;p&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="nx"&gt;cls&lt;/span&gt;&lt;span class="s2"&gt;`
          mb-4 text-xl font-bold leading-normal 
          md:text-2xl
        `&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Sorry we couldn't find this page.`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;p&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;'mb-8'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`But don't worry, you can find plenty of other things on our homepage.`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cls&lt;/code&gt; tag based on &lt;a href="https://github.com/lukeed/clsx"&gt;clsx&lt;/a&gt;, and &lt;code&gt;tw&lt;/code&gt; tag integrated &lt;a href="https://github.com/dcastil/tailwind-merge"&gt;tailwind-merge&lt;/a&gt; already.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; How to auto indent/dedent strings in tagged template if I want to wrap/unwrap tagged classnames by functions or html tags?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; &lt;a href="https://eslint.org/"&gt;ESLint&lt;/a&gt; is a awesome tool, &lt;a href="https://github.com/sindresorhus/eslint-plugin-unicorn"&gt;eslint-plugin-unicorn&lt;/a&gt; has a &lt;a href="https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/template-indent.md"&gt;template-indent&lt;/a&gt; rule for us to auto indent/dedent.&lt;/p&gt;

&lt;p&gt;It is also compatiable with &lt;a href="https://github.com/tailwindlabs/prettier-plugin-tailwindcss"&gt;prettier-plugin-tailwindcss&lt;/a&gt; even if write classnames by multiple lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; What is the impact on runtime performance, especially for what could have been wrote by pure strings?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; There is also a new born &lt;a href="https://github.com/yunsii/unplugin-polish-tagged-templates"&gt;unplugin-polish-tagged-templates&lt;/a&gt; for this, It can transform tagged templates without expressions into pure strings at compile time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Try overall features on &lt;a href="https://gitpod.io/#https://github.com/yunsii/tagged-classnames-free"&gt;Gitpod&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build Chrome Extension (MV3) development environment based on Vite + React</title>
      <dc:creator>Yuns</dc:creator>
      <pubDate>Sun, 18 Apr 2021 10:21:17 +0000</pubDate>
      <link>https://dev.to/yuns/build-chrome-extension-mv3-development-environment-based-on-vite-react-497h</link>
      <guid>https://dev.to/yuns/build-chrome-extension-mv3-development-environment-based-on-vite-react-497h</guid>
      <description>&lt;h2&gt;
  
  
  Foreword
&lt;/h2&gt;

&lt;p&gt;I have always wanted to make a bilibili barrage extension. I recently took the opportunity of researching Vite to do it. It took two days to build a Chrome Extension (MV3) development environment based on Vite + React. The core functions are as follows:&lt;/p&gt;

&lt;p&gt;-📦️ JS packaged into a single file&lt;br&gt;
-🎨 Automatically introduce CSS&lt;br&gt;
-🔨 Package service worker&lt;br&gt;
-🚀 Hot reload of development environment&lt;/p&gt;

&lt;p&gt;Here is a focus on the implementation of the current hot update. Other functions are relatively simple. For details, please refer to &lt;a href="https://github.com/yunslove/violet" rel="noopener noreferrer"&gt;yunslove/violet&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I watched "Violet Evergarden" at bilibili, which was impressive. Just this time I planned to be a barrage extension of bilibili, and simply took the heroine's name &lt;strong&gt;violet&lt;/strong&gt; 😃&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Practical operation
&lt;/h2&gt;

&lt;p&gt;The general process of hot update is shown in the figure below:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmvlokcmpurtl0xbryim.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmvlokcmpurtl0xbryim.png" alt="hot-reload-graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  start up
&lt;/h3&gt;

&lt;p&gt;Execute three commands simultaneously through &lt;code&gt;npm run dev&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;-tsc compile service worker and monitor changes&lt;br&gt;
-vite compile extension&lt;br&gt;
-The websocket service monitors the changes of the directory /dist after packaging&lt;/p&gt;

&lt;p&gt;Among them, because &lt;a href="https://github.com/vitejs/vite/issues/1434" rel="noopener noreferrer"&gt;&lt;code&gt;vite build --watch&lt;/code&gt; has not yet been released&lt;/a&gt;, temporarily through &lt;a href="https://github.com/yunslove/violet/blob/master/scripts/build-ext-watch.js" rel="noopener noreferrer"&gt;custom script&lt;/a&gt; monitor the source code changes, and can be removed after the vite feature is released.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hot Update
&lt;/h3&gt;

&lt;p&gt;After the browser page loads the content scripts, a websocket link will be created. After receiving the request, the server will start listening to the &lt;code&gt;/dist&lt;/code&gt; directory. The websocket service will actively initiate a notification after listening to the change of &lt;code&gt;/dist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The content scripts receive the notification that the extension needs to be updated, and trigger the event registered in the service worker by &lt;code&gt;chrome.runtime.onMessage&lt;/code&gt; via &lt;code&gt;chrome.runtime.sendMessage&lt;/code&gt;, which triggers &lt;code&gt;chrome.runtime.reload&lt;/code&gt; and &lt;code&gt;chrome.tabs.reload&lt;/code&gt; in turn to update Extension and current page. What you write is what you get without any manual intervention 🚀&lt;/p&gt;

&lt;p&gt;Readers may have a question, why not listen for notifications from websocket directly in the service worker?&lt;/p&gt;

&lt;p&gt;I have been thinking the same way before. The use of service workers under Manifest V3 promotes &lt;a href="https://developer.chrome.com/docs/extensions/mv3/migrating_to_service_workers/#events" rel="noopener noreferrer"&gt;Thinking with events&lt;/a&gt; through &lt;code&gt;chrome.runtime.onInstalled&lt;/code&gt;And &lt;code&gt;chrome.runtime.onStartup&lt;/code&gt; to create a websocket client will be closed unexpectedly, even if the timer polling is used, it will be closed and restarted after multiple executions. Therefore, the best solution currently found is to monitor the &lt;code&gt;chrome.runtime.onMessage&lt;/code&gt; event in the service worker.&lt;/p&gt;

&lt;p&gt;In this way, the hot update process will only be triggered when the page loads the current Extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sum Up
&lt;/h2&gt;

&lt;p&gt;Since most of the current Chrome Extension versions are lower than the MV3 version, I have stepped on a lot of pits in the past two days, and I have a certain degree of understanding of browser extension development that I have not touched before. Now it is only for the Chrome Extension scenario. I will continue to improve the current scenario to complete the support for other browser extensions. Finally, it should be possible to encapsulate a tool for browser extension development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Translate from Chinese, checkout by &lt;a href="https://github.com/yunslove" rel="noopener noreferrer"&gt;yunslove&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>vite</category>
      <category>react</category>
      <category>chrome</category>
      <category>extension</category>
    </item>
  </channel>
</rss>
