<?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: Rei</title>
    <description>The latest articles on DEV Community by Rei (@chloerei).</description>
    <link>https://dev.to/chloerei</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%2F836141%2F1d4be3f2-9fc0-492b-ae45-2b4818d16369.jpg</url>
      <title>DEV Community: Rei</title>
      <link>https://dev.to/chloerei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chloerei"/>
    <language>en</language>
    <item>
      <title>test quick post, is it useful?</title>
      <dc:creator>Rei</dc:creator>
      <pubDate>Mon, 10 Mar 2025 07:20:00 +0000</pubDate>
      <link>https://dev.to/chloerei/test-quick-post-is-it-useful-1c7h</link>
      <guid>https://dev.to/chloerei/test-quick-post-is-it-useful-1c7h</guid>
      <description></description>
      <category>test</category>
      <category>discuss</category>
    </item>
    <item>
      <title>test</title>
      <dc:creator>Rei</dc:creator>
      <pubDate>Fri, 22 Nov 2024 09:01:28 +0000</pubDate>
      <link>https://dev.to/chloerei/test-4a7d</link>
      <guid>https://dev.to/chloerei/test-4a7d</guid>
      <description></description>
    </item>
    <item>
      <title>Rails developers should embrace Web Component</title>
      <dc:creator>Rei</dc:creator>
      <pubDate>Thu, 17 Oct 2024 15:06:18 +0000</pubDate>
      <link>https://dev.to/chloerei/rails-developers-should-embrace-web-components-1lmn</link>
      <guid>https://dev.to/chloerei/rails-developers-should-embrace-web-components-1lmn</guid>
      <description>&lt;p&gt;Rails 8 will continue to use Hotwire as the default, which I think is great. Hotwire is a server-side renderingfront-end solution. Since the server is the source of data, most applications can solve problems through server-side rendering without considering data synchronization.&lt;/p&gt;

&lt;p&gt;However, just because it can be done doesn't mean it's optimal. There are still some issues that need to be handled on the client side, usually involving client-side state and front-end rendering. For example, a multi-select input box. Currently, &lt;a href="https://geeknote.net/" rel="noopener noreferrer"&gt;Geeknote&lt;/a&gt;'s tag input uses the &lt;a href="https://github.com/josefarias/hotwire_combobox" rel="noopener noreferrer"&gt;hotwire_combobox&lt;/a&gt; library, which fully utilizes Hotwire's server-side rendering features to implement a multi-select input box in a clever way. But if the network is slow, you will find that the input has a delay:&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%2F4zqeyii7la04yyul3nth.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%2F4zqeyii7la04yyul3nth.png" alt=" " width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem here is that when converting the input to a chip, hotwire_combobox uses server-side rendering, which can actually be done on the client side because the data needed for rendering has already been obtained when displaying the autocomplete list. Of course, hotwire_combobox may switch to client-side rendering in the future, and then you will find that you need to handle two issues: client-side state and rendering. Since Hotwire does not include client-side rendering capabilities, it would be very painful to handle it purely with JavaScript. Consider how to manage options, entered values, and current selections, and reflect them in the UI?&lt;/p&gt;

&lt;p&gt;At this point, you need to consider a front-end solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Front-end Components
&lt;/h2&gt;

&lt;p&gt;In the past decade of front-end framework battles, the concept of "components" has gained consensus. A component is a front-end module that includes styles, state, and functionality. Components can contain more components, and components can communicate with each other. Managing front-end code in a component-based way is the mainstream in today's front-end frameworks.&lt;/p&gt;

&lt;p&gt;So when choosing a front-end solution, I will consider component-based front-end solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  View Component
&lt;/h3&gt;

&lt;p&gt;If you search for &lt;code&gt;Rails Component&lt;/code&gt;, you will find the &lt;a href="https://viewcomponent.org/" rel="noopener noreferrer"&gt;ViewComponent&lt;/a&gt; gem. It is essentially an object-oriented server-side partial template that provides better testing interfaces but does not solve client-side state and rendering.&lt;/p&gt;

&lt;h3&gt;
  
  
  React/Vue, etc.
&lt;/h3&gt;

&lt;p&gt;React/Vue and other popular front-end frameworks can easily build front-end components. They usually provide reactive properties and declarative templates, which can handle client-side state and rendering well. And these frameworks have large communities with a lot of ready-made UI libraries and component libraries.&lt;/p&gt;

&lt;p&gt;But this front-end frameworks have a problem: poor interoperability. React components need to be used in React projects, and Vue components need to be used in Vue projects. Of course, you can add adapters to make components from different frameworks interoperate, but few people do this. Usually, once a framework is chosen, the entire application will choose components based on that framework.&lt;/p&gt;

&lt;p&gt;Due to this problem, using React/Vue in Rails View also seems weird. Based on my experience, introducing React/Vue into Rails View will eventually lead to front-end and back-end separation because these components cannot interact with Rails View. Instead of coupling them together, it is better to separate them completely.&lt;/p&gt;

&lt;p&gt;Some people may think this is good, but I hope front-end components are used to enhance rather than replace Rails View, because Rails View work well at server-side rendering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Component
&lt;/h3&gt;

&lt;p&gt;Finally, I turned my attention to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components" rel="noopener noreferrer"&gt;Web Component&lt;/a&gt;, a standard browser API. Web Component allows developers to create custom elements and use them like built-in browser elements.&lt;/p&gt;

&lt;p&gt;For example, you can use custom elements like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;my-combobox&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tabs"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Ruby,JavaScript"&lt;/span&gt; &lt;span class="na"&gt;suggest-url=&lt;/span&gt;&lt;span class="s"&gt;"/tags/suggests"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-combobox&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;my-combobox&amp;gt;&lt;/code&gt; is a custom element that works like a built-in browser element and will be submitted with the form.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I haven't implemented &lt;code&gt;&amp;lt;my-combobox&amp;gt;&lt;/code&gt; yet, maybe in the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For Rails projects, it is better because you can use custom elements in the Turbo Stream/Broadcast without additional initialization code.&lt;/p&gt;

&lt;p&gt;You can create custom elements directly with the browser API, but I recommend starting with the Lit library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Lit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://lit.dev/" rel="noopener noreferrer"&gt;Lit&lt;/a&gt; is a library for developing Web Components, mainly developed by Google. According to the &lt;a href="https://lit.dev/docs/#why-should-i-choose-lit" rel="noopener noreferrer"&gt;official introduction&lt;/a&gt;, the Lit development team participated in the formulation of the Web Component standard.&lt;/p&gt;

&lt;p&gt;Compared to the native browser interface, Lit provides more features , such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scoped styles.&lt;/li&gt;
&lt;li&gt;Reactive properties.&lt;/li&gt;
&lt;li&gt;Declarative templates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of a counter component implemented with Lit:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;css&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;lit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCounter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`
    label {
      color: green;
    }
  `&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&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="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
        &amp;lt;label&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/label&amp;gt;
        &amp;lt;button @click="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;Increment&amp;lt;/button&amp;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;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyCounter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Styles within the component are only effective for internal elements, so class names can be written very concisely.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;${}&lt;/code&gt; for interpolation and &lt;code&gt;@event&lt;/code&gt; for event binding.&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;count&lt;/code&gt; property changes, only the parts that need to be updated will be updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features can greatly simplify front-end component development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice
&lt;/h2&gt;

&lt;p&gt;Recently, I developed a project called &lt;a href="https://www.geekslide.com/" rel="noopener noreferrer"&gt;Geekslide&lt;/a&gt; using Lit, which is used for UI component and slide editing/playback.&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%2Fd7g7a5tvx1188lenp5ih.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%2Fd7g7a5tvx1188lenp5ih.png" alt=" " width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without Lit, such interactions would be very hard to write manually. Due to the excellent interoperability of Web Components, I can use Lit when needed without completely replacing Rails View.&lt;/p&gt;

&lt;p&gt;I plan to update more content on Lit practices in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Finally, I recommend some resources.&lt;/p&gt;

&lt;p&gt;The best place to learn Lit is the official documentation: &lt;a href="https://lit.dev/docs/" rel="noopener noreferrer"&gt;https://lit.dev/docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adobe's UI library has a Web Component version: &lt;a href="https://opensource.adobe.com/spectrum-web-components/" rel="noopener noreferrer"&gt;https://opensource.adobe.com/spectrum-web-components/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The FontAwesome team is developing a UI library based on Web Components: &lt;a href="https://backers.webawesome.com/" rel="noopener noreferrer"&gt;https://backers.webawesome.com/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you need to develop interactive applications and don't want to replace the default Rails View stack, try Web Components / Lit.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Importmap or jsbundling? I use both</title>
      <dc:creator>Rei</dc:creator>
      <pubDate>Sat, 12 Oct 2024 14:29:24 +0000</pubDate>
      <link>https://dev.to/chloerei/importmap-or-jsbundling-i-use-both-47pd</link>
      <guid>https://dev.to/chloerei/importmap-or-jsbundling-i-use-both-47pd</guid>
      <description>&lt;p&gt;Starting from Rails 7, Importmap has become the default mechanism for handling JavaScript loading. It can fully utilize HTTP/2's parallel download and caching mechanisms, avoiding the need to download all code every time a change is made by bundling everything into one large package.&lt;/p&gt;

&lt;p&gt;For js dependencies, Importmap provides a &lt;code&gt;pin&lt;/code&gt; feature, for example, by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/importmap pin local-time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Importmap will download the &lt;code&gt;local-time&lt;/code&gt; js file from the CDN and place it in the &lt;code&gt;vendor/javascript&lt;/code&gt; directory, automatically adding the configuration to &lt;code&gt;config/importmap.rb&lt;/code&gt;. Then you can import it in your js file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import LocalTime from "local-time"
LocalTime.start()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, some js libraries assume developers will use bundling tools and do not package the source code into a complete bundle but instead split it into many files. In this case, using &lt;code&gt;importmap pin&lt;/code&gt; will encounter problems. For example, with Lit, if you execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/importmap pin lit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pinning "lit" to vendor/javascript/lit.js via download from https://ga.jspm.io/npm:lit@3.2.0/index.js
Pinning "@lit/reactive-element" to vendor/javascript/@lit/reactive-element.js via download from https://ga.jspm.io/npm:@lit/reactive-element@2.0.4/reactive-element.js
Pinning "lit-element/lit-element.js" to vendor/javascript/lit-element/lit-element.js.js via download from https://ga.jspm.io/npm:lit-element@4.1.0/lit-element.js
Pinning "lit-html" to vendor/javascript/lit-html.js via download from https://ga.jspm.io/npm:lit-html@3.2.0/lit-html.js
Pinning "lit-html/is-server.js" to vendor/javascript/lit-html/is-server.js.js via download from https://ga.jspm.io/npm:lit-html@3.2.0/is-server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that Lit references many sub-packages. The problem is that even after downloading so many packages, the import is still incomplete. If you &lt;code&gt;import { LitElement } from "lit"&lt;/code&gt; in your js code, you will get an error in the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://localhost:3000/assets/css-tag.js net::ERR_ABORTED 404 (Not Found)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because the &lt;code&gt;@lit/reactive-element&lt;/code&gt; package has many optional modules that were not downloaded. But if you download all optional modules, the importmap configuration will become very bloated. There is a PR in progress (&lt;a href="https://github.com/rails/importmap-rails/pull/235" rel="noopener noreferrer"&gt;#235&lt;/a&gt;), but it's hard to say if it will solve the problem because the issue lies in the library authors not considering the need for unbundled imports.&lt;/p&gt;

&lt;p&gt;So why not change the approach: first use jsbundling to bundle the dependencies, and then use importmap to import them. Here's how to achieve it.&lt;/p&gt;

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

&lt;p&gt;Assuming you have already created a project using Rails and are using importmap by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails new myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The code is tested on Rails 8.0.0.beta1 but should work for Rails 7+.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, install jsbundling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/bundle add jsbundling-rails
./bin/rails javascript:install:esbuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you will see js compilation errors because the default configurations of jsbundling and importmap conflict. Next, we will fix the conflicts.&lt;/p&gt;

&lt;p&gt;Remove this line from &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;javascript_include_tag&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"data-turbo-track"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"reload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify &lt;code&gt;package.json&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    "build": "esbuild app/assets/javascripts/*.* --bundle --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the path is changed to &lt;code&gt;app/assets/javascripts/*.*&lt;/code&gt;, which is the directory where js files that need to be compiled by esbuild will be placed in the future.&lt;/p&gt;

&lt;p&gt;Add the following to &lt;code&gt;config/application.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;excluded_paths&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"app/assets/javascripts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the folder &lt;code&gt;app/javascript/src/&lt;/code&gt; and add the file &lt;code&gt;app/assets/javascripts/lit.js&lt;/code&gt; with the content:&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="k"&gt;export&lt;/span&gt; &lt;span class="o"&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;lit&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;Install the lit package via yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add lit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following configuration to &lt;code&gt;config/importmap.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"lit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"lit.js"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now start the development process with &lt;code&gt;./bin/dev&lt;/code&gt;, and you will see esbuild compile lit to &lt;code&gt;app/assets/builds/lit.js&lt;/code&gt;. Open the browser and view the page source; the importmap content has increased:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "imports": {
    ...
    "lit": "/assets/lit-9c62c803.js",
    ...
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire workflow is: esbuild compiles the source code in &lt;code&gt;app/assets/javascripts&lt;/code&gt; to &lt;code&gt;app/assets/build&lt;/code&gt;, the content of &lt;code&gt;app/assets/build&lt;/code&gt; is processed by the assets pipeline, and the import name and file name mapping is added in &lt;code&gt;config/importmap.rb&lt;/code&gt;, so the module can be imported by the application's js code.&lt;/p&gt;

&lt;p&gt;Now, you can &lt;code&gt;import { LitElement } from "lit"&lt;/code&gt; in your js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This article uses a combination of esbuild and importmap to solve the problem of importmap being unable to handle complex dependencies. Although this breaks the expectation of nobuild, it still takes advantage of fine-grained caching. Until importmap is widely compatible with js packages, you can use this method to handle complex dependencies.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
