<?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: kyohei</title>
    <description>The latest articles on DEV Community by kyohei (@tnzk).</description>
    <link>https://dev.to/tnzk</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%2F385156%2F6052ef54-f78e-43c7-9616-5008c26fab49.jpg</url>
      <title>DEV Community: kyohei</title>
      <link>https://dev.to/tnzk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tnzk"/>
    <language>en</language>
    <item>
      <title>I built Form Builder like Typeform where nobody can see answers in clear text</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Fri, 12 Aug 2022 04:33:32 +0000</pubDate>
      <link>https://dev.to/tnzk/i-built-form-builder-like-typeform-where-nobody-can-see-answers-in-clear-text-cf9</link>
      <guid>https://dev.to/tnzk/i-built-form-builder-like-typeform-where-nobody-can-see-answers-in-clear-text-cf9</guid>
      <description>&lt;p&gt;Hey fellow developers! &lt;/p&gt;

&lt;p&gt;I've been recently running &lt;a href="https://hyde.to/"&gt;Hyde&lt;/a&gt;, a privacy-tech company, as a co-founder and CTO of it for a little shy of a year.&lt;/p&gt;

&lt;p&gt;I feel that OAuth's conception of "scope" should be richer. Right now, there's nothing that prevents OAuth clients from breaking their promises they made in Authorization screens. Not just in practice but in terms of RFC 6749, scopes simply convey a set of kinds of resources authorized, not how they could or couldn't be used.&lt;/p&gt;

&lt;p&gt;I don't think this is a problem of OAuth as it's based on the assumption that, in the first place, you can trust OAuth clients in a degree at which they wouldn't break the promises they themselves made. Like, as long as OAuth clients are somewhat famous enterprises, it would critically harm them if they break the promises they made against their customers.&lt;/p&gt;

&lt;p&gt;At the same time, it's obvious for savvy people like ones in this community, that there's a bunch of malicious actors who would intentionally break those promises, and it's not easy to distinguish those shady agencies from indie hackers who actually do really interesting works.&lt;/p&gt;

&lt;p&gt;In such a context, I've came up with an idea where you would be able to audit, in advance, what computation would happen on your data. I believe this could be established on open standards out there, but for this time, to prove the concept myself right now, I've built PoC tool for both.&lt;/p&gt;

&lt;p&gt;So I made a Form Builder like Typeform where nobody can see answers in clear text.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
    &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__two-pics"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cWSQby3j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/FZtxRkfaAAAexr5.jpg" alt="unknown tweet media content"&gt;
    &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--NUSUKjn4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1466316326322917377/tevZQkUL_normal.jpg" alt="Kyohei profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Kyohei
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/tnzk"&gt;@tnzk&lt;/a&gt;
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I made a Form Builder like Typeform where nobody can see answers in clear text!&lt;br&gt;&lt;br&gt;It works like typical form builders on the surface, but unlike, you wouldn't read responses even if you're the owner. You'll see these instead (what is the use of it? will cover later in thread :) 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      11:18 AM - 09 Aug 2022
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1556963104256557056" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1556963104256557056" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1556963104256557056" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;It works like typical form builders on the surface, but unlike them, you wouldn't be able read responses from participants even if you're the owner. &lt;/p&gt;

&lt;p&gt;I propose two ways to work with those data kept secret.&lt;/p&gt;

&lt;p&gt;First one is UI with visualization but as only vector embeddings, not raw data. Vector embeddings keep characteristic in terms of the operations on elements in the set. You would get the idea roughly by referring several word2vec explanations out there.&lt;/p&gt;

&lt;p&gt;In nutshell, vector embedding preserve the relations between elements in a set while it compresses (in other words, anonymize in this context) by mapping them onto another set. For instance, if you get an idea of adding like &lt;code&gt;King&lt;/code&gt; + &lt;code&gt;Female&lt;/code&gt; = &lt;code&gt;Queen&lt;/code&gt;, then you would construct an embedding in which (&lt;code&gt;king.x&lt;/code&gt;, &lt;code&gt;king.y&lt;/code&gt;, &lt;code&gt;king.z&lt;/code&gt;) + (&lt;code&gt;female.x&lt;/code&gt;, &lt;code&gt;female.y&lt;/code&gt;, &lt;code&gt;female.z&lt;/code&gt;) = (&lt;code&gt;queen.x&lt;/code&gt;, &lt;code&gt;queen.y&lt;/code&gt;, &lt;code&gt;queen.z&lt;/code&gt;). This allows you to execute certain class of computation being unaware of actual words i.e. sensitive information in this context. Caveats are that this also requires you, the application programmer here, to understand what the embeddings are and how you would operate on them.&lt;/p&gt;

&lt;p&gt;Second one is something perhaps a little overloaded in terms of architecture, but simpler to work with. To access the data, you need to make a Docker image. The image will be executed on our end, with JSON files of responses mounted there. Here, you would be able to process the responses in clear text. And it would be supposed to write results to a specific file, from which we would read and provide you via API. Since they (hopefully including you!) can code on them as usual, unlike on the embeddings discussed above.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
    &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__two-pics"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1XPTFsFT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/FZtxeMvaAAAxXaw.jpg" alt="unknown tweet media content"&gt;
    &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--NUSUKjn4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1466316326322917377/tevZQkUL_normal.jpg" alt="Kyohei profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Kyohei
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/tnzk"&gt;@tnzk&lt;/a&gt;
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      To access the data, you need to have a Docker image. The image will be executed on our end, with JSON files of responses mounted there. It would be supposed to write results to a  specific file, from which we would read and provide you via API. 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      11:18 AM - 09 Aug 2022
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1556963114985594880" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1556963114985594880" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1556963114985594880" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Tutorial and API reference is &lt;a href="https://teamhome271.notion.site/I-made-Form-Builder-like-Typeform-where-nobody-can-see-your-answers-in-clear-text-da9d35ce769e4dbfb743b03719e6fbc6"&gt;available here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any feedback would be warmly appreciated :)&lt;/p&gt;

&lt;p&gt;As a next story, I envisage to integrate this on top of OAuth or GNAP; Either by adding a scope/access.actions with specific semantics or returning results in place of tokens. Since GNAP has async mechanism in nature it would fit better. &lt;/p&gt;

</description>
      <category>oauth</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Integrating Svelte Kit and Prisma without wrapper class to workaround</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Thu, 21 Apr 2022 10:14:22 +0000</pubDate>
      <link>https://dev.to/tnzk/integrating-svelte-kit-and-prisma-without-wrapper-class-to-workaround-1lc</link>
      <guid>https://dev.to/tnzk/integrating-svelte-kit-and-prisma-without-wrapper-class-to-workaround-1lc</guid>
      <description>&lt;p&gt;&lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;Svelte Kit&lt;/a&gt; and &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; is a go-to stack for me these days. I like its great ergonomics in frontend and less cost of cognitive load from context switches between server sides.&lt;/p&gt;

&lt;p&gt;Users of Svelte Kit, Nuxt or other Vite based frameworks haven't been able to import PrismaClient or other exports in the way the documentation suggests&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&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%2Fb3rhl24qwg2pa2aoxmo1.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%2Fb3rhl24qwg2pa2aoxmo1.png" alt="doc says..."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which leads you to see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import Prisma, { PrismaClient } from "@prisma/client";
                 ^^^^^^^^^^^^
SyntaxError: Named export 'PrismaClient' not found. The requested module '@prisma/client' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@prisma/client';
const { PrismaClient } = pkg;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While there's &lt;a href="https://github.com/prisma/prisma/discussions/9027#discussion-3548083" rel="noopener noreferrer"&gt;several&lt;/a&gt; &lt;a href="https://github.com/prisma/prisma/issues/5030#issuecomment-970157451" rel="noopener noreferrer"&gt;workarounds&lt;/a&gt; &lt;a href="https://www.mikenikles.com/blog/svelte-kit-prisma-a-match-made-in-digital-heaven#commento-comment-name-c13f447ec60eb97a32ae2cb8fe7aaabd760208be22be65d1345f533c5a51f251" rel="noopener noreferrer"&gt;known&lt;/a&gt; in the community, they still have some shortcomings like inability to import Enum values or &lt;code&gt;Prisma&lt;/code&gt; object for SQL templates nicely.&lt;/p&gt;

&lt;p&gt;For the context, when you use Prisma, what you use is not something in &lt;code&gt;@prisma/client&lt;/code&gt;, but a code locally generated prisma generate command, which in turn &lt;code&gt;@prisma/client&lt;/code&gt; would import inside. Since Prisma need to provide you a custom made API that reflects your schema, it wouldn't able to come as like an ordinary package.&lt;/p&gt;

&lt;p&gt;As a result, &lt;code&gt;@prisma/client&lt;/code&gt; contains just a line of code or two, to import the custom-made client supposedly generated at the time of deployment. It's really small piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.prisma/client/index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this glues the application code and generated code, I would call this as Prisma's glue code.&lt;/p&gt;

&lt;p&gt;This works fine for CJS code to require. Similarly, the code that would be transpiled by TypeScript or other bundlers can work with this, since those tools take care at compile time.&lt;/p&gt;

&lt;p&gt;The problem is ES modules, who cannot recognize any exports other than default exports.&lt;/p&gt;

&lt;p&gt;Svelte Kit (as far as I know also Nuxt or other Vite based frameworks, depending on configs) emits ES modules as their build artifacts, unlike Next that emits CJS bundles, and encounters this problem.&lt;/p&gt;

&lt;p&gt;But why?&lt;/p&gt;

&lt;p&gt;When an ES module tries to &lt;code&gt;import&lt;/code&gt; named exports from other CJS modules, Node recognizes only the exports that explicitly defiend in specific syntax. They would be detected before they get executed with static analysis &lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For better compatibility with existing usage in the JS ecosystem, Node.js in addition attempts to determine the CommonJS named exports of every imported CommonJS module to provide them as separate ES module exports using a static analysis process.&lt;/p&gt;

&lt;p&gt;The detection of named exports is based on common syntax patterns but does not always correctly detect named exports.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because of this, Prisma's glue code effectively reexports just default export from perspective of Node, while TS compiler somehow recognized the named exports. This causes a weird situation where they would work fine in dev server, but fails with the error message like this once they have been bundled for production, as ES modules with static &lt;code&gt;import&lt;/code&gt; s.&lt;/p&gt;

&lt;p&gt;Fortunately, Node doesn't detect only &lt;code&gt;export.name = value&lt;/code&gt;. It seems to support more involved syntax, like &lt;sup id="fnref3"&gt;3&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&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="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.prisma/client/index&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which I sent as &lt;a href="https://github.com/prisma/prisma/pull/12907" rel="noopener noreferrer"&gt;a pull request to Prisma&lt;/a&gt;. I'm not sure when or even if it would be accepted, I assume you would be able to use this hook in &lt;code&gt;package.json&lt;/code&gt; for the time being. Assuming above glue code replacement (JS snippet) saved as &lt;code&gt;patches/prisma-fixed-glue.js&lt;/code&gt;, add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cp patches/prisma-fixed-glue.js node_modules/@prisma/client/index.js &amp;amp;&amp;amp; svelte-kit build"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(I use pnpm which &lt;a href="https://github.com/pnpm/pnpm/issues/2891" rel="noopener noreferrer"&gt;no longer supports lifecycle scripts&lt;/a&gt; in default, but you can put &lt;code&gt;prebuild&lt;/code&gt; as long as you enabled it or use npm)&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/instantiate-prisma-client" rel="noopener noreferrer"&gt;https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/instantiate-prisma-client&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://nodejs.org/api/esm.html#commonjs-namespaces" rel="noopener noreferrer"&gt;https://nodejs.org/api/esm.html#commonjs-namespaces&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://github.com/nodejs/cjs-module-lexer/tree/1.2.2" rel="noopener noreferrer"&gt;https://github.com/nodejs/cjs-module-lexer/tree/1.2.2&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>svelte</category>
      <category>prisma</category>
    </item>
    <item>
      <title>Jest-gauge, a Jest extension to write acceptance tests  in natural languages like Gauge</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Mon, 09 Aug 2021 03:14:57 +0000</pubDate>
      <link>https://dev.to/tnzk/jest-gauge-a-jest-extension-to-write-acceptance-tests-in-natural-languages-similar-to-gauge-lie</link>
      <guid>https://dev.to/tnzk/jest-gauge-a-jest-extension-to-write-acceptance-tests-in-natural-languages-similar-to-gauge-lie</guid>
      <description>&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;I’ve released a Jest extension that allows you to write acceptance tests  in natural languages similar to Gauge, in which you can practice acceptance tests driven development; ATDD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tnzk/jest-gauge"&gt;https://github.com/tnzk/jest-gauge&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Acceptance-Test Driven Development (ATDD)?
&lt;/h1&gt;

&lt;p&gt;Acceptance-Test Driven Development is a software development methodology derived from Test-Driven Development, as known as TDD. In contrast to TDD which focuses on describing what you expect a class or a module to be, ATDD encourages you to describe acceptance criteria of the subject system as a whole, in a larger sense.&lt;/p&gt;

&lt;p&gt;Roughly speaking, they provide a feedback cycle of software tests around unit testing with TDD and E2E testing for ATDD, respectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://dannorth.net/introducing-bdd/"&gt;Behavior-Driven Development, BDD, is another methodology which also derives from TDD&lt;/a&gt;. BDD shares the same feedback cycle as in TDD, but focuses on defining “behaviors” of a class or a module. More importantly, BDD involves a wider variety of stakeholders to participate in. Unlike TDD which is designed and evolved as a practice for programmers to get their job done nicely, BDD puts emphasis on describing User Stories to define what kind of value should be delivered to customers, through &lt;a href="%5Bhttps://cucumber.io/docs/bdd/discovery-workshop/%5D(https://cucumber.io/docs/bdd/discovery-workshop/)"&gt;“Discovery workshop”&lt;/a&gt; by the “three amigos,” said the product owner, developers and testers.&lt;/p&gt;

&lt;p&gt;User Stories by theirselves cannot drive a feedback cycle of software tests since they’re just some plain sentences in a natural language. However, expressing an expected behavior directly as a piece of test code will prevent non-programers to participate in the session as stakeholders, which exactly BDD encourages in the first place.&lt;/p&gt;

&lt;p&gt;To overcome this dilemma, Cucumber, a well known BDD framework, provides a DSL called Gharkin, which you can describe the insights found in “Discovery workshop”. Gharkin allows you to write something like “AS a Customer, TO avoid standing in the line for a bank teller, I WANT to withdraw cash via ATM”, similar to well-known User Story Template. This looks understandable to stakeholders who don’t code.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://dannorth.net/introducing-bdd/"&gt;As Daniel North explained was inspired by Ubiquitous Language by Eric Evans&lt;/a&gt;, they are almost identical to the domain definition, in other words, the "acceptance criteria" to the product from the business owner's perspective. The motivation towards ATDD is the question of how we can drives software development by defining these acceptance criteria in terms of &lt;a href="https://www.stevenrbaker.com/tech/history-of-rspec.html"&gt;executable specification of the software&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Gauge?
&lt;/h1&gt;

&lt;p&gt;Through the explanation above, you might find BDD and ATDD don't seem to differ that much. If so, can't we use Cucumber to drive ATDD, as long as we let the minor mismatches aside?&lt;/p&gt;

&lt;p&gt;The dealbreaker is the fact that Gherkin is not a natural language on a closer look, but a loosely-defined formal language. Finished examples in Gherkin looks as if written in a natural language indeed, but when it comes to writing, stakeholders who don't code found it very tough to write in it (Programmers, of course including me, sometimes misbelieve even non-programmers can read and write a simple piece of RSpec or something, but in reality they can't. This should be a cognitive bias which &lt;a href="https://www.codewithjason.com/recommend-against-cucumber/"&gt;many programmers share&lt;/a&gt; I think).&lt;/p&gt;

&lt;p&gt;Gherkin's syntax in which you write the behavioral definition is, in fact, not a natural language but slightly formally constrained.&lt;/p&gt;

&lt;p&gt;In Gauge, you can write literally in a natural language. While specification file itself is defined as subset of Markdown, sentences inside are just a line of a human language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Top page Specification &lt;/span&gt;

You can explain freely the background or motivation of the specification, since paragraphs here will be ignored as just comments.

&lt;span class="gu"&gt;## Scenario: a user can open a site and see the top page.&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Open "https://duckduckgo.com/".
&lt;span class="p"&gt;-&lt;/span&gt; It shows a picture of a cute Cucumber-looking bird to the user.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run tests, Gauge will look up step implementations by the title for corresponding to specification lines, in exact matching basis. You can insert a template variable to give it to some robustness as you like, whereas in turn it makes the sentences look like in a formal language. Unlike Gherkin, you can tweak the strictness of the language by using or not using these variables or other similar mechanisms.&lt;/p&gt;

&lt;p&gt;I'm interested in Gauge since it allows us to write specifications and acceptance criteria in a free-form natural language.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Jest-gauge?
&lt;/h1&gt;

&lt;p&gt;Gauge seemed a little opinionated to me, and felt it required a heavy-lifting to integrate into an existing product. It was hesitant for me to give a surprise like "Hey guys, we need to switch the testing framework to Gauge!" to team members who just had been familiarized with unit/E2E testing in Jest.&lt;/p&gt;

&lt;p&gt;I suppose I will need Gauge in the future to navigate full-fledged ATDD, but my primary motivation at this time is something narrower than "Is ATDD good or not?", more like "Will specs in a Gauge-like natural language be the catalyst that leads communication between developers and non-developer stakeholders?"&lt;/p&gt;

&lt;p&gt;So, I've started building a tool for a team with existing unit/E2E tests in Jest to try ATDD easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tnzk/jest-gauge"&gt;https://github.com/tnzk/jest-gauge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Refer &lt;a href="https://github.com/tnzk/jest-gauge"&gt;README&lt;/a&gt; for installation and usage.&lt;/p&gt;

&lt;p&gt;Since it is a Jest extension, you can try it out by adding a configuration into &lt;code&gt;jest.config.js&lt;/code&gt;. For specification above, it shows a test report like this:&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;npx jest &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jest.config.gauge.js specs/

PASS  examples/welcome.spec

Top page Specification 

Scenario: a user can open a site and see the top page.
✓ Open &lt;span class="s2"&gt;"https://duckduckgo.com/"&lt;/span&gt;
✓ It shows a picture of a cute Cucumber-looking bird to the user.

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.913 s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It supports a large part of Gauge's functionality, but of course there's many things not supported yet. You can find what is supported and what is not in &lt;a href="https://github.com/tnzk/jest-gauge#todo"&gt;TODO section in README&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Motivation
&lt;/h1&gt;

&lt;p&gt;I'm running a coding bootcamp in Japan. We are building and maintaining a learning management system for internal use from scratch. We have stakeholders of the project working as a non-tech staffs and they have very raw and factual needs about what matters for operating the educational activity in the bootcamp, as massive and complex Excel spreadsheets! It had motivated me to wander how to keep them organized and ship as working software.&lt;/p&gt;

&lt;p&gt;I tried convincing the stakeholders "We're a coding bootcamp, so we should take a risk and try new things on software development methodology. It must lead us to some insights about quality of the educational service". I knew this is a kind of big ask to be accepted in other domain of businesses. Even developers are surprised on this. So I must say a warm appreciation for accepting this to colleagues.&lt;/p&gt;

&lt;p&gt;A bit tangentially, that was not the only stretching. We've built a video chat functionality from scratch with WebRTC into the LMS, where the lectures and technical support sessions take place. Screenshot below are us doing a workshop on it. It takes much of efforts to stabilize the connectivity since we don't rely on a famous product like Agora and Zoom APIs, and in course we had learnt many insights and grown team unity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DRubON9A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/zenn-user-upload/ae3748c855fea33e332c3532.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DRubON9A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/zenn-user-upload/ae3748c855fea33e332c3532.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I decided to build Jest-gauge, after concluding Gauge itself is not for our team at this moment and catching up ATDD in 2021 and Cucumber/Gherkin which I experienced half decade ago. And then on, our CI runs acceptance tests written in our mother tongue everyday.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n5E5Jsc8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/zenn-user-upload/86057b0ecb1d491fbff6321f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n5E5Jsc8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://storage.googleapis.com/zenn-user-upload/86057b0ecb1d491fbff6321f.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, this is our proud production case :)&lt;/p&gt;

&lt;p&gt;A joke aside, we accept risks because we are not a big-co and of the background above. There's many rough edge in it, so please use it at your own risk.&lt;/p&gt;

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

&lt;p&gt;These experience above, and the books on ATDD like &lt;a href="https://www.amazon.co.jp/dp/0321503627"&gt;"Growing Object-Oriented Software, Guided by Tests"&lt;/a&gt;, leads me to a belief that it might be too early for developers and other stakeholders to communicate through behavioral descriptions or in a ubiquitous language, in evidence-based manner, a decade ago.&lt;/p&gt;

&lt;p&gt;Increasing importance of technology and things like no-code platforms may change this. We may be able to discuss and share what a product is and should be through a semi-formal language in like Gauge or Cucumber.&lt;/p&gt;

&lt;p&gt;Members of a company who runs a coding bootcamp, maybe inevitably, looks like having relatively good understanding of computers and software, even they're not developers. This might be the reason we had adopted ATDD with relatively little friction. We'll practice the ATDD with Jest-gauge there at this moment, and later transfer that insight to other fields with less association with software.&lt;/p&gt;

&lt;p&gt;But this is just a try. Maybe it works, or maybe not. If you try Jest-gauge, and got some insights, please share it with me. Of course, any contributions are warmly welcomed.&lt;/p&gt;

</description>
      <category>jest</category>
      <category>gauge</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Svelte for Web Components development: Pitfalls and workarounds</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Mon, 05 Jul 2021 14:09:40 +0000</pubDate>
      <link>https://dev.to/tnzk/svelte-for-web-components-development-pitfalls-and-workarounds-as-of-july-2021-3lii</link>
      <guid>https://dev.to/tnzk/svelte-for-web-components-development-pitfalls-and-workarounds-as-of-july-2021-3lii</guid>
      <description>&lt;p&gt;&lt;a href="https://svelte.dev/docs#Custom_element_API"&gt;Svelte components can be compiled to custom elements, aka web components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since Svelte is a library in relatively early stage, there are some pitfalls to avoid with workarounds, which I'm going to describe in this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tnzk/svelte-webcomponents-exp"&gt;Corresponding code for repro and trying out yourself the workarounds&lt;/a&gt; are on GitHub. &lt;a href="https://svelte-webcomponents-exp.vercel.app/"&gt;The working example is available online&lt;/a&gt; via Vercel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attributes named in kebab-case won't be recognized
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;props&lt;/code&gt; defined in Svelte components compiles to an attribute of a custom element. In HTML, most of the attributes are named in &lt;code&gt;kebab-case&lt;/code&gt;, specified as words in lower alphabets combined with &lt;code&gt;-&lt;/code&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In Svelte, however, &lt;code&gt;props&lt;/code&gt; are described as a set of declaration of variables, which in JavaScript cannot include &lt;code&gt;-&lt;/code&gt; in the name. This is known issues&lt;sup id="fnref2"&gt;2&lt;/sup&gt; with a workaround.&lt;/p&gt;

&lt;p&gt;Svelte team recognizes this but has not been resolved. It is suggested to use &lt;code&gt;$$props&lt;/code&gt; to access the props like &lt;code&gt;$$props['kebab-attr']&lt;/code&gt; in these situations&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;This, however, works only in the case you use the custom element in HTML directly. It is okay for the end users of the custom element since they would use it in that way but is problematic for developers of the components. If you mount it as Svelte component, all &lt;code&gt;props&lt;/code&gt; should be &lt;code&gt;undefined&lt;/code&gt; at that moment the component has been instantiated, unintentionally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
import './Kebab.svelte'

let name = value
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;kebab&lt;/span&gt; &lt;span class="na"&gt;your-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;kebab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

// Kebab.svelte
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-kebab"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
export let yourName = $$props['your-name']
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;yourName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another workaround which allows you to code &lt;code&gt;&amp;lt;swc-kebab your-name={name}&amp;gt;&amp;lt;/swc-kebab&amp;gt;&lt;/code&gt; is to have a wrapper class to intercept default behavior of the Svelte&lt;sup id="fnref3"&gt;3&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// KebabFixed.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Kebab&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;./Kebab.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;KebabFixed&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Kebab&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;observedAttributes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observedAttributes&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;])(?=[&lt;/span&gt;&lt;span class="sr"&gt;A-Z&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$1-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;attributeChangedCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;attrName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;up&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributeChangedCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swc-kebab-fixed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;KebabFixed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
import './KebabFixed.svelte'

let name = value
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;kebab-fixed&lt;/span&gt; &lt;span class="na"&gt;your-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;kebab-fixed&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Attributes with upper-case letters won't be recognized
&lt;/h2&gt;

&lt;p&gt;Similarly, you cannot use an upper-case letter in the name of attributes if the component is mounted as a custom element. For instance, even you specified like &lt;code&gt;yourName="some value"&lt;/code&gt;,  it will be converted to a lower-case version like &lt;code&gt;yourname&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It seems the browsers that convert names to comply the naming convention explained above, rather than a problem of Svelte's Web Components support.&lt;/p&gt;

&lt;p&gt;Since camelCase is de-facto standard way of naming in JavaScript, naming a prop like &lt;code&gt;yourName&lt;/code&gt; as usual would result &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this case, changing two occurrence of &lt;code&gt;yourName&lt;/code&gt; to &lt;code&gt;yourname&lt;/code&gt; fixes it to work properly. Unlikely, the attribute name on caller side doesn't matter, whichever it is &lt;code&gt;yourName="camelCase"&lt;/code&gt; or &lt;code&gt;yourname="non camel case"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
import './NoUppercase.svelte'

let name = value
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;no-uppercase&lt;/span&gt; &lt;span class="na"&gt;yourName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;no-uppercase&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

// NoUppercase.svelte
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-no-uppercase"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
export let yourName // Change this to `yourname`
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;yourName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;!--&lt;/span&gt; &lt;span class="na"&gt;Change&lt;/span&gt; &lt;span class="na"&gt;this&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="na"&gt;yourname&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="err"&gt;--&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Changing one of props via DOM API applies to the component, but bind mechanism doesn't work
&lt;/h2&gt;

&lt;p&gt;In the example above, I have used Svelte notations to set attribute values. You can leverage the most of Svelte functionality to develop custom elements. Changes of &lt;code&gt;value&lt;/code&gt; propagates to &lt;code&gt;name&lt;/code&gt; in the child component which depends to &lt;code&gt;value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Svelte notation does not available in HTML, so you wouldn't be able to &lt;code&gt;yourname={name}&lt;/code&gt;. The only way to set attribute values is to code &lt;code&gt;yourname="a string literal"&lt;/code&gt; directly. Use DOM APIs to change these attribute values dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swc-child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yourName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a updated name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever attribute values changed, &lt;code&gt;attributeChangedCallback&lt;/code&gt; which Svelte registered propagates the change to the internal DOM of the custom element. This enables you to treat the custom element similarly to Svelte components.&lt;/p&gt;

&lt;p&gt;On the other hand, there's no support of &lt;code&gt;bind:&lt;/code&gt; mechanism in custom elements. Changes in child custom elements will not be available to parent components.&lt;/p&gt;

&lt;p&gt;Use custom events I'd described later to pass back the changes in child custom elements. In this case, end users of the custom element must register an event listener to subscribe the events.&lt;/p&gt;

&lt;p&gt;This weighs to the end users, but it is reasonable for them to be responsible of since they've decided not to use any front-end frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can't pass an object other than a string through attributes
&lt;/h2&gt;

&lt;p&gt;Svelte components accept any objects as contents of &lt;code&gt;props&lt;/code&gt;. But attribute values in HTML accept just a literal string.&lt;/p&gt;

&lt;p&gt;If you have a Svelte component first and try to compile it to a custom element, this might be a problem. You can serialize an object to JSON if the object is simple enough, while it is very unlikely in the real world.&lt;/p&gt;

&lt;p&gt;A (weird) workaround would be to have an object like "store" in global namespace, pass any objects you want through the store. As long as the key is just a string, you can set it to the attribute values of the custom element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-root"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  import PassAnObjectFixed from './PassAnObjectFixed.svelte'

  let name = 'default name'

  window.__myData = &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;somekey&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="si"&gt;}&lt;/span&gt;
  $: window.__myData['somekey'].name = name
  const syncToParent = () =&amp;gt; &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__myData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;somekey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As WC: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;pass-object&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;pass-object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As Svelte: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PassAnObject&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As WC: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;pass-object-fixed&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"somekey"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;pass-object-fixed&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;syncToParent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Sync to input field&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

// PassAnObjectFixed.svelte

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-pass-object-fixed"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
export let key
let name

const refresh = () =&amp;gt; &lt;span class="si"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__myData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;somekey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="si"&gt;}&lt;/span&gt;
refresh()

$: window.__myData['somekey'].name = name

&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refresh&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Refresh&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, the parent component can read the changes the child applied to store, thus you can have some feedback mechanism like the &lt;code&gt;bind:&lt;/code&gt; in anyway.&lt;/p&gt;

&lt;p&gt;Of course it is not very cool since only the key would be specified explicitly. I'd prefer to change the values through DOM API and custom events to have dependency of data clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emiting a custom event in Svelte doesn't emit a DOM event automatically
&lt;/h2&gt;

&lt;p&gt;Svelte supports custom events to emit any component specific events other than built-in events like &lt;code&gt;on:click&lt;/code&gt;, &lt;code&gt;on:keydown&lt;/code&gt; or &lt;code&gt;on:focus&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, a callback set via &lt;code&gt;addEventListener&lt;/code&gt; wouldn't be able to catch them since they're built on Svelte-specific event mechanism. In the example below, you can see how a custom event, which is successfully listened in Svelte event handler, doesn't fire the callback registered via &lt;code&gt;addEventListener&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-root"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;window&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;handleLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CustomEventExample&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;./CustomEventExample.svelte&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default name&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;handleCustomEvent&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rootElement&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleLoad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rootElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swc-custom-events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;customElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;namechanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleCustomEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&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;customEventElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;customEventElement&lt;/span&gt;&lt;span class="p"&gt;.&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;name&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rootElement&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Custom Event&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As Svelte: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CustomEventExample&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;namechanged&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCustomEvent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As WC: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;custom-events&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;custom-events&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

// CustomEventExample.svelte
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-custom-events"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
import &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createEventDispatcher&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt; from 'svelte';
const dispatch = createEventDispatcher();

export let name
  $: (name) &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; dispatch('namechanged', &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;)
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A workaround suggested in GitHub&lt;sup id="fnref3"&gt;3&lt;/sup&gt; would be like below. There, you can have a wrapper to emit a DOM event also:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-custom-events-fixed"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  import &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createEventDispatcher&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt; from 'svelte';
  import &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;get_current_component&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt; from 'svelte/internal';

  const component = get_current_component();
  const originalDispatch = createEventDispatcher();

  const dispatch = (name, detail) =&amp;gt; &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;originalDispatch&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="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CustomEvent&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="si"&gt;}&lt;/span&gt;

  export let name
  $: (name) &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; dispatch('namechanged', &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;)
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Styles defined in child components doesn't apply
&lt;/h2&gt;

&lt;p&gt;You can use a component as a Svelte component or a custom element almost interchangeably. One of subtle difference would be how a set of  styles defined in components applies.&lt;/p&gt;

&lt;p&gt;A component with &lt;code&gt;&amp;lt;svelte:options tag="tag-name" /&amp;gt;&lt;/code&gt; will have &lt;a href="https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_shadow_DOM"&gt;a shadow root&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, child components in the above said component won't have a shadow root. The &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; section will be extracted and merged into the parent's one. Thus,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-root"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
import StylesEncupsulated from './StylesEncupsulated.svelte'
let name = 'default name'
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Styles&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As Svelte: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StylesEncupsulated&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;As WC: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;styles-encapsulated&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;swc&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;styles-encapsulated&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// StylesEncupsulated.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-styles-encapsulated"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
export let name
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  span &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple workaround for this is to use inline style. Svelte compiler does not touch the inline styles, so it keeps existing and applies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// StylesEncupsulated.svelte&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svelte&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt; &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"swc-styles-encapsulated"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
export let name
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"color: blue;"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is not cool since you must code the same styles repeatedly, as well as have scattered template code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uncaught (in promise) TypeError: Illegal constructor at new SvelteElement
&lt;/h2&gt;

&lt;p&gt;Svelte use the component classes directly to &lt;code&gt;createElements.define&lt;/code&gt; to register custom elements. If you enabled &lt;code&gt;customElement&lt;/code&gt; in compiler options, there's no way to control which component should be compiled to a custom element and which is not.&lt;/p&gt;

&lt;p&gt;So you'll encounter &lt;code&gt;Uncaught (in promise) TypeError: Illegal constructor at new SvelteElement&lt;/code&gt; if you misses &lt;code&gt;&amp;lt;svelte:options tag="swc-styles-encapsulated" /&amp;gt;&lt;/code&gt; in any component inside the project.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-observed-attributes"&gt;https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-observed-attributes&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://github.com/sveltejs/svelte/issues/875"&gt;https://github.com/sveltejs/svelte/issues/875&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://github.com/sveltejs/svelte/issues/3852"&gt;https://github.com/sveltejs/svelte/issues/3852&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://www.notion.so/Svelte-Web-Components-2021-7-fc7b724677bf4c68b6289e8d0ca241b6"&gt;https://www.notion.so/tnzk/Svelte-Web-Components-2021-7-fc7b724677bf4c68b6289e8d0ca241b6#c666e54ccfe54e98a4c72626bec2a502&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Install Puppeteer on MacBook Pro with Apple Silicon / M1</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Sun, 13 Jun 2021 12:47:06 +0000</pubDate>
      <link>https://dev.to/tnzk/install-puppeteer-on-macbook-pro-with-apple-silicon-m1-3kc</link>
      <guid>https://dev.to/tnzk/install-puppeteer-on-macbook-pro-with-apple-silicon-m1-3kc</guid>
      <description>&lt;p&gt;For those who wouldn't like to work outside the CLI.&lt;/p&gt;

&lt;p&gt;Install Chromium via brew:&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;brew &lt;span class="nb"&gt;install &lt;/span&gt;chromium
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;which chromium&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set an environemntal variable to prevent &lt;code&gt;[npm/yarn/pnpm] install&lt;/code&gt; downloading Chromium automatically (I'd put &lt;code&gt;.env&lt;/code&gt; into the repo so coworkers with Apple Silicon can &lt;code&gt;$ source .env&lt;/code&gt; .)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although &lt;a href="https://github.com/puppeteer/puppeteer/issues/6622#issuecomment-788199984"&gt;in some situations you need to patch Puppeteer&lt;/a&gt; since it has a hard-coded executable path to &lt;code&gt;/usr/bin/chromium-browser&lt;/code&gt;, you can try an option of &lt;code&gt;puppeteer.launch&lt;/code&gt; to overwrite it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;PUPPETEER_EXECUTABLE_PATH&lt;/span&gt;&lt;span class="err"&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;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/puppeteer/puppeteer/issues/6622"&gt;Installation fails on Apple Silicon / M1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/3tomcha/items/f141faa1cb24124e9d66"&gt;M1 MacBookでpuppeteerが動かない時の解決策&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/Buzzword111/items/aa5dd4c89358a63f970a"&gt;M1 Macでpuppeteerを動かす方法（2020年12月21日時点）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>puppeteer</category>
      <category>m1</category>
      <category>applesilicon</category>
    </item>
    <item>
      <title>TDD, BDD, ATDD and Agile timeline</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Wed, 05 May 2021 07:48:55 +0000</pubDate>
      <link>https://dev.to/tnzk/tdd-bdd-atdd-and-agile-timeline-f32</link>
      <guid>https://dev.to/tnzk/tdd-bdd-atdd-and-agile-timeline-f32</guid>
      <description>&lt;h1&gt;
  
  
  Timeline
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;2000 &lt;a href="https://amzn.to/3uiVvUj"&gt;Test Driven Development: By Example&lt;/a&gt; by Kent Beck&lt;/li&gt;
&lt;li&gt;2001 &lt;a href="https://agilemanifesto.org/history.html"&gt;Agile Manifesto&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2002 &lt;a href="https://www.scrumalliance.org/"&gt;Scrum Alliance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2003 &lt;a href="https://amzn.to/33eq29Y"&gt;Domain-Driven Design: Tackling Complexity in the Heart of Software&lt;/a&gt; by Eric Evans, BDD and JBehave by Daniel North&lt;/li&gt;
&lt;li&gt;2003 &lt;a href="https://github.com/unclebob/fitnesse/"&gt;FitNesse&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2004 BDD getting traction among the community&lt;/li&gt;
&lt;li&gt;2005 RSpec by Dave, Aslak&lt;/li&gt;
&lt;li&gt;2006 &lt;a href="http://dannorth.net/introducing-bdd/"&gt;Introducing BDD&lt;/a&gt; by Daniel North&lt;/li&gt;
&lt;li&gt;2008 &lt;a href="https://cucumber.io/"&gt;Cucumber&lt;/a&gt; by Aslak&lt;/li&gt;
&lt;li&gt;2010 &lt;a href="https://amzn.to/2SegZTZ"&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2010 &lt;a href="https://amzn.to/3efUS8a"&gt;The RSpec Book&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2011 &lt;a href="https://aslakhellesoy.com/post/11055981222/the-training-wheels-came-off"&gt;The training wheels came off&lt;/a&gt; by Aslak&lt;/li&gt;
&lt;li&gt;2012 &lt;a href="https://martinfowler.com/bliki/PageObject.html"&gt;Page Object pattern&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2013 &lt;a href="https://www.slideshare.net/RiverGlide/a-journey-beyond-the-page-object-pattern"&gt;Screenplay pattern&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2014 &lt;a href="https://dhh.dk/2014/tdd-is-dead-long-live-testing.html"&gt;TDD is dead. Long live testing.&lt;/a&gt; by DHH&lt;/li&gt;
&lt;li&gt;2018 &lt;a href="https://www.thoughtworks.com/news/gauge-test-automation"&gt;gauge&lt;/a&gt; by ThoughtWorks&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Background and Motivation
&lt;/h1&gt;

&lt;p&gt;I'm not so crucial about BDD, nor a ritual practitioner of it. Even so I occasionally come up with an idea that BDD must be suited to the issues I encountered sometimes.&lt;/p&gt;

&lt;p&gt;This time I wish to be a little more thoughtful. I've collected the important events in BDD and Agile field, and sorted them chronologically so I can grasp a brief history and trend of TDD, BDD and ATDD.&lt;/p&gt;

&lt;p&gt;Any information and advice would be appreciated, especially events since 2014 which seem missing in this list.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sources
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cucumber.io/docs/bdd/history/"&gt;History of BDD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://amzn.to/3uiVvUj"&gt;Test Driven Development:By Example&lt;/a&gt; and &lt;a href="https://www.amazon.co.jp/dp/4274217884/ref=cm_sw_r_cp_awdb_imm_T4K57RQDWVDKEVFT23MQ"&gt;its Japanese translation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.co.jp/dp/0135781868/ref=cm_sw_r_cp_awdb_imm_SM7Y3PXXN2W9S2342NP1"&gt;Clean Agile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codewithjason.com/recommend-against-cucumber/"&gt;Why I recommend against using Cucumber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tdd</category>
      <category>agile</category>
      <category>testing</category>
    </item>
    <item>
      <title>Trying openapi2aspida to auto-generate Type Definition for a Web API</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Sun, 31 May 2020 07:49:00 +0000</pubDate>
      <link>https://dev.to/tnzk/trying-openapi2aspida-to-auto-generate-type-definition-for-a-web-api-2mpj</link>
      <guid>https://dev.to/tnzk/trying-openapi2aspida-to-auto-generate-type-definition-for-a-web-api-2mpj</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/tnzk/making-web-apis-type-safe-with-aspida-fkf"&gt;Previously&lt;/a&gt;, we had explored how &lt;a href="https://github.com/aspidajs/aspida"&gt;Aspida&lt;/a&gt; provides a way to integrate external Web APIs into your code in type-safe manner.&lt;/p&gt;

&lt;p&gt;But writing down the complete type definition of an API by hand hardly seems very fun. Rather, we'd like it to be generated automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aspidajs/openapi2aspida"&gt;openapi2aspida&lt;/a&gt; tools gives this functionality, as long as the API provides OpenAPI 3.0 or Swagger schema.&lt;/p&gt;

&lt;h1&gt;
  
  
  Generate Type Definition
&lt;/h1&gt;

&lt;p&gt;Since you've followed instruction in previous post, you would have &lt;code&gt;apis&lt;/code&gt; directory, which this time &lt;code&gt;openapi2aspida&lt;/code&gt; expects it to be absent. So we need remove this before trying this tool.&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;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$REPO_ROOT&lt;/span&gt;/apis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create aspida.config.js, Get JSON schema path&lt;/p&gt;

&lt;p&gt;Run this to generate and pour packages into &lt;code&gt;apis/&lt;/code&gt;:&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;npx openapi2aspida &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Try using
&lt;/h1&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;yarn run aspida-mock &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Property &lt;span class="s1"&gt;'resHeaders'&lt;/span&gt; is missing &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="s1"&gt;'{ status: 200; resBody: { about: { description: string; title: string; locale: string; version: string; https: true; moderators: { id: number; username: string; avatar_template: string; name: string; title: string; }[]; admins: { ...; }[]; }; }; }'&lt;/span&gt; but required &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="s1"&gt;'BaseResponse&amp;lt;{ about?: { description?: string; title?: string; locale?: string; version?: string; https?: boolean; moderators?: { id?: number; username?: string; avatar_template?: string; name?: string; title?: string; }[]; admins?: { ...; }[]; }; }, unknown, 200&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow I thought I had tried to compile C++ abusing class templates here.&lt;/p&gt;

&lt;p&gt;This error seems to occur because Discourse API doc (perhaps including OpenAPI schema). Discourse maintainers said so in the &lt;a href="https://docs.discourse.org/"&gt;doc&lt;/a&gt; and &lt;a href="https://meta.discourse.org/t/discourse-api-documentation/22706/257"&gt;the thread&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let the linter explain before deep diving this ourselves:&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;yarn global add ibm-openapi-validator
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-O&lt;/span&gt; https://docs.discourse.org/openapi.json
&lt;span class="nv"&gt;$ &lt;/span&gt;lint-openapi openapi.json | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 10

&lt;span class="o"&gt;[&lt;/span&gt;Warning] No .validaterc file found. The validator will run &lt;span class="k"&gt;in &lt;/span&gt;default mode.
To configure the validator, create a .validaterc file.

errors

  Message :   Parameters MUST have their data described by either &lt;span class="sb"&gt;`&lt;/span&gt;schema&lt;span class="sb"&gt;`&lt;/span&gt; or &lt;span class="sb"&gt;`&lt;/span&gt;content&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
  Path    :   paths./c/&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;.json.get.parameters.0
  Line    :   296

&lt;span class="nv"&gt;$ &lt;/span&gt;lint-openapi openapi.json | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
1318
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;We have tried Discourse API and found it lacked an OpenAPI-compiliant Schema. While &lt;code&gt;openapi2aspida&lt;/code&gt; doesn't seem to work very well in this situation, but if you are in a project where you have well-written OpenAPI schema, &lt;code&gt;openapi2aspida&lt;/code&gt; will be promising for your development.&lt;/p&gt;

&lt;p&gt;Unfortunately, you wouldn't find so many projects with OpenAPI Schema out there at the moment. Yet &lt;a href="https://dev.to/tnzk/making-web-apis-type-safe-with-aspida-fkf"&gt;we saw previously&lt;/a&gt;, we can start writing type definition by hand as necessary.&lt;/p&gt;

&lt;p&gt;If you'll happen to be design a web API, you can contribute the OpenAPI ecosystem by starting it with writing OpenAPI Schema for the API. This might be encouraged from test-driven point of view.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Making Web APIs Type-safe with Aspida</title>
      <dc:creator>kyohei</dc:creator>
      <pubDate>Thu, 14 May 2020 07:29:06 +0000</pubDate>
      <link>https://dev.to/tnzk/making-web-apis-type-safe-with-aspida-fkf</link>
      <guid>https://dev.to/tnzk/making-web-apis-type-safe-with-aspida-fkf</guid>
      <description>&lt;p&gt;Types matter. Even with the naive type system of C/C++, I used to feel somehow protected.&lt;/p&gt;

&lt;p&gt;TypeScript enables for JavaScript libraries to provide their type definitions but Web APIs. Actually, majority of APIs lack precise documentation, let alone type definition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aspidajs/aspida" rel="noopener noreferrer"&gt;Aspida&lt;/a&gt; fills this blind spot. Few HTTP client libraries on NPM provide this capability.&lt;/p&gt;

&lt;p&gt;In this article, I demonstrate how we can invoke Discourse API as an example in type-safe manner.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up Aspida
&lt;/h1&gt;

&lt;p&gt;You can setup Aspida according &lt;a href="https://github.com/aspidajs/aspida" rel="noopener noreferrer"&gt;the official README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since Aspida provides just an abstraction layer for type-safety, you need to chose one of HTTP client library as its back-end. Major libraries (&lt;a href="https://github.com/aspidajs/aspida/tree/master/packages/aspida-axios" rel="noopener noreferrer"&gt;axios&lt;/a&gt;, &lt;a href="https://github.com/aspidajs/aspida/tree/master/packages/aspida-ky" rel="noopener noreferrer"&gt;ky&lt;/a&gt;, &lt;a href="https://github.com/aspidajs/aspida/tree/master/packages/aspida-fetch" rel="noopener noreferrer"&gt;fetch&lt;/a&gt; and &lt;a href="https://github.com/aspidajs/aspida/tree/master/packages/aspida-node-fetch" rel="noopener noreferrer"&gt;node-fetch&lt;/a&gt;) seem to be supported.&lt;/p&gt;

&lt;p&gt;Here, I pick axios.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview of Discourse API
&lt;/h1&gt;

&lt;p&gt;You may know that &lt;a href="https://www.discourse.org/" rel="noopener noreferrer"&gt;Discourse&lt;/a&gt; is an open source discussion platform. &lt;/p&gt;

&lt;p&gt;I try accessing an instance of Discourse via its Web API and show the names of visible Categories in the forum for demonstration.&lt;/p&gt;

&lt;p&gt;Discourse API is a simple RESTful API, with &lt;a href="https://docs.discourse.org/" rel="noopener noreferrer"&gt;nice and sufficient documentation&lt;/a&gt;. I'm not so fluent about the API, but it seems to cover almost all of its functionalities.&lt;/p&gt;

&lt;p&gt;Since &lt;a href="https://ichiji.social/@tnzk" rel="noopener noreferrer"&gt;I'm the Server Admin of a Mastodon server&lt;/a&gt;, I chose &lt;a href="https://discourse.joinmastodon.org/" rel="noopener noreferrer"&gt;Mastodon Meta Discussion Board&lt;/a&gt; for an example :)&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating Type definition
&lt;/h1&gt;

&lt;p&gt;First of all, we need the type definition.&lt;/p&gt;

&lt;p&gt;You can assign types for the response and request parameters of your favorite APIs with Aspida, by putting type definition files in &lt;code&gt;$REPO_ROOT/apis/&lt;/code&gt; like:&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;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CategoryList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;can_create_category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;can_create_topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;draft_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;draft_sequence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt; &lt;span class="o"&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;text_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topic_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;post_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topic_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;logo_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;background_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;read_restricted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;notification_level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;can_edit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topic_template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;has_children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topics_day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topics_week&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topics_month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topics_year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;topics_all_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description_excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;resBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;category_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CategoryList&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time I put this as &lt;code&gt;categories.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a hand-crafted type definition ™️ looking up &lt;a href="https://docs.discourse.org/#tag/Categories" rel="noopener noreferrer"&gt;the API documentation&lt;/a&gt; 💪&lt;/p&gt;

&lt;h1&gt;
  
  
  Building the Type definition
&lt;/h1&gt;

&lt;p&gt;Once you have created the type definition, you need to build before using in application:&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;yarn run aspida &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be happier by having this defined in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Invoking the API in Application
&lt;/h1&gt;

&lt;p&gt;Now you can invoke the API in type-safe manner! You can write your application like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dotenv&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;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;aspida&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;@aspida/axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&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;../apis/$api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CategoryList&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;../apis/categories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&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;axiosConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://discourse.joinmastodon.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&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;Accept&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="c1"&gt;//        'Api-Username': process.env.DISCOURSE_API_USERNAME,&lt;/span&gt;
&lt;span class="c1"&gt;//        'Api-Key': process.env.DISCOURSE_API_KEY,&lt;/span&gt;
    &lt;span class="p"&gt;}&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;aspida&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;axiosConfig&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;;(&lt;/span&gt;&lt;span class="k"&gt;async &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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;category_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;category_list&lt;/span&gt;
            &lt;span class="nx"&gt;category_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;cat&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="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&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;It seems you need to import types explicitly if you want enable code-completion.&lt;/p&gt;

&lt;p&gt;Also, you can pass Axios options at instantiation of Aspida. I had confirmed it worked well with headers for authentication.&lt;/p&gt;

&lt;p&gt;This results:&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;yarn run start
Server administration
General
Core development
App development
Translation
Meta feedback
Feedback
Done &lt;span class="k"&gt;in &lt;/span&gt;10.56s.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fi%2Fjhg8u8v7ym1n90on6go2.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%2Fi%2Fjhg8u8v7ym1n90on6go2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks good 👍&lt;/p&gt;

&lt;p&gt;You can see complete code at: &lt;a href="https://github.com/tnzk/aspida-demo" rel="noopener noreferrer"&gt;https://github.com/tnzk/aspida-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You're now embraced in type system, so you won't break a thing like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;category_list.categories.forEach(cat =&amp;gt; console.log(cat.name * 1))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;because this will be detected &lt;strong&gt;at compile time&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/discourse-list-category.ts:25:65 - error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.

25             category_list.categories.forEach(cat =&amp;gt; console.log(cat.name * 1))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Upnext
&lt;/h1&gt;

&lt;p&gt;Aspida has another interesting functionality which automatically build type definitions from OpenAPI Specification.&lt;/p&gt;

&lt;p&gt;Since Discourse API provides it, we'll try this in next article :)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>aspida</category>
    </item>
  </channel>
</rss>
