<?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: kasu</title>
    <description>The latest articles on DEV Community by kasu (@ergofriend).</description>
    <link>https://dev.to/ergofriend</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%2F1129009%2F0ff89182-d2ae-4a2b-8206-31a0a5b621de.png</url>
      <title>DEV Community: kasu</title>
      <link>https://dev.to/ergofriend</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ergofriend"/>
    <language>en</language>
    <item>
      <title>eval() with WASM instead of sandbox with Web Extensions</title>
      <dc:creator>kasu</dc:creator>
      <pubDate>Wed, 30 Oct 2024 11:27:09 +0000</pubDate>
      <link>https://dev.to/ergofriend/eval-with-wasm-instead-of-sandbox-with-web-extensions-3icm</link>
      <guid>https://dev.to/ergofriend/eval-with-wasm-instead-of-sandbox-with-web-extensions-3icm</guid>
      <description>&lt;h4&gt;
  
  
  in 4 lines
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Manifest V3 is now required for &lt;code&gt;eval()&lt;/code&gt; in Chrome extensions, so you need to use sandbox.&lt;/li&gt;
&lt;li&gt;Firefox without sandbox can use &lt;code&gt;unsafe-eval&lt;/code&gt; by reverting to V2...&lt;/li&gt;
&lt;li&gt;Chrome and Firefox have different implementations, and I don't want to have a security gap between the two :(&lt;/li&gt;
&lt;li&gt;Yes, let's succes with QuickJS(WASM)!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I am working on a Web Extension&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;What this extension provided was Google search and YouTube/X site search. These implementations were hard-coded.&lt;/p&gt;

&lt;p&gt;We wanted to avoid having to make a release for every variation, so we were looking for a means for users to set up their own arbitrary site search or favorite search engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Policy
&lt;/h3&gt;

&lt;p&gt;Based on the above background, we have decided to provide a function that allows users to register a function that can be used to process and copy URLs and page content, such as in Cocopy&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. We decided to provide a function that allows users to register functions they have entered.&lt;/p&gt;

&lt;p&gt;Basically, the function entered by the user is in string form, and the browser has a function called &lt;code&gt;eval()&lt;/code&gt;&lt;sup id="fnref3"&gt;3&lt;/sup&gt; is built in.&lt;/p&gt;

&lt;p&gt;However, extensions are limited by &lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.%20json/content_security_policy#browser_compatibility" rel="noopener noreferrer"&gt;content_security_policy - Mozilla | MDN&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extension &lt;code&gt;eval()&lt;/code&gt; Fact
&lt;/h2&gt;

&lt;p&gt;First, the extension has a version specification called Manifest.&lt;/p&gt;

&lt;p&gt;Chrome is only available in V3, while Firefox currently allows you to choose between V2 and V3, whichever you prefer.&lt;br&gt;
The basic &lt;code&gt;eval()&lt;/code&gt; method differs depending on the version.&lt;/p&gt;
&lt;h3&gt;
  
  
  Manifest V3
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.chrome.com/docs/extensions/how-to/security/sandboxing-eval?%20hl=en" rel="noopener noreferrer"&gt;Using eval() in a sandboxed iframe | Chrome for Developers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V3 does not allow direct use of &lt;code&gt;eval()&lt;/code&gt;, so the method via sandbox is guided.&lt;br&gt;
However, this is not the case in Firefox&lt;sup id="fnref4"&gt;4&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Manifest V2
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"content_security_policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script-src 'self' 'unsafe-eval'; object-src 'self';"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In V2, &lt;code&gt;eval()&lt;/code&gt; can be used by specifying &lt;code&gt;unsafe-eval&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, as the dangers of &lt;code&gt;eval()&lt;/code&gt; are widely known, it is a method to be avoided if at all possible.&lt;/p&gt;
&lt;h3&gt;
  
  
  Here's what's wrong with the general method
&lt;/h3&gt;

&lt;p&gt;Chrome requires V3, so it is sandboxed, and Firefox does not have a sandbox, so it is naturally fixed to the &lt;code&gt;unsafe-eval&lt;/code&gt; implementation in V2.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different implementations between Chrome and Firefox can be a maintenance cost&lt;/li&gt;
&lt;li&gt;Security gap between sandbox and unsafe-eval&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  WASM may be an option.
&lt;/h3&gt;

&lt;p&gt;There is a JavaScript engine called QuickJS&lt;sup id="fnref5"&gt;5&lt;/sup&gt; made in C. engine made in C.&lt;/p&gt;

&lt;p&gt;If this can be called from an extension as a WASM Module, the same implementation can be used in both Chrome and Firefox, and security can be ensured.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Thankfully, a WASM build of QuickJS and a client for the JavaScript environment were available, so we were able to use these.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/justjake" rel="noopener noreferrer"&gt;
        justjake
      &lt;/a&gt; / &lt;a href="https://github.com/justjake/quickjs-emscripten" rel="noopener noreferrer"&gt;
        quickjs-emscripten
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Safely execute untrusted Javascript in your Javascript, and execute synchronous code that uses async functions
    &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;quickjs-emscripten&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Javascript/Typescript bindings for QuickJS, a modern Javascript interpreter
compiled to WebAssembly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Safely evaluate untrusted Javascript (supports &lt;a href="https://test262.fyi/#%7Cqjs,qjs_ng" rel="nofollow noopener noreferrer"&gt;most of ES2023&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Create and manipulate values inside the QuickJS runtime (&lt;a href="https://github.com/justjake/quickjs-emscripten#interfacing-with-the-interpreter" rel="noopener noreferrer"&gt;more&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Expose host functions to the QuickJS runtime (&lt;a href="https://github.com/justjake/quickjs-emscripten#exposing-apis" rel="noopener noreferrer"&gt;more&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Execute synchronous code that uses asynchronous functions, with &lt;a href="https://github.com/justjake/quickjs-emscripten#asyncify" rel="noopener noreferrer"&gt;asyncify&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Supports browsers, NodeJS, Deno, Bun, Cloudflare Workers, QuickJS (via &lt;a href="https://github.com/justjake/quickjs-emscripten/blob/main/packages/quickjs-for-quickjs" rel="noopener noreferrer"&gt;quickjs-for-quickjs&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://github.com/justjake/quickjs-emscripten" rel="noopener noreferrer"&gt;Github&lt;/a&gt; | &lt;a href="https://www.npmjs.com/package/quickjs-emscripten" rel="nofollow noopener noreferrer"&gt;NPM&lt;/a&gt; | &lt;a href="https://github.com/justjake/quickjs-emscripten/blob/main/doc/packages.md" rel="noopener noreferrer"&gt;API Documentation&lt;/a&gt; | &lt;a href="https://github.com/justjake/quickjs-emscripten/blob/main/doc/quickjs-emscripten-core/README.md" rel="noopener noreferrer"&gt;Variants&lt;/a&gt; | &lt;a href="https://github.com/justjake/quickjs-emscripten/blob/main/packages/quickjs-emscripten/src/quickjs.test.ts" rel="noopener noreferrer"&gt;Examples&lt;/a&gt;&lt;/p&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;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;getQuickJS&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"quickjs-emscripten"&lt;/span&gt;
&lt;span class="pl-k"&gt;async&lt;/span&gt; &lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;main&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;QuickJS&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;getQuickJS&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;vm&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;QuickJS&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;newContext&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;

  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;world&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;vm&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;newString&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"world"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-s1"&gt;vm&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;setProp&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;vm&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;global&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;"NAME"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;world&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-s1"&gt;world&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;dispose&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;

  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;vm&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;evalCode&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;`"Hello " + NAME + "!"`&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;result&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;error&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-smi"&gt;console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;log&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/justjake/quickjs-emscripten" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The default method in the documentation fetches the WASM Module remotely, so the extension must import it directly to bundle the main body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;variant&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;@jitl/quickjs-singlefile-browser-release-sync&lt;/span&gt;&lt;span class="dl"&gt;"&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;newQuickJSWASMModuleFromVariant&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;quickjs-emscripten-core&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;QuickJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;newQuickJSWASMModuleFromVariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;variant&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;QuickJS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evalCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1 + 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For user input, we asked the user to define an anonymous function, which was immediately executed and evaluated.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
({keyword}) =&amp;gt; {
return "https://www.google.com/search?q=" + keyword
}`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QuickJS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evalCode&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;inputCode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)({ keyword: "Golang"})`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.google.com/search?q=Golang&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;h3&gt;
  
  
  Reference Implementation
&lt;/h3&gt;

&lt;p&gt;This is a pull request for actual incorporation into the extension.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/ergofriend/Quiqsearch/pull/10" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add custom filter
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#10&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/ergofriend" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F29725082%3Fv%3D4" alt="ergofriend avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/ergofriend" rel="noopener noreferrer"&gt;ergofriend&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/ergofriend/Quiqsearch/pull/10" rel="noopener noreferrer"&gt;&lt;time&gt;Oct 10, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I have improved the search methods for user.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] Browser's default search engine&lt;/li&gt;
&lt;li&gt;[x] Building custom search url&lt;/li&gt;
&lt;li&gt;[x] Escape hatch for custom filters&lt;/li&gt;
&lt;li&gt;[x] Sorting custom filters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/db2e9f16-8c55-47d2-9800-0b8b4ed9f660"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fdb2e9f16-8c55-47d2-9800-0b8b4ed9f660" alt="CleanShot 2024-10-13 at 15 05 53@2x"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ergofriend/Quiqsearch/pull/10" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;






&lt;p&gt;This article is a translation from Japanese.&lt;br&gt;
&lt;a href="https://ergofriend.hatenablog.com/entry/2024/10/17/005830" rel="noopener noreferrer"&gt;https://ergofriend.hatenablog.com/entry/2024/10/17/005830&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="//https://%20github.com/ergofriend/Quiqsearch"&gt;ergofriend/Quiqsearch: A chrome extension. Quickly search for the Selected text on the Web.&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://github.com/pokutuna/chrome-cocopy" rel="noopener noreferrer"&gt;pokutuna/chrome-cocopy: chrome extension to copy text by your code.&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/%20JavaScript/Reference/Global_Objects/eval" rel="noopener noreferrer"&gt;eval() - JavaScript | MDN&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/%20content_security_policy#browser_compatibility:~:text=object%2Dsrc%20%27self%27%22-,Browser%20compatibility,-Report%20problems%20%20with" rel="noopener noreferrer"&gt;Browser compatibility : sandbox - Mozilla | MDN&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;&lt;a href="https://github.com/bellard/quickjs" rel="noopener noreferrer"&gt;bellard/quickjs: Public repository of the QuickJS Javascript Engine.&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>extensions</category>
      <category>webassembly</category>
      <category>quickjs</category>
      <category>eval</category>
    </item>
    <item>
      <title>Go's template engine “templ” is convenient (it also works with TinyGo)</title>
      <dc:creator>kasu</dc:creator>
      <pubDate>Tue, 29 Oct 2024 15:51:06 +0000</pubDate>
      <link>https://dev.to/ergofriend/gos-template-engine-templ-is-convenient-it-also-works-with-tinygo-3ad6</link>
      <guid>https://dev.to/ergofriend/gos-template-engine-templ-is-convenient-it-also-works-with-tinygo-3ad6</guid>
      <description>&lt;h2&gt;
  
  
  Synopsis
&lt;/h2&gt;

&lt;p&gt;I wanted to run an application in Go that returned plain HTML,&lt;br&gt;
I decided to use Cloudflare Workers, which can convert it to Wasm and deploy it.&lt;/p&gt;

&lt;p&gt;I recommend syumai/workers's template for deploying Go applications to Cloudflare Workers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/syumai/workers" rel="noopener noreferrer"&gt;syumai/workers: Go package to run an HTTP server on Cloudflare Workers.&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Go + &lt;code&gt;text/template&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;First, let's build using &lt;code&gt;text/template&lt;/code&gt; in a straightforward manner.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /build
   total 15656
   &lt;span class="nt"&gt;-rwxr-xr-x&lt;/span&gt; 1 ergofriend staff 7.6M 8 8 20:12 app.wasm
   &lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 1.2K 8 8 20:12 shim.mjs
   &lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 16K 8 8 20:12 wasm_exec.js
   &lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 160B 8 8 20:12 worker.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It was almost 8 MB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/platform/limits/#account-plan-limits" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/workers/platform/limits/#account-plan-limits&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloudflare Workers has worker size limits depending on the plan.&lt;/p&gt;

&lt;p&gt;The free slot is 1MB, and the paid slot ($5~) is 10MB.&lt;/p&gt;

&lt;p&gt;Even with the final &lt;a href="https://developers.cloudflare.com/workers/platform/limits/#worker-size" rel="noopener noreferrer"&gt;limit based on size after compression&lt;/a&gt;, it will be tough to fit into the free quota starting at 8MB.&lt;/p&gt;
&lt;h3&gt;
  
  
  TinyGo + &lt;code&gt;text/template&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;So I decided to switch to TinyGo, which is supposed to be for WebAssembly (Wasm).&lt;/p&gt;

&lt;p&gt;After building, the size is about 0.75 MB, which seems to fit into the free frame.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /build
total 1160
&lt;span class="nt"&gt;-rwxr-xr-x&lt;/span&gt; 1 ergofriend staff 556K 8 8 20:23 app.wasm
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 1.2K 8 8 20:23 shim.mjs
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 15K 8 8 20:23 wasm_exec.js
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 160B 8 8 20:23 worker.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Oops!
&lt;/h4&gt;

&lt;p&gt;But here is where tragedy strikes.&lt;/p&gt;

&lt;p&gt;When I try to access the built application, I get an error.&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="o"&gt;[&lt;/span&gt;wrangler:inf] GET / 200 OK &lt;span class="o"&gt;(&lt;/span&gt;35ms&lt;span class="o"&gt;)&lt;/span&gt;
✘ &lt;span class="o"&gt;[&lt;/span&gt;ERROR] Uncaught &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;response&lt;span class="o"&gt;)&lt;/span&gt; RuntimeError: unreachable

      at main.runtime._panic &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[35]:0x2b4a&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;text/template.state&lt;span class="o"&gt;)&lt;/span&gt;.evalField
  &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[540]:0x6c5f4&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;text/template.state&lt;span class="o"&gt;)&lt;/span&gt;.evalFieldChain
  &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[531]:0x697fe&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;text/template.state&lt;span class="o"&gt;)&lt;/span&gt;.evalFieldNode
  &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[530]:0x6959a&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;text/template.state&lt;span class="o"&gt;)&lt;/span&gt;.evalPipeline
  &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[535]:0x6a1d2&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;text/template.state&lt;span class="o"&gt;)&lt;/span&gt;.walk &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[569]:0x72cdd&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;text/template.state&lt;span class="o"&gt;)&lt;/span&gt;.walk &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[569]:0x730b0&lt;span class="o"&gt;)&lt;/span&gt;
      at main.main&lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[261]:0x2ac52&lt;span class="o"&gt;)&lt;/span&gt;
      at main.&lt;span class="o"&gt;(&lt;/span&gt;net/http.HandlerFunc&lt;span class="o"&gt;)&lt;/span&gt;.ServeHTTP
  &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[463]:0x5973a&lt;span class="o"&gt;)&lt;/span&gt;
      at
  main.interface:&lt;span class="o"&gt;{&lt;/span&gt;ServeHTTP:func:&lt;span class="o"&gt;{&lt;/span&gt;named:net/http.ResponseWriter,pointer:named:net/http.Request&lt;span class="o"&gt;}{}}&lt;/span&gt;.ServeHTTP&lt;span class="nv"&gt;$invoke&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;wasm://wasm/main-0022bc46:wasm-function[459]:0x56f72&lt;span class="o"&gt;)&lt;/span&gt;

panic: unimplemented: &lt;span class="o"&gt;(&lt;/span&gt;reflect.Value&lt;span class="o"&gt;)&lt;/span&gt;.MethodByName&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The method &lt;code&gt;MethodByName&lt;/code&gt;, which is called when a template variable is passed in &lt;a href="https://pkg.go.dev/html/template#Template.ExecuteTemplate" rel="noopener noreferrer"&gt;template.ExecuteTemplate()&lt;/a&gt;, is not yet It seems to be unimplemented.&lt;/p&gt;

&lt;p&gt;Since TinyGo is a subset of the original, there are many unsupported features,&lt;br&gt;
I found that &lt;code&gt;text/template&lt;/code&gt; was calling unsupported methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tinygo-org/tinygo/blob/1154212c15e6e97048e122068730dab5a1a9427f/src/reflect/type.go#L1086-L1088" rel="noopener noreferrer"&gt;https://github.com/tinygo-org/tinygo/blob/1154212c15e6e97048e122068730dab5a1a9427f/src/reflect/type.go#L1086-L1088&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, I would like to be cool and say p-r for TinyGo, but this time I'm going to look for a quick alternative.&lt;/p&gt;
&lt;h2&gt;
  
  
  TEMPL
&lt;/h2&gt;

&lt;p&gt;So I was looking for another template engine to replace &lt;code&gt;text/template&lt;/code&gt; and came across &lt;strong&gt;templ&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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/a-h" rel="noopener noreferrer"&gt;
        a-h
      &lt;/a&gt; / &lt;a href="https://github.com/a-h/templ" rel="noopener noreferrer"&gt;
        templ
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A language for writing HTML user interfaces in Go.
    &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" href="https://github.com/a-h/templ/raw/main/templ.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fa-h%2Ftempl%2Fraw%2Fmain%2Ftempl.png" alt="templ"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;An HTML templating language for Go that has great developer tooling.&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/a-h/templide-demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fa-h%2Ftemplide-demo.gif" alt="templ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Documentation&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;See user documentation at &lt;a href="https://templ.guide" rel="nofollow noopener noreferrer"&gt;https://templ.guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://pkg.go.dev/github.com/a-h/templ" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dd6dc24fdd7677f1e86becbe197255f1dd57ab6802fb254d2b45574b729dbc54/68747470733a2f2f706b672e676f2e6465762f62616467652f6769746875622e636f6d2f612d682f74656d706c2e737667" alt="Go Reference"&gt;&lt;/a&gt;
&lt;a href="https://xcfile.dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3c9a917834acc7e2c5c405df266db4a644ade18d21a57d085ba2827ade5e962b/68747470733a2f2f786366696c652e6465762f62616467652e737667" alt="xc compatible"&gt;&lt;/a&gt;
&lt;a href="https://raw.githack.com/wiki/a-h/templ/coverage.html" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fa-h%2Ftempl%2Fwiki%2Fcoverage.svg" alt="Go Coverage"&gt;&lt;/a&gt;
&lt;a href="https://goreportcard.com/report/github.com/a-h/templ" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/215d66c0b0bfe0208146da9994c0016c7203aad770faf729b4188eaee1bf23ca/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f612d682f74656d706c" alt="Go Report Card"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tasks&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;build&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Build a local version.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go run ./get-version &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; .version
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; cmd/templ
go build&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;nix-update-gomod2nix&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;gomod2nix&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;install-snapshot&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Build and install current version.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Remove templ from the non-standard ~/bin/templ path&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; that this command previously used.&lt;/span&gt;
rm -f &lt;span class="pl-k"&gt;~&lt;/span&gt;/bin/templ
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Clear LSP logs.&lt;/span&gt;
rm -f cmd/templ/lspcmd/&lt;span class="pl-k"&gt;*&lt;/span&gt;.txt
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Update version.&lt;/span&gt;
go run ./get-version &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; .version
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install to $GOPATH/bin or $HOME/go/bin&lt;/span&gt;
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; cmd/templ &lt;span class="pl-k"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go install&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;build-snapshot&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Use goreleaser to build the command line binary using goreleaser.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;goreleaser build --snapshot --clean&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;generate&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Run templ generate using local version.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go run ./cmd/templ generate -include-version=false&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;test&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Run Go tests.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go run ./get-version &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; .version
go run ./cmd/templ generate -include-version=false
go &lt;span class="pl-c1"&gt;test&lt;/span&gt; ./...&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;test-short&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Run Go tests.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go run ./get-version &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; .version
go run ./cmd/templ generate -include-version=false
go &lt;span class="pl-c1"&gt;test&lt;/span&gt; ./... -short&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;test-cover&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Run…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/a-h/templ" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;Here is a summary of TEMPL.&lt;/p&gt;

&lt;h4&gt;
  
  
  Own DSL
&lt;/h4&gt;

&lt;p&gt;It is not difficult to write a unique program, but it can be written like &lt;code&gt;templ ≈ Go + JSX&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;templ&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Welcome&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks like a very familiar writing style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;templ&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isLoggedIn&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isLoggedIn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;!&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"login"&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Log in"&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you use it, you call Go functions generated from the DSL by &lt;code&gt;templ generate&lt;/code&gt; on a component-by-component basis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isLoggedIn&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;templ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Component&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;templruntime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GeneratedTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;templ_7745c5c3_Input&lt;/span&gt; &lt;span class="n"&gt;templruntime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GeneratedComponentInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;templ_7745c5&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;templ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function of the generated component inherits the argument types defined in the template, so it can be safely called.&lt;br&gt;
Unlike some ExecuteTemplate, this is safe.&lt;/p&gt;
&lt;h4&gt;
  
  
  VSCode Extensions
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=a-h.templ" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=a-h.templ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Syntax Highlight and LSP completion will be very useful.&lt;/p&gt;
&lt;h3&gt;
  
  
  TinyGo + &lt;code&gt;templ&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Just to be sure, I checked and found that it only depends on reflect's &lt;code&gt;TypeOf&lt;/code&gt;, which is already implemented in TinyGo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tinygo-org/tinygo/blob/1154212c15e6e97048e122068730dab5a1a9427f/src/reflect/type.go#L494-L500" rel="noopener noreferrer"&gt;https://github.com/tinygo-org/tinygo/blob/1154212c15e6e97048e122068730dab5a1a9427f/src/reflect/type.go#L494-L500&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's try using templ.&lt;br&gt;
The build seemed to have enough room.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /build
total 1008
&lt;span class="nt"&gt;-rwxr-xr-x&lt;/span&gt; 1 ergofriend staff 477K 8 8 20:35 app.wasm
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 1.2K 8 8 20:35 shim.mjs
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 15K 8 8 20:35 wasm_exec.js
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 ergofriend staff 160B 8 8 20:35 worker.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the actual application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://goworkers-demo.ergofriend.workers.dev/" rel="noopener noreferrer"&gt;goworkers-demo.ergofriend.workers.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When accessed, the HTML can be returned without error.&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="o"&gt;&amp;gt;&lt;/span&gt; wrangler deploy
Total Upload: 493.48 KiB / &lt;span class="nb"&gt;gzip&lt;/span&gt;: 187.91 KiB
Total Upload: 493.48 KiB / &lt;span class="nb"&gt;gzip&lt;/span&gt;: 187.91 KiB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final deployed size is also &lt;code&gt;187.91 KiB&lt;/code&gt;, so there is plenty of room to expand the application.&lt;/p&gt;

&lt;p&gt;This verification is left in this repository.&lt;br&gt;
&lt;a href="https://github.com/ergofriend/goworkers-demo" rel="noopener noreferrer"&gt;ergofriend/goworkers-demo&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This article is a translation from Japanese.&lt;br&gt;
&lt;a href="https://ergofriend.hatenablog.com/entry/2024/08/08/230603" rel="noopener noreferrer"&gt;https://ergofriend.hatenablog.com/entry/2024/08/08/230603&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>tinygo</category>
      <category>templ</category>
      <category>cloudflare</category>
    </item>
  </channel>
</rss>
