-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
110 lines (109 loc) · 15.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<!DOCTYPE html>
<!-- This file was auto-generated by exmd at 2023-03-31T21:35:38.899Z. Do NOT edit by hand! -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🧪 Vite + WebR + Pyodide + Lit</title><meta property="og:title" content="🧪 Vite + WebR + Pyodide + Lit">
<meta property="twitter:title" content="🧪 Vite + WebR + Pyodide + Lit">
<meta property="og:description" content="Better builds + lightweight components.">
<meta property="twitter:description" content="Better builds + lightweight components.">
<meta property="og:site" content="https://rud.is/w/vite-webr-lit">
<meta property="og:site_name" content="WebR Exeriments">
<meta property="og:image:url" content="https://rud.is/w/vite-webr-lit/preview.png">
<meta property="og:image:width" content="1014">
<meta property="og:image:height" content="836">
<meta property="og:image:alt" content="example">
<meta property="twitter:site_name" content="@hrbrmstr">
<meta property="twitter:domain" content="rud.is">
<meta property="twitter:card" content="summary_large_image">
<meta property="article:published_time" content="2023-03-31T21:35:38.900Z">
<link rel='apple-touch-icon' sizes='180x180' href='./favicon/apple-touch-icon.png'>
<link rel='icon' type='image/png' sizes='32x32' href='./favicon/favicon-32x32.png'>
<link rel='icon' type='image/png' sizes='16x16' href='./favicon/favicon-16x16.png'>
<link rel='manifest' href='./favicon/site.webmanifest'>
<link href='./src/index.css' rel='stylesheet'>
<link href='./src/components.css' rel='stylesheet'>
<script type='module' src='./src/main.js'></script>
</head>
<body>
<h1>🧪 🕸️ Vite + WebR + Pyodide + <img src="./src/assets/lit.svg" width="32" height="32" style="padding-left:4px;"/> Lit</h1>
<p><status-message id="webr-status" text="WebR Loading…"></status-message></p>
<p><button-with-raw-results id="r-button" label="Get some random numbers from" disabled></button-with-raw-results></p>
<h2>hrbrmstr, you need help</h2>
<p>Yes. Yes, I do.</p>
<p>There's nothing ZOMGOSH special in this latest experiment except that it is a fully working <a href="https://vitejs.dev/">Vite</a> + WebR + <a href="https://lit.dev/">Lit</a> Vanilla JS web app with <em>reusable</em> components that provides a button and output area.</p>
<p>The source uses this highly reusable component in it:</p>
<pre class="shiki " style="background-color: #0b0e14" tabindex="0"><code><span class="line"><span style="color: #39BAE680"><</span><span style="color: #39BAE6">button-with-raw-results</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #FFB454">id</span><span style="color: #BFBDB6"> </span><span style="color: #BFBDB6B3">=</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"r-button"</span><span style="color: #BFBDB6"> </span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #FFB454">label</span><span style="color: #BFBDB6"> </span><span style="color: #BFBDB6B3">=</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"Get some random numbers from"</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #FFB454">disabled</span></span>
<span class="line"><span style="color: #39BAE680">></</span><span style="color: #39BAE6">button-with-raw-results</span><span style="color: #39BAE680">></span></span>
<span class="line"></span></code></pre>
<p>We target it and wire up our <code>onClick</code> handler to it:</p>
<pre class="shiki " style="background-color: #0b0e14" tabindex="0"><code><span class="line"><span style="color: #FF8F40">const</span><span style="color: #BFBDB6"> rButton </span><span style="color: #F29668">=</span><span style="color: #BFBDB6"> document</span><span style="color: #F29668">.</span><span style="color: #FFB454">querySelector</span><span style="color: #BFBDB6">(</span><span style="color: #AAD94C">'#r-button'</span><span style="color: #BFBDB6">)</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"><span style="color: #BFBDB6">rButton</span><span style="color: #F29668">.</span><span style="color: #FFB454">onClick</span><span style="color: #BFBDB6"> </span><span style="color: #F29668">=</span><span style="color: #BFBDB6"> </span><span style="color: #FF8F40">async</span><span style="color: #BFBDB6"> () </span><span style="color: #FF8F40">=></span><span style="color: #BFBDB6"> {</span></span>
<span class="line"><span style="color: #BFBDB6"> rButton</span><span style="color: #F29668">.</span><span style="color: #BFBDB6">results </span><span style="color: #F29668">=</span><span style="color: #BFBDB6"> JSON</span><span style="color: #F29668">.</span><span style="color: #FFB454">stringify</span><span style="color: #BFBDB6">(</span><span style="color: #FF8F40">await</span><span style="color: #BFBDB6"> </span><span style="color: #FFB454">R</span><span style="color: #AAD94C">`sample(100, 5)`</span><span style="color: #BFBDB6">) </span><span style="color: #ACB6BF8C; font-style: italic">// *</span></span>
<span class="line"><span style="color: #BFBDB6">}</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"><span style="color: #BFBDB6">rButton</span><span style="color: #F29668">.</span><span style="color: #BFBDB6">disabled </span><span style="color: #F29668">=</span><span style="color: #BFBDB6"> </span><span style="color: #D2A6FF">false</span></span>
<span class="line"></span></code></pre>
<p><em>(*Notice the use of the <code>R</code> template tag function.)</em></p>
<p>That idiom lets us de-couple the "business logic" from the presentation layer.</p>
<p>You can look in <code>button-with-raw-results.js</code> for the full code, but one other addition which makes this component reusable is that we're using CSS variables for styling (not fully b/c I'm tired, but enough to get the idea):</p>
<pre class="shiki " style="background-color: #0b0e14" tabindex="0"><code><span class="line"><span style="color: #BFBDB6">:host div</span><span style="color: #F29668">.</span><span style="color: #BFBDB6">results</span><span style="color: #F29668">-</span><span style="color: #BFBDB6">output {</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #59C2FF">color</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #FF8F40">var</span><span style="color: #BFBDB6">(--results-color)</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"><span style="color: #BFBDB6"> font</span><span style="color: #F29668">-</span><span style="color: #59C2FF">family</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #FF8F40">var</span><span style="color: #BFBDB6">(--results-font-family)</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"><span style="color: #BFBDB6">}</span></span>
<span class="line"></span></code></pre>
<p>I added a <code>components.css</code> to set those two variables for this project:</p>
<pre class="shiki " style="background-color: #0b0e14" tabindex="0"><code><span class="line"><span style="color: #59C2FF">button-with-raw-results</span><span style="color: #BFBDB6"> {</span></span>
<span class="line"><span style="color: #BFBDB6"> --results-font-family</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">'Comic Code Ligatures'</span><span style="color: #BFBDB6B3">,</span><span style="color: #BFBDB6"> </span><span style="color: #F29668; font-style: italic">monospace</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"><span style="color: #BFBDB6"> --results-color</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #F07178">rgba</span><span style="color: #BFBDB6">(</span><span style="color: #F07178">var</span><span style="color: #BFBDB6">(--functional-green)</span><span style="color: #BFBDB6B3">,</span><span style="color: #BFBDB6"> </span><span style="color: #D2A6FF">1</span><span style="color: #BFBDB6">)</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"><span style="color: #BFBDB6">}</span></span>
<span class="line"></span></code></pre>
<h2>Vite Config</h2>
<p>The <code>vite.config.js</code> is worth talking about. Explanations are in-line:</p>
<pre class="shiki " style="background-color: #0b0e14" tabindex="0"><code><span class="line"><span style="color: #FF8F40">import</span><span style="color: #BFBDB6"> { defineConfig } </span><span style="color: #FF8F40">from</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">'vite'</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ACB6BF8C; font-style: italic">// this handles our ES6 modules using "top-level 'await'"</span></span>
<span class="line"><span style="color: #ACB6BF8C; font-style: italic">// for us without us having to code-up anything</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF8F40">import</span><span style="color: #BFBDB6"> topLevelAwait </span><span style="color: #FF8F40">from</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"vite-plugin-top-level-await"</span><span style="color: #BFBDB6B3">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ACB6BF8C; font-style: italic">// Ref:https://vitejs.dev/config/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF8F40">export</span><span style="color: #BFBDB6"> </span><span style="color: #FF8F40">default</span><span style="color: #BFBDB6"> </span><span style="color: #FFB454">defineConfig</span><span style="color: #BFBDB6">({</span></span>
<span class="line"><span style="color: #BFBDB6"> base</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">'/w/vite-webr-lit/'</span><span style="color: #BFBDB6B3">,</span><span style="color: #BFBDB6"> </span><span style="color: #ACB6BF8C; font-style: italic">// change this for your production deployment; vite will assum `/` if not</span></span>
<span class="line"><span style="color: #BFBDB6"> build</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> {</span></span>
<span class="line"><span style="color: #BFBDB6"> lib</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> {</span></span>
<span class="line"><span style="color: #BFBDB6"> entry</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">'index.html'</span><span style="color: #BFBDB6B3">,</span><span style="color: #BFBDB6"> </span><span style="color: #ACB6BF8C; font-style: italic">// doing this has Vite slurp up all resource references in it</span></span>
<span class="line"><span style="color: #BFBDB6"> formats</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> [</span><span style="color: #AAD94C">'es'</span><span style="color: #BFBDB6">]</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> }</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> rollupOptions</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> { </span><span style="color: #ACB6BF8C; font-style: italic">// we need lit on the server; this section is in here by default and not commented</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #ACB6BF8C; font-style: italic">// external: /^lit/,</span></span>
<span class="line"><span style="color: #BFBDB6"> }</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> }</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> plugins</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> [</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #FFB454">topLevelAwait</span><span style="color: #BFBDB6">({</span></span>
<span class="line"><span style="color: #BFBDB6"> promiseExportName</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"__tla"</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #FFB454">promiseImportName</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #D2A6FF">i</span><span style="color: #BFBDB6"> </span><span style="color: #FF8F40">=></span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">`__tla_</span><span style="color: #FF8F40">${</span><span style="color: #BFBDB6">i</span><span style="color: #FF8F40">}</span><span style="color: #AAD94C">`</span></span>
<span class="line"><span style="color: #BFBDB6"> })</span></span>
<span class="line"><span style="color: #BFBDB6"> ]</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> server</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> {</span></span>
<span class="line"><span style="color: #BFBDB6"> headers</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> { </span><span style="color: #ACB6BF8C; font-style: italic">// for serving locally</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"Cache-Control"</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"no-cache; max-age=1"</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"Cross-Origin-Embedder-Policy"</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"require-corp"</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"Cross-Origin-Opener-Policy"</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"same-origin"</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"Cross-Origin-Resource-Policy"</span><span style="color: #BFBDB6B3">:</span><span style="color: #BFBDB6"> </span><span style="color: #AAD94C">"cross-origin"</span><span style="color: #BFBDB6B3">,</span></span>
<span class="line"><span style="color: #BFBDB6"> }</span></span>
<span class="line"><span style="color: #BFBDB6"> }</span></span>
<span class="line"><span style="color: #BFBDB6">})</span></span>
<span class="line"></span></code></pre>
<p>The <code>justfile</code> has also been updated, accordingly.</p>
<p>If you use VS Code or some other environment that groks "Vite", it'll start a dev serve for you on load and automatically track file changes and reload on-the-fly.</p>
<p>You can use <code>just build</code> to make the <code>dist/</code> directory, then put that anywhere you like.</p>
<p>Oh, and the Pyodide support is in the sources on GH. Just uncomment out the obvious bits and you'll have that, too.</p>
<p>Source is on <a href="https://github.com/hrbrmstr/vite-webr-lit">GitHub</a></p>
<!-- extra body bits -->
</body>
</html>