<?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: Aaron Gong</title>
    <description>The latest articles on DEV Community by Aaron Gong (@aisone).</description>
    <link>https://dev.to/aisone</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%2F186344%2F019ed04d-d280-458d-887a-e7878f6282da.png</url>
      <title>DEV Community: Aaron Gong</title>
      <link>https://dev.to/aisone</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aisone"/>
    <language>en</language>
    <item>
      <title>Redoc With VueJS</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Fri, 21 Feb 2025 00:23:13 +0000</pubDate>
      <link>https://dev.to/aisone/redoc-with-vuejs-223a</link>
      <guid>https://dev.to/aisone/redoc-with-vuejs-223a</guid>
      <description>&lt;p&gt;Here is a very short post on using &lt;a href="https://github.com/Redocly/redoc" rel="noopener noreferrer"&gt;Redoc&lt;/a&gt; in &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;VueJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is a component you can use in any VueJS project. Remember to install &lt;code&gt;redoc&lt;/code&gt; and &lt;code&gt;null&lt;/code&gt; dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Redoc Sample&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"redoc-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// npm install redoc&lt;/span&gt;
&lt;span class="c1"&gt;// npm install null&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;redoc&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;redoc/bundles/redoc.standalone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// requires null package&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;onMounted&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;onMounted&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="nx"&gt;redoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://petstore.swagger.io/v2/swagger.json&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expandResponses&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;200,400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redoc-container&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="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>openapi</category>
      <category>redocly</category>
    </item>
    <item>
      <title>Caveat</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Thu, 14 Oct 2021 15:14:29 +0000</pubDate>
      <link>https://dev.to/aisone/caveat-4k7d</link>
      <guid>https://dev.to/aisone/caveat-4k7d</guid>
      <description>&lt;p&gt;There could be a potential web performance issue&lt;/p&gt;

&lt;p&gt;If you have 3 of the same custom components in your app, and the custom component has huge JS library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subheader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Component Test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NameViteVanilla&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;K1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NameViteVanilla&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;K2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NameViteVanilla&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;K3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could end up loading the library 3 times (see image below). Ouch!&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%2Fepghldl75xhdh899lt0w.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%2Fepghldl75xhdh899lt0w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Seems like the multiple reload of JS code also happens if &lt;code&gt;streamlit-aggrid&lt;/code&gt; is used.&lt;/p&gt;

&lt;p&gt;Code snippet below displaying 3 grids&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;grid_data1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AgGrid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;titanic_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ag1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gridOptions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gridOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;grid_data2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AgGrid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;titanic_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ag2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gridOptions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gridOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;grid_data3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AgGrid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;titanic_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ag3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gridOptions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gridOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Snapshot of browser network calls, showing the aggrid related JS file being called three times...&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%2Fmonluigpv44oqd88aj5o.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%2Fmonluigpv44oqd88aj5o.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I could be doing something wrong here though. So this definitely needs some investigation...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding @antv/g6 To Streamlit Custom Component</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Sat, 25 Sep 2021 03:57:02 +0000</pubDate>
      <link>https://dev.to/aisone/adding-antv-g6-to-streamlit-custom-components-e84</link>
      <guid>https://dev.to/aisone/adding-antv-g6-to-streamlit-custom-components-e84</guid>
      <description>&lt;h3&gt;
  
  
  Steps To Implement
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need to already create the vite vanilla JS custom component in &lt;a href="https://dev.to/aisone/streamlit-custom-components-vite-vanilla-js-40hl"&gt;part 2 or this series&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;From the &lt;code&gt;template&lt;/code&gt; folder &lt;/li&gt;
&lt;li&gt;Add the @antv/g9 library
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd vite_vanilla_component/frontend
npm i @antv/g6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;insert the code below just after &lt;code&gt;import { Streamlit } from 'streamlit-component-lib'&lt;/code&gt; on or near the top of the &lt;code&gt;main.js&lt;/code&gt; file
&lt;/li&gt;
&lt;/ul&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="nx"&gt;G6&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;@antv/g6&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;gdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;nodes&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&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="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;edges&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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;gdata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;th edge of A-B`&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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;gdata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;th edge of B-C`&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&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="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;G6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processParallelEdges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gdata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&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;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;scrollWidth&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;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;scrollHeight&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&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;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;G6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Graph&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// translate the graph to align the canvas's center, support by v3.5.1&lt;/span&gt;
  &lt;span class="na"&gt;fitCenter&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="c1"&gt;// the edges are linked to the center of source and target ndoes&lt;/span&gt;
  &lt;span class="na"&gt;linkCenter&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="na"&gt;defaultNode&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#5B8FF9&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#9EC9FF&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lineWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;labelCfg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&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="na"&gt;defaultEdge&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;quadratic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;labelCfg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;autoRotate&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="na"&gt;modes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;default&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="s1"&gt;drag-canvas&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="s1"&gt;drag-node&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;nodeStateStyles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fillOpacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lineWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&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;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gdata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;graph&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running
&lt;/h3&gt;

&lt;p&gt;The steps to run are the same as in previous &lt;a href="https://dev.to/aisone/streamlit-custom-components-vite-vanilla-js-40hl#running"&gt;article&lt;/a&gt; (right click and open new tab).&lt;/p&gt;

&lt;p&gt;You should see the following when navigating to the component url:&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%2Fwwwfsdjapzfmsm9w8z64.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%2Fwwwfsdjapzfmsm9w8z64.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Further Improvements
&lt;/h3&gt;

&lt;p&gt;The following are improvements that can be done once the code is added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow end-user to pass in g6 config, nodes and edges from python code&lt;/li&gt;
&lt;li&gt;Add graph event listeners to record last clicked node&lt;/li&gt;
&lt;li&gt;Modify the button to send last clicked node information back&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>streamlit</category>
      <category>g6</category>
    </item>
    <item>
      <title>Streamlit Custom Components + Vite + VueJS</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Thu, 23 Sep 2021 08:08:41 +0000</pubDate>
      <link>https://dev.to/aisone/streamlit-custom-components-vite-vuejs-58p4</link>
      <guid>https://dev.to/aisone/streamlit-custom-components-vite-vuejs-58p4</guid>
      <description>&lt;h2&gt;
  
  
  Create Component based on VueJS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;From the template folder&lt;/li&gt;
&lt;li&gt;Create new component using vite and add &lt;strong&gt;init&lt;/strong&gt;.py code for testing the component
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir vite_vue_component
$ cd vite_vue_component
$ npm init vite@latest frontend --template vue # npm v6 (v7 is different)
$ touch __init__.py # command may be different in Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add in the &lt;strong&gt;init&lt;/strong&gt;.py code below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamlit.components.v1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;

&lt;span class="n"&gt;_RELEASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_RELEASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;_component_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;declare_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vite_vue_component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# vite dev server port
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;parent_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;build_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&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="n"&gt;parent_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;frontend/dist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;_component_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;declare_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vite_vue_component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;build_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;component_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_component_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;component_value&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_RELEASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;
  &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subheader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Component Test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;num_clicks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NameViteVue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ve clicked %s times!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_clicks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;install the frontend node libraries, streamlit-component-lib, create vite.config.js
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd frontend
$ npm i
$ npm i streamlit-component-lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the following property to vite.config.js
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&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;ul&gt;
&lt;li&gt;replace App.vue file with the following code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;{{ msg }}&amp;lt;/h1&amp;gt;
    &amp;lt;button @click="doClick"&amp;gt;click&amp;lt;/button&amp;gt;
    &amp;lt;p&amp;gt;Count {{ count }}&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { Streamlit } from 'streamlit-component-lib'
import { ref, onMounted } from 'vue'

export default {
  setup(props, context) {
    const msg = ref('No Msg')
    const count = ref(0)

    const doClick = () =&amp;gt; {
      count.value += 1

      Streamlit.setComponentValue(count.value)
    }

    const onRender = (event) =&amp;gt; {
      const data = event.detail
      msg.value = `Hello, ` + data.args['name']
      Streamlit.setFrameHeight()
    }

    onMounted(() =&amp;gt; {
      Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRender)
      Streamlit.setComponentReady()
      Streamlit.setFrameHeight()
    })

    return {
      doClick,
      count,
      msg
    }
  }
}

&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the example
&lt;/h3&gt;

&lt;p&gt;From the base directory, navigate to the frontend and serve it from a dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd template/vite_vue_component/frontend
$ npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a separate terminal, from base directory, navigate to and run the Streamlit app (assuming python environment has been activated):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd template
$ streamlit run vite_vue_component/__init__.py  # run the example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the following image below. Button click will increment the count.&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%2Fetcu5ngi3ioqgyry6a59.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%2Fetcu5ngi3ioqgyry6a59.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>streamlit</category>
      <category>javascript</category>
      <category>vite</category>
    </item>
    <item>
      <title>Streamlit Custom Components + Vite + Vanilla JS</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Thu, 23 Sep 2021 08:08:20 +0000</pubDate>
      <link>https://dev.to/aisone/streamlit-custom-components-vite-vanilla-js-40hl</link>
      <guid>https://dev.to/aisone/streamlit-custom-components-vite-vanilla-js-40hl</guid>
      <description>&lt;h2&gt;
  
  
  Create Component Based On vanilla JS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;From the template folder&lt;/li&gt;
&lt;li&gt;Create new component using vite and add &lt;strong&gt;init&lt;/strong&gt;.py code for testing the component
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir vite_vanilla_component
$ cd vite_vanilla_component
$ npm init vite@latest frontend --template vanilla # npm v6 (v7 is different)
$ touch __init__.py # command may be different in Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add in the &lt;strong&gt;init&lt;/strong&gt;.py code below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamlit.components.v1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;

&lt;span class="n"&gt;_RELEASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_RELEASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;_component_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;declare_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vite_vanilla_component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# vite dev server port
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;parent_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;build_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&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="n"&gt;parent_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;frontend/dist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;_component_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;declare_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vite_vanilla_component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;build_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;component_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_component_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;component_value&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_RELEASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;
  &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subheader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Component Test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;num_clicks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NameViteVanilla&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ve clicked %s times!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_clicks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;install the frontend node libraries, streamlit-component-lib, create vite.config.js
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd frontend
$ npm i
$ npm i streamlit-component-lib
$ touch vite.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;vite.config.js should look like below
&lt;/li&gt;
&lt;/ul&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="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&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;ul&gt;
&lt;li&gt;replace the content of main.js with the following (based on the reactless-template of the original component-template repo)
&lt;/li&gt;
&lt;/ul&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;Streamlit&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;streamlit-component-lib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;span&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;textNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextNode&lt;/span&gt;&lt;span class="p"&gt;(&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;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Click Me!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;numClicks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isFocused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;numClicks&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;Streamlit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setComponentValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numClicks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onfocus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isFocused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onblur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isFocused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;onRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&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;borderStyling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`1px solid var(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
      &lt;span class="nx"&gt;isFocused&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--primary-color&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;gray&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;borderStyling&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;borderStyling&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;textNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;! `&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromCharCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Streamlit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrameHeight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Streamlit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&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="nx"&gt;Streamlit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RENDER_EVENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onRender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;Streamlit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setComponentReady&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;Streamlit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrameHeight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the example &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;From the base directory, navigate to the frontend and serve it from a dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;template/vite_vanilla_component/frontend
&lt;span class="nv"&gt;$ &lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a separate terminal, from base directory, navigate to and run the Streamlit app (assuming python environment has been activated):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;template
&lt;span class="nv"&gt;$ &lt;/span&gt;streamlit run vite_vanilla_component/__init__.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the image below, and clicking the button should increment the count.&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%2Fzu5shgr28rzv0xexaapn.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%2Fzu5shgr28rzv0xexaapn.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The component looks truncated. To fix this, set body style in the component to have &lt;code&gt;margin: 0;&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>streamlit</category>
      <category>javascript</category>
      <category>vite</category>
    </item>
    <item>
      <title>Streamlit Custom Components + Vite</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Thu, 23 Sep 2021 08:08:02 +0000</pubDate>
      <link>https://dev.to/aisone/streamlit-custom-components-vite-4bj7</link>
      <guid>https://dev.to/aisone/streamlit-custom-components-vite-4bj7</guid>
      <description>&lt;h2&gt;
  
  
  Why use vite?
&lt;/h2&gt;

&lt;p&gt;With vite you can build you streamlit custom components based on various frameworks supported by vite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vue&lt;/li&gt;
&lt;li&gt;react&lt;/li&gt;
&lt;li&gt;vanilla JS&lt;/li&gt;
&lt;li&gt;preact&lt;/li&gt;
&lt;li&gt;svelte&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For all the choices listed above, you are able to also chose to use them with Typescript.&lt;/p&gt;

&lt;p&gt;The initial steps is similar to the readme in the component-template repository.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/streamlit" rel="noopener noreferrer"&gt;
        streamlit
      &lt;/a&gt; / &lt;a href="https://github.com/streamlit/component-template" rel="noopener noreferrer"&gt;
        component-template
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Templates and example code for creating Streamlit Components
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Streamlit Component Templates&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This repo contains templates and example code for creating &lt;a href="https://streamlit.io" rel="nofollow noopener noreferrer"&gt;Streamlit&lt;/a&gt; Components.&lt;/p&gt;
&lt;p&gt;For complete information, please see the &lt;a href="https://docs.streamlit.io/en/latest/streamlit_components.html" rel="nofollow noopener noreferrer"&gt;Streamlit Components documentation&lt;/a&gt;!&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;A Streamlit Component is made out of a Python API and a frontend (built using any web tech you prefer).&lt;/p&gt;
&lt;p&gt;A Component can be used in any Streamlit app, can pass data between Python and frontend code, and and can optionally be distributed on &lt;a href="https://pypi.org/" rel="nofollow noopener noreferrer"&gt;PyPI&lt;/a&gt; for the rest of the world to use.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a component's API in a single line of Python:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;streamlit&lt;/span&gt;.&lt;span class="pl-s1"&gt;components&lt;/span&gt;.&lt;span class="pl-s1"&gt;v1&lt;/span&gt; &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;components&lt;/span&gt;

&lt;span class="pl-c"&gt;# Declare the component:&lt;/span&gt;
&lt;span class="pl-s1"&gt;my_component&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;components&lt;/span&gt;.&lt;span class="pl-en"&gt;declare_component&lt;/span&gt;(&lt;span class="pl-s"&gt;"my_component"&lt;/span&gt;, &lt;span class="pl-s1"&gt;path&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"frontend/build"&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Use it:&lt;/span&gt;
&lt;span class="pl-en"&gt;my_component&lt;/span&gt;(&lt;span class="pl-s1"&gt;greeting&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"Hello"&lt;/span&gt;, &lt;span class="pl-s1"&gt;name&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"World"&lt;/span&gt;)&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Build the component's frontend out of HTML and JavaScript (or TypeScript, or ClojureScript, or whatever you fancy). React is supported, but not required:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-smi"&gt;MyComponent&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/streamlit/component-template" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Clone the component-template repo
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/streamlit/component-template.git
$ cd component-template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a new Python virtual environment for the template
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# NOTE: the commands may differ (eg. python3 instead of python)&lt;/span&gt;
&lt;span class="c"&gt;# due to the way your python is installed, or your OS&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;template
&lt;span class="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv my_venv  &lt;span class="c"&gt;# create venv&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; my_venv/bin/activate   &lt;span class="c"&gt;# activate venv&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;streamlit &lt;span class="c"&gt;# install streamlit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you are done, from here on, we start creating our custom components.&lt;/p&gt;

</description>
      <category>python</category>
      <category>vue</category>
      <category>streamlit</category>
      <category>vite</category>
    </item>
    <item>
      <title>FastAPI + SAML on Keycloak</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Sat, 26 Jun 2021 04:37:01 +0000</pubDate>
      <link>https://dev.to/zenika/fastapi-saml-on-keycloak-49l6</link>
      <guid>https://dev.to/zenika/fastapi-saml-on-keycloak-49l6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL:DR; a quick article to help FastAPI users get SAML working on their application.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The code and instructions are found at &lt;a href="https://github.com/ais-one/fastapi-saml"&gt;https://github.com/ais-one/fastapi-saml&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less than 100 lines of code&lt;/li&gt;
&lt;li&gt;Only 4 dependencies to install&lt;/li&gt;
&lt;li&gt;Requirements and setup are all documented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there is a problem please raise an issue, so that documentation and code can be improved.&lt;/p&gt;




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

&lt;p&gt;This may look like a very short article but to get this working took quite a lot of time and effort...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;searching on Google and Stack-Overflow&lt;/li&gt;
&lt;li&gt;choosing which library to use&lt;/li&gt;
&lt;li&gt;digging into the library itself to find out what went wrong&lt;/li&gt;
&lt;li&gt;many trial and error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you and hope it is helpful to you.&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>saml</category>
      <category>keycloak</category>
      <category>python</category>
    </item>
    <item>
      <title>Setup MongoDB On WSL Ubuntu 18.04</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Mon, 20 Apr 2020 08:20:46 +0000</pubDate>
      <link>https://dev.to/zenika/setup-mongodb-on-wsl-ubuntu-18-04-167</link>
      <guid>https://dev.to/zenika/setup-mongodb-on-wsl-ubuntu-18-04-167</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;This article will cover the use of MongoDB on WSL (Windows Subsytem For Linux) Ubuntu. Other than installation and we will cover some caveats, use cases such as migration, upgrade process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ADVISORY:&lt;/strong&gt; Do not use WSL for production. We are only using it here to learn how to use Ubuntu OS version of MongoDB - on a windows machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;The are 2 commonly used packages available for MongoDB on Ubuntu&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mongodb&lt;/li&gt;
&lt;li&gt;mongodb-org&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;mongodb-org&lt;/strong&gt; is the package described in official &lt;a href="https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/"&gt;MongoDB&lt;/a&gt; documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  mongodb
&lt;/h2&gt;

&lt;p&gt;If you use &lt;strong&gt;mongodb&lt;/strong&gt; package, you will be able to install easily and run smoothly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;mongodb
&lt;span class="nb"&gt;sudo &lt;/span&gt;service mongodb start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the current version installed is 3.6 and you will miss out on using MongoDB Transactions introduced from 4.0 onwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  mongodb-org
&lt;/h2&gt;

&lt;p&gt;For &lt;strong&gt;mongodb-org&lt;/strong&gt; package, although you can install and manually run the latest stable version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Even though official documentation says MongoDB is not supported on WSL, you can still try and install.&lt;/p&gt;

&lt;p&gt;However, the service will not be able to install (I suspect due to WSL Ubuntu only supporting system V init). You will get the following error if you try to run the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service mongod start
initctl: Unable to connect to Upstart: Failed to connect to socket /com/ubuntu/upstart: Connection refused
mongod: unrecognized service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running as a service issue can be fixed by following the steps in &lt;a href="https://github.com/microsoft/WSL/issues/796#issuecomment-611626709"&gt;this github comment&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You manually create the service using the following script &lt;a href="https://raw.githubusercontent.com/mongodb/mongo/master/debian/init.d"&gt;https://raw.githubusercontent.com/mongodb/mongo/master/debian/init.d&lt;/a&gt;, and now you can use...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service mongod start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Which One To Use
&lt;/h2&gt;

&lt;p&gt;This will depend on your requirements. If you need to use an updated version, use &lt;strong&gt;mongodb-org&lt;/strong&gt;. If you need something quick and easy to install, use &lt;strong&gt;mongodb&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;NOTE: the configuration file names are different for each package&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mongodb - /etc/&lt;strong&gt;mongodb&lt;/strong&gt;.conf&lt;/li&gt;
&lt;li&gt;mongodb-org - /etc/&lt;strong&gt;mongod&lt;/strong&gt;.conf&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Data Migration / Backup / Restore
&lt;/h1&gt;

&lt;p&gt;As mentioned in the official MongoDB documents &lt;a href="https://docs.mongodb.com/manual/core/backups/"&gt;https://docs.mongodb.com/manual/core/backups/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting from MongoDB 4.2, &lt;strong&gt;mongodump&lt;/strong&gt; should not be used as part of backup strategy if you are using &lt;strong&gt;sharded clusters and transactions in progress&lt;/strong&gt;. Use the other recommended methods instead.&lt;/p&gt;

&lt;p&gt;However, in a development environment, you can use &lt;strong&gt;mongodump&lt;/strong&gt; and &lt;strong&gt;mongorestore&lt;/strong&gt; to backup, restore and migrate data and indexes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# backup&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mongodump &lt;span class="nt"&gt;--archive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my_dump

&lt;span class="c"&gt;# do some upgrade&lt;/span&gt;

&lt;span class="c"&gt;# restore&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mongorestore &lt;span class="nt"&gt;--archive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my_dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Setting Up Replication Set
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://docs.mongodb.com/manual/replication/"&gt;Replication&lt;/a&gt; is used to provide redundancy and high-availibility. They are also required if you are need to use &lt;a href="https://docs.mongodb.com/manual/core/transactions/"&gt;Transactions&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Config File Changes
&lt;/h3&gt;

&lt;p&gt;In /etc/mongod.conf (mongodb-org package), set the replication.replSetName property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;replication:
   oplogSizeMB: &amp;lt;int&amp;gt;
   replSetName: &amp;lt;string&amp;gt;
   enableMajorityReadConcern: &amp;lt;boolean&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the service after changes are made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start Replication
&lt;/h3&gt;

&lt;p&gt;Connect to MongoDB using the  &lt;strong&gt;mongo&lt;/strong&gt; client and start up or check for replication set using the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# start up replica set&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rs.initiate&lt;span class="o"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;# check replica set status&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rs.status&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;There are many more topics to cover for MongoDB, especially for running smoothly in a production environment.&lt;/p&gt;

&lt;p&gt;Some topics to cover include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Sharding&lt;/li&gt;
&lt;li&gt;Change streams&lt;/li&gt;
&lt;li&gt;Administration&lt;/li&gt;
&lt;li&gt;MongoDB internals and storage engines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an alternative to doing it all by yourself, you can use Mongo Atlas and leave the operational work to others while you focus on your business data and logic.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Caveats When Choosing 3rd Party Libraries For Your Application</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Sun, 29 Mar 2020 23:35:45 +0000</pubDate>
      <link>https://dev.to/zenika/caveats-when-choosing-3rd-party-libraries-for-your-application-3g3e</link>
      <guid>https://dev.to/zenika/caveats-when-choosing-3rd-party-libraries-for-your-application-3g3e</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;This is the first of a series of articles providing insights on choosing 3rd party libraries.&lt;/p&gt;

&lt;p&gt;There are caveats and pitfalls to be aware of which may have a huge impact on your application, such as complete code rewrites, resource usage, etc.&lt;/p&gt;

&lt;p&gt;Such caveats might have overlooked, not stated on the documentation, or hidden somewhere in the issues list.&lt;/p&gt;

&lt;p&gt;Hence, one has to do their due diligence when choosing 3rd party libraries and study their ABCs (architecture, behavior and codes) before using them.&lt;/p&gt;

&lt;p&gt;Some of actions to take before on-boarding a library are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;searching online for more information, reviews, comparison with alternatives&lt;/li&gt;
&lt;li&gt;looking into the issues list&lt;/li&gt;
&lt;li&gt;going through the code and dependencies (if library is opensource)&lt;/li&gt;
&lt;li&gt;testing out with debugging tools, monitor console, network requests, slow network conditions&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  The Caveat
&lt;/h1&gt;

&lt;p&gt;"Hidden" performance issues. On the surface the library may look to be working well.&lt;/p&gt;

&lt;p&gt;However, it may be written in a way that can cause usability problems in poor network environment, as we shall see...&lt;/p&gt;




&lt;h1&gt;
  
  
  The Example
&lt;/h1&gt;

&lt;p&gt;Here we look at a feature rich phone number input library &lt;a href="https://github.com/LouisMazel/vue-phone-number-input"&gt;vue-phone-number-input&lt;/a&gt; and its &lt;a href="https://louismazel.github.io/vue-phone-number-input/"&gt;demo site&lt;/a&gt;. &lt;strong&gt;NOTE:&lt;/strong&gt; A few other Javascript country flag selection libraries has the same caveat too!&lt;/p&gt;

&lt;p&gt;The evaluation on the demo site was performed on &lt;strong&gt;18 March 2019 1130Hrs +8GMT&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rVI4Lqpq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iu74gu621xdc4ee3i6jf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rVI4Lqpq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iu74gu621xdc4ee3i6jf.png" alt="gotcha - initial load"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The initial load looks alright, with only a few requests fired.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Issue
&lt;/h1&gt;

&lt;p&gt;When you click the country dropdown with flag, you see many HTTP requests (refer to image below). There are about &lt;strong&gt;240&lt;/strong&gt; of them, each of them representing a country flag.&lt;/p&gt;

&lt;p&gt;This can be a problem on slow or intermittent networks. Also seeing 240 requests  being made on a single click just does not look professional.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HwWlqwE---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/48lu8jnns6wtvz56tigq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HwWlqwE---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/48lu8jnns6wtvz56tigq.png" alt="gotcha - flags load"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Some Suggestions
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Look for similar libraries that uses Intersection Observer to lazy load the images, or load the images as a single image and then use offsets to get the portion you need. You basically want to reduce the number of requests&lt;/li&gt;
&lt;li&gt;Learn more about i18n in-depth. Countries and flags are politically sensitive, some libraries have different list of "recognized countries"&lt;/li&gt;
&lt;li&gt;You also need to consider number and date formats, LTR or RTL, character sets, etc. Balancing application size and language support&lt;/li&gt;
&lt;li&gt;Try to go Native as much as possible&lt;/li&gt;
&lt;li&gt;Consider CSS customization flexibility and frontend UI being used&lt;/li&gt;
&lt;li&gt;Worst case, you may need to implement your own better solution... really!&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thank you for taking you time to read this article. Hope it has provided you some useful insights.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>VueJS+NodeJS Evergreen Cookbook</title>
      <dc:creator>Aaron Gong</dc:creator>
      <pubDate>Wed, 24 Jul 2019 02:48:40 +0000</pubDate>
      <link>https://dev.to/aisone/vuejs-expressjs-crud-cookbook-46l0</link>
      <guid>https://dev.to/aisone/vuejs-expressjs-crud-cookbook-46l0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Cookbook Rule #1 - Do Not Build Up Technical Debt&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As developers we create different applications. Along the way, we come up with code recipes for ORMs, GraphQL, SSO, charts, OpenAPI, Vue/React SPA, etc.&lt;/p&gt;

&lt;p&gt;These recipes solve real world problems and can be reused elsewhere!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Evergreen Cookbook Project
&lt;/h2&gt;

&lt;p&gt;The project originally began life as a &lt;a href="https://medium.com/@aaronjxz/vue-crud-x-a-highly-customisable-crud-component-using-vuejs-and-vuetify-2b1539ce2054" rel="noopener noreferrer"&gt;CRUD Component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As more and more functionality and codes were added, the code "recipes" were consolidated in a "Cookbook" for future use.&lt;/p&gt;

&lt;p&gt;If you just want to dive in, visit the &lt;strong&gt;&lt;a href="https://github.com/ais-one/cookbook" rel="noopener noreferrer"&gt;project&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ais-one" rel="noopener noreferrer"&gt;
        ais-one
      &lt;/a&gt; / &lt;a href="https://github.com/ais-one/cookbook" rel="noopener noreferrer"&gt;
        cookbook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      VueJS + NodeJS Evergreen Cookbook
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/49dcab8a544eda11ea59795ed5741ac052d1dc2e4c66b6b9fbeb54cda85cd977/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6173742d636f6d6d69742f6169732d6f6e652f636f6f6b626f6f6b2f6d6173746572"&gt;&lt;img src="https://camo.githubusercontent.com/49dcab8a544eda11ea59795ed5741ac052d1dc2e4c66b6b9fbeb54cda85cd977/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6173742d636f6d6d69742f6169732d6f6e652f636f6f6b626f6f6b2f6d6173746572" alt="master commit"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a772cf8424f7a6d35baffe3192d9774fc51c0c8237806cad2694ad7ddc229d58/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6169732d6f6e652f636f6f6b626f6f6b"&gt;&lt;img src="https://camo.githubusercontent.com/a772cf8424f7a6d35baffe3192d9774fc51c0c8237806cad2694ad7ddc229d58/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6169732d6f6e652f636f6f6b626f6f6b" alt="release"&gt;&lt;/a&gt;
&lt;a href="https://badge.fury.io/js/cookbook" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c9663af6d646bb7d216bb02e15ae55b8710e5215328d58738136d03d6c727ae6/68747470733a2f2f62616467652e667572792e696f2f6a732f636f6f6b626f6f6b2e737667" alt="npm version"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/cookbook" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c5a9a9909288cfe972230b273c9ad8615ec6eabdfc915990a608f7cdbc79fa01/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f636f6f6b626f6f6b2e737667" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/dashboard?id=com.lapots.breed.judge:judge-rule-engine" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d26950ab964fd1db5113a3e6eecad966dc50b54ac3b915c21969de04f64eb3a9/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d636f6d2e6c61706f74732e62726565642e6a756467653a6a756467652d72756c652d656e67696e65266d65747269633d616c6572745f737461747573" alt="Sonarcloud Status"&gt;&lt;/a&gt;
&lt;a href="https://snyk.io/test/github/ais-one/cookbook" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ecdb64a58ea38b48b4a50d57ded1f7b2afab8cf93fd64d76c78f132b2997f367/68747470733a2f2f736e796b2e696f2f746573742f6769746875622f6169732d6f6e652f636f6f6b626f6f6b2f62616467652e737667" alt="Known Vulnerabilities"&gt;&lt;/a&gt;
&lt;a href="https://madewithvuejs.com/p/cookbook/shield-link" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8d04aeb21cf0e08116e3287665bfbe732582e2b5f71eacfa30ee8b85dc309016/68747470733a2f2f6d616465776974687675656a732e636f6d2f73746f726167652f7265706f2d736869656c64732f3832332d736869656c642e737667" alt="MadeWithVueJs.com shield"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1 - IMPORTANT - Read Me First!&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;templates&lt;/code&gt; (express and vuejs template) and &lt;code&gt;libraries&lt;/code&gt; (shareable libraries and tools) projects referenced in the &lt;a href="https://github.com/ais-one/cookbookrecipes/README.md" rel="noopener noreferrer"&gt;Recipes&lt;/a&gt; are based on the two principles below.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1.1 - Updateable Templates&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Your project is created using a template. If template updates, can upstream changes be merged with minimal impact on userland codes?&lt;/p&gt;
&lt;p&gt;Yes and it is achieved through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design
&lt;ul&gt;
&lt;li&gt;Create folder where all userland code is placed, template must NOT touch this folder&lt;/li&gt;
&lt;li&gt;template should not to be part of a monorepo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Process
&lt;ul&gt;
&lt;li&gt;clone template and create remote called &lt;code&gt;upstream&lt;/code&gt; pointing to template&lt;/li&gt;
&lt;li&gt;update framework when necessary by merging &lt;code&gt;upstream&lt;/code&gt; into &lt;code&gt;origin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1.2 - Manageable Sharing&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;You have code shared between multiple projects and libraries. If the code is updated, is breaking dependents and dependencies avoidable?&lt;/p&gt;
&lt;p&gt;Yes, based on the following principles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shared libraries should be isolated and versioned. Use last-known-good version and update when ready&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ais-one/cookbook" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Considerations
&lt;/h2&gt;

&lt;p&gt;The recipes must be continuously maintained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding new recipes and removing obsolete ones&lt;/li&gt;
&lt;li&gt;updating and improving existing recipes (e.g. cleaner code)&lt;/li&gt;
&lt;/ul&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%2Feslf52psca2bwyt843rw.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%2Feslf52psca2bwyt843rw.png" alt="Charts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also should bear in mind the following which have impact on cookbook users:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make it easy for users to build and maintain multiple projects based on the cookbook&lt;/li&gt;
&lt;li&gt;make it easy for users to update their projects when cookbook recipes are updated&lt;/li&gt;
&lt;li&gt;easy to deploy using CI/CD, containers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Recipes
&lt;/h2&gt;

&lt;p&gt;Some available recipes in the cookbook are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL &amp;amp; subscriptions&lt;/li&gt;
&lt;li&gt;SAML2, OpenID Connect, OAuth social logins, JWT, refresh token, 2FA/TOTP&lt;/li&gt;
&lt;li&gt;Multi-part forms, file uploads, signup uploads&lt;/li&gt;
&lt;li&gt;REST, OpenAPI documentation and validation&lt;/li&gt;
&lt;li&gt;Web components - Webcam, Canvas inputs, CRUD table&lt;/li&gt;
&lt;li&gt;MongoDB, replication, transactions, streams&lt;/li&gt;
&lt;li&gt;SQL Query Builders, migration, seed&lt;/li&gt;
&lt;li&gt;cors, body parser, helmet, connect-api-history-fallback&lt;/li&gt;
&lt;li&gt;Automated testing&lt;/li&gt;
&lt;li&gt;Visualization (Charts, Maps, etc.)&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;/ul&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%2Fp00tz2fe37nws32okls4.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%2Fp00tz2fe37nws32okls4.png" alt="Signin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find out how each recipe works by checking out, building, and running the code while referencing the project documents.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cookbook Web Frontend Type
&lt;/h2&gt;

&lt;p&gt;There are 3 ways to build a web frontend application&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single Page Application (SPA)&lt;/li&gt;
&lt;li&gt;Server-Side Rendered (SSR)&lt;/li&gt;
&lt;li&gt;Static Sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The table below shows the comparison between the 3 ways. &lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://www.slideshare.net/slideshow/embed_code/key/anHVp5aFN2MvLL" alt="anHVp5aFN2MvLL on slideshare.net" width="100%" height="487"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;After comparing the feature of each way, the decision was to focus on SPA and Static Sites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Some Historical Notes
&lt;/h2&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%2Fk4v7glzud44nvxozx1mr.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%2Fk4v7glzud44nvxozx1mr.png" alt="Table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A CRUD component was developed in late 2017 due to a desire to create a better table editor using VueJS 2 and Vuetify 1.&lt;/li&gt;
&lt;li&gt;A backend project and authentication was added as this was needed. Features and applications start getting added, updated, removed.&lt;/li&gt;
&lt;li&gt;Vuetify 2 (3Q 2019) introduced breaking changes. Hence the need to look at more stable or reduced number of dependencies.&lt;/li&gt;
&lt;li&gt;Backend structure was re-organized to allow same codebase on multiple projects.&lt;/li&gt;
&lt;li&gt;Project was again re-organized when docker and CI/CD had to be taken into account.&lt;/li&gt;
&lt;li&gt;With ES Modules introduced, a no bundler version of the frontend was created. The CRUD UI was also migrated to a use Web Components and Bulma CSS.&lt;/li&gt;
&lt;li&gt;Docker compose files for applications such as DB, Redis, Kafka, Vault were added to support local development.&lt;/li&gt;
&lt;li&gt;Vue3 broke Vue2 plugins, fortunately the project did not use many plugins (it used libraries like leafletJS directly instead). The migration was quite painless.&lt;/li&gt;
&lt;li&gt;Escaped much pain when VueJS and its 3rd party libraries update, e.g.:

&lt;ul&gt;
&lt;li&gt;vee-validate v1 -&amp;gt; v2 -&amp;gt; v3 -&amp;gt; v4 (keeps breaking)&lt;/li&gt;
&lt;li&gt;vue-apollo (cannot use for Vue3 yet)&lt;/li&gt;
&lt;li&gt;vue-rx (cannot use for Vue3 yet)&lt;/li&gt;
&lt;li&gt;vuetify v1 -&amp;gt; v2 -&amp;gt; v3 (keeps breaking)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Experience with a sister &lt;a href="https://github.com/ais-one/favv" rel="noopener noreferrer"&gt;project&lt;/a&gt; helped in addressing cookbook user considerations stated above.&lt;/li&gt;

&lt;li&gt;Now awaiting npm workspaces in the upcoming NodeJS 16 LTS release... and focus on project stability.&lt;/li&gt;

&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ais-one" rel="noopener noreferrer"&gt;
        ais-one
      &lt;/a&gt; / &lt;a href="https://github.com/ais-one/favv" rel="noopener noreferrer"&gt;
        favv
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Fullstack Web Application Framework With FastAPI + Vite + VueJS. Streamlit for rapid development.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;Hope you find the cookbook project, and its recipes helpful.&lt;/p&gt;

&lt;p&gt;The cookbook is continuously being updated and improved to remain relevant and useful.&lt;/p&gt;

&lt;p&gt;We are looking for contributors and maintainers to continuously make it better.&lt;/p&gt;

&lt;p&gt;Thank you for taking your time to read this.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>graphql</category>
      <category>node</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
