<?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: Andrew Luchuk</title>
    <description>The latest articles on DEV Community by Andrew Luchuk (@speratus).</description>
    <link>https://dev.to/speratus</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%2F393577%2F6b04ceaa-83fa-4388-ad69-0cd2599e34df.png</url>
      <title>DEV Community: Andrew Luchuk</title>
      <link>https://dev.to/speratus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/speratus"/>
    <language>en</language>
    <item>
      <title>Simplify your frontend with Inertia JS</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Wed, 30 Jul 2025 16:11:00 +0000</pubDate>
      <link>https://dev.to/speratus/simplify-your-frontend-with-inertia-js-4lmp</link>
      <guid>https://dev.to/speratus/simplify-your-frontend-with-inertia-js-4lmp</guid>
      <description>&lt;p&gt;I sometimes want to integrate a frontend framework like Vue or React with Django.&lt;/p&gt;

&lt;p&gt;There's only one major problem: maintainability. If I build the frontend of my application using a JavaScript framework, I will have to maintain multiple  repositories and create APIs to facilitate communication between the frontend and  the backend. Since I often develop projects on my own, setting up an API can be a prohibitive amount of extra work.&lt;/p&gt;

&lt;p&gt;Fortunately there's a solution: &lt;a href="https://inertiajs.com/" rel="noopener noreferrer"&gt;Inertia JS&lt;/a&gt;. Inertia allows you to replace the view layer of your full stack framework with your frontend framework of choice.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Inertia JS offers
&lt;/h1&gt;

&lt;p&gt;Here are some other reasons you might want to try Inertia.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity:&lt;/strong&gt; Inertia cuts out the complexity of an additional API layer between your backend and frontend. It also eliminates one of the more complex aspects of frontend frameworks in my experience: client-side routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A familiar full stack workflow:&lt;/strong&gt; instead of communicating with the frontend using an API, Inertia uses the traditional approach: controllers and views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced development time:&lt;/strong&gt; because you no longer need an API, you can reduce the amount of time needed to complete your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified maintenance:&lt;/strong&gt; the lack of an API layer means that maintaining your application is simpler due to the reduction in code dedicated to server-client communications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might think that by using the typical full stack approach, you would lose one of the core benefits of frontend frameworks: seamless transitions between pages. Surprisingly, Inertia is able to maintain seamless page-to-page transitions without sacrificing the traditional full stack structure.&lt;/p&gt;

&lt;p&gt;Inertia is not a one-size fits all solution. If you intend to build an API for your backend for a reason other than purely communicating with the frontend, Inertia may be unnecessary. Similarly, if you do not need the seamless page-to-page transition user experience that frontend frameworks offer, Inertia probably isn't the best choice. If your site is primarily intended to present information to readers (like a CMS) and complex user interaction is not required, Inertia might introduce pointless complexity.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to get started
&lt;/h1&gt;

&lt;p&gt;That said, if Inertia would be useful for you, getting started with Inertia JS is pretty simple.&lt;/p&gt;

&lt;p&gt;Inertia is designed for Laravel, so if you are building a Laravel application, then following the &lt;a href="https://inertiajs.com/server-side-setup" rel="noopener noreferrer"&gt;official setup documentation&lt;/a&gt; is the best way to get started.&lt;/p&gt;

&lt;p&gt;On the other hand, setting up Inertia with Django is more complicated. The Inertia community has already built an adapter for Django, so you won't have to build your own tool kit to get Inertia and Django working together. Because Inertia is intended mainly for use with Laravel, the documentation for getting it set up with Django is&lt;br&gt;
less descriptive and straightforward.&lt;/p&gt;

&lt;p&gt;Fortunately, I have created a simple solution to get Inertia and Django up and running right away. I've created a &lt;a href="https://github.com/speratus/django-inertia-template-react" rel="noopener noreferrer"&gt;GitHub repository template&lt;/a&gt; that you can use to scaffold Django with Inertia, React, and Tailwind CSS in just a few clicks. The first step is to go to the repository's &lt;a href="https://github.com/speratus/django-inertia-template-react" rel="noopener noreferrer"&gt;GitHub page&lt;/a&gt; and click "Use this template". The template is configured so that Django should already have Inertia, React, and Tailwind CSS configured. If generating the project using a template would be helpful to you, please visit the repository to get started. I hope it helps you build your application in record time!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/speratus" rel="noopener noreferrer"&gt;
        speratus
      &lt;/a&gt; / &lt;a href="https://github.com/speratus/django-inertia-template-react" rel="noopener noreferrer"&gt;
        django-inertia-template-react
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A template repository for bootstrapping a Django project with InertiaJS and React
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Django Inertia Template (React)&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This is a template repository for bootstrapping an application based on the following stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.djangoproject.com/" rel="nofollow noopener noreferrer"&gt;Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://inertiajs.com/" rel="nofollow noopener noreferrer"&gt;Inertia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://react.dev/" rel="nofollow noopener noreferrer"&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vite.dev/" rel="nofollow noopener noreferrer"&gt;Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/" rel="nofollow noopener noreferrer"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The first step for using this template is to create a new repository based on this template.&lt;/p&gt;
&lt;p&gt;Once your new repository is created, you will likely want to take a number of customization steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Change the name of the application. There are two parts to this
a. Rename the &lt;code&gt;webapp&lt;/code&gt; directory to the name of your application
b. Update python references to the &lt;code&gt;webapp&lt;/code&gt; package to the name of your application. For example, in the &lt;code&gt;settings.py&lt;/code&gt; file, you will need to change the &lt;code&gt;ROOT_URLCONF&lt;/code&gt; property and &lt;code&gt;WSGI_APPLICATION&lt;/code&gt; property so that they reference the new package name instead of &lt;code&gt;webapp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rename the default &lt;code&gt;app&lt;/code&gt; app to a more descriptive name. Similarly to step 1, you will also need to replace any python references to…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/speratus/django-inertia-template-react" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>django</category>
      <category>react</category>
      <category>inertiajs</category>
      <category>python</category>
    </item>
    <item>
      <title>I'm Starting a dev log</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Wed, 04 Sep 2024 20:48:30 +0000</pubDate>
      <link>https://dev.to/speratus/im-starting-a-dev-log-49eb</link>
      <guid>https://dev.to/speratus/im-starting-a-dev-log-49eb</guid>
      <description>&lt;p&gt;It's been a while since I posted anything on dev. I've been trying out new things and exploring a lot of software, but I haven't really thought that I had much insight into what I was working on. Maybe I'm selling myself short, but that's how I've felt.&lt;/p&gt;

&lt;p&gt;Well, I'm trying something new. I'm starting a dev log. &lt;/p&gt;

&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;For a while now, I've been working on a game. I have enjoyed RTS games and 4X games for a while, but my biggest complaint with them is that they take forever to complete a single game. I'm talking 2+ hours to complete one game of Age of Empires, or 10+ hours for a single game of Sid Meier's Civilization. For me, this is a pretty huge time commitment. &lt;/p&gt;

&lt;p&gt;So, a while ago, I began building my own 4X RTS game with the goal of having a single round being completable within a range of thirty minutes to an hour. For now, I'm calling the game &lt;strong&gt;Exaforge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At the moment, there's not a ton to show for this game, but I've found that sharing my progress in projects regularly helps me to stay motivated and keep up with the project. And, that's the reason I'm starting this dev log. Again, I don't feel like I'm particularly insightful into the world of game development, but I'd like to share my journey in building this game, and if you're interested, you'll be able to follow along.&lt;/p&gt;

&lt;p&gt;I plan to be releasing the log mainly on YouTube, but when I'm able, I'll probably post updates here as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Exaforge?
&lt;/h2&gt;

&lt;p&gt;If this whole endeavor sounds appealing to you, keep reading and I'll tell you a bit more about the game.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exaforge&lt;/strong&gt; is set in an out of the way corner of the galaxy where a number of civilizations have developed relatively peacefully alongside each other. Right before the start of the game, however, an alien species called the Kryllan Collective has invaded the sector and conquered all the civilizations. &lt;/p&gt;

&lt;p&gt;Despite their military prowess, they know they will not be able to rule the sector on their own, so they have setup a contest for the civilizations in the sector to determine which civilization is most worthy of ruling the others. They call this contest the exaforge. The winning civilization will be made the ruler of the sector.&lt;/p&gt;

&lt;p&gt;But the Kryllan Collective has displayed some cracks in its veneer of undefeatable power, and the civilization that you control not only aspires to win the exaforge, but to escape the clutches of the Kryllan Collective and save its people from the Kryllan Collective's tyranny. There are three potential paths of escape: military unity with your neighboring civilizations, scientific study of advanced technical artifacts which may enable your people to transcend the bounds of space and time, and finally, cultural hegemony that overtakes the Kryllan Collective's own, leaving them open to having their own leaders replaced with your own.&lt;/p&gt;

&lt;p&gt;Which path will you choose?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where can I find updates?
&lt;/h2&gt;

&lt;p&gt;If this project sounds interesting, you can follow me here on dev where I may post updates.&lt;/p&gt;

&lt;p&gt;The best place to find updates, though will be on YouTube where I plan to post regularly. The channel is called &lt;a href="https://www.youtube.com/@exaforge-dev" rel="noopener noreferrer"&gt;Exaforge dev log&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's the first video in the dev log:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/tLXinLqTjUE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/@exaforge-dev?sub_confirmation=1" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Subscribe on YouTube&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;If you have any questions, I'd love to answer them in the comments!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>development</category>
      <category>devlog</category>
    </item>
    <item>
      <title>What Alternatives to VS Code do you use?</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Mon, 29 Jan 2024 00:18:22 +0000</pubDate>
      <link>https://dev.to/speratus/what-alternatives-to-vs-code-do-you-use-52a1</link>
      <guid>https://dev.to/speratus/what-alternatives-to-vs-code-do-you-use-52a1</guid>
      <description>&lt;p&gt;What, if any, alternatives to VS Code do you recommend? I think VS Code is a pretty great editor, but I have some objections to it which have been stacking up for some time now, and I'm looking for something that could potentially replace it.&lt;/p&gt;

&lt;p&gt;If you have any suggestions, I'd love to hear them! Here are the things I'm currently prioritizing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast (read "not an Electron app"), preferably relatively small memory/CPU footprint.&lt;/li&gt;
&lt;li&gt;Not owned by Microsoft&lt;/li&gt;
&lt;li&gt;Excellent out of the box language support for many mainstream languages, &lt;em&gt;or&lt;/em&gt; a plugin ecosystem which has plugins to that add support for those languages&lt;/li&gt;
&lt;li&gt;Smart refactoring tools (sometimes find and replace isn't good enough)&lt;/li&gt;
&lt;li&gt;A strong plugin ecosystem. I like to make use of advanced debugging tools when they are available. Also, good plugins can go a long way toward quality of life features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Alternative's I'm considering
&lt;/h3&gt;

&lt;p&gt;I have tried or looked into a few alternatives, but I'm not sold on any of them yet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://lapce.dev/" rel="noopener noreferrer"&gt;Lapce&lt;/a&gt;. Seems solid, but the plugins often seem like they are out of date and there's no way to tell whether they are except by trying them out. Also, even though Rust has good language support, I've found some of the other language support to be lacking.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gnu.org/software/emacs/" rel="noopener noreferrer"&gt;Emacs&lt;/a&gt;. I've been hearing about Emacs lately, so I'm considering looking into it in more depth, but I haven't yet. I guess have two main concerns with Emacs: 1) I'm not sure how many advanced features it offers because I'm not sure what it's plugin ecosystem is like, and 2) How good is Emacs' Windows support?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zed.dev/" rel="noopener noreferrer"&gt;Zed&lt;/a&gt;. I'm really excited about this option as it seems very promising, but I only use Windows and Linux 😥&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.vim.org/" rel="noopener noreferrer"&gt;Vim&lt;/a&gt;/&lt;a href="https://neovim.io/" rel="noopener noreferrer"&gt;Neovim&lt;/a&gt;. These tools have been around for a long time and are pretty performant according to my understanding, but from my experience, they don't seem to have many features beyond syntax highlighting, and I'd prefer more advanced features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear any suggestions from the community! Also, if you have any thoughts about the editors I've already tried, I'd love to hear those too!&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Designing a Full-Featured Web Synthesizer</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Mon, 05 Jun 2023 15:45:00 +0000</pubDate>
      <link>https://dev.to/speratus/designing-a-full-featured-web-synthesizer-p80</link>
      <guid>https://dev.to/speratus/designing-a-full-featured-web-synthesizer-p80</guid>
      <description>&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;I ended my last post with a working prototype of a Rust and WebAssembly based synthesizer using &lt;code&gt;wasm-pack&lt;/code&gt; to build the JavaScript wrappers. Now that the prototype is complete, it's time to start designing and building a more feature-complete synthesizer.&lt;/p&gt;

&lt;p&gt;This update will be short compared with previous entries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Here is an overview of the architecture I plan to use for the synthesizer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6suovwkoh7ld9horgci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6suovwkoh7ld9horgci.png" alt="Design Diagram" width="800" height="1296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The entry point for the synthesizer will be a wrapper struct that starts the process of fully synthesizing the sound:&lt;/p&gt;

&lt;p&gt;The wrapper starts by sending information about  the note that should be playing to the oscillator bank which will use that information to generate the initial audio buffers. From there, the audio buffer will be passed along the chain of modifiers to apply filters and other transformations to the audio. Finally, the audio buffer will be returned to the wrapper to be passed back to the best available audio device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this design?
&lt;/h2&gt;

&lt;p&gt;I chose this design to keep the code base as flexible as possible. I eventually want to turn the synthesizer into a plugin for &lt;a href="https://en.wikipedia.org/wiki/Digital_audio_workstation" rel="noopener noreferrer"&gt;digital audio workstations&lt;/a&gt;. To achieve that goal, I want to make the design as generic as possible so that it will be easily compatible with many different plugin formats.&lt;/p&gt;

</description>
      <category>architecture</category>
    </item>
    <item>
      <title>How I used wasm-pack to build a WebAssembly module for an AudioWorkletProcessor</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Mon, 15 May 2023 15:45:00 +0000</pubDate>
      <link>https://dev.to/speratus/how-i-used-wasm-pack-to-build-a-webassembly-module-for-an-audioworkletprocessor-4aa7</link>
      <guid>https://dev.to/speratus/how-i-used-wasm-pack-to-build-a-webassembly-module-for-an-audioworkletprocessor-4aa7</guid>
      <description>&lt;p&gt;If you haven't been following this series, I have been building a synthesizer in &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; and &lt;a href="https://webassembly.org/" rel="noopener noreferrer"&gt;WebAssembly&lt;/a&gt;. The advantage of using WebAssembly is that I can take advantage of all of Rust's features while simultaneously avoiding the pitfalls of trying to use the operating system's complex libraries for playing audio.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Last Solution Was Not Ideal
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/speratus/i-built-this-despite-a-flaw-in-rusts-webassembly-toolchain-38p2"&gt;In the last post&lt;/a&gt;, I arrived at a working, but less than ideal solution for importing WebAssembly into an &lt;code&gt;AudioWorkletProcessor&lt;/code&gt;. Even though I couldn't initially figure out how to import a WebAssembly module into a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Using_AudioWorklet" rel="noopener noreferrer"&gt;worklet&lt;/a&gt; using &lt;code&gt;wasm-pack&lt;/code&gt;, the process of doing so without &lt;code&gt;wasm-pack&lt;/code&gt; enabled me to identify a potential solution that uses &lt;code&gt;wasm-pack&lt;/code&gt;.&lt;br&gt;
The next step was trying to implement it.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Better Idea
&lt;/h2&gt;

&lt;p&gt;Once I understood the process of importing a WebAssembly module into a worklet, doing so using &lt;code&gt;wasm-pack&lt;/code&gt; proved to be fairly simple. There are two general steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compile the WebAssembly module using the &lt;code&gt;wasm-pack&lt;/code&gt; &lt;code&gt;web&lt;/code&gt; target. The &lt;code&gt;web&lt;/code&gt; target creates JavaScript code that works without a bundler or Node.&lt;/li&gt;
&lt;li&gt;Copy the JavaScript into the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; file and adapt it to the context of &lt;code&gt;AudioWorkletGlobalScope&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;Since the &lt;code&gt;web&lt;/code&gt; target is meant to work without the need for a bundler, the resulting JvaScript code can be copied into the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; file and will only require minor changes. This approach is currently the best option because the &lt;code&gt;AudioWorkletGlobalScope&lt;/code&gt; lacks the features required to import WebAssembly modules.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing the Solution
&lt;/h2&gt;

&lt;p&gt;The first step is to build the Rust code with the &lt;code&gt;web&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;wasm-pack build &lt;span class="nt"&gt;--target&lt;/span&gt; web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once the code is compiled, I opened the JavaScript file named "_bg.js". This file contains the WebAssembly bindings generated by &lt;code&gt;wasm-pack&lt;/code&gt;. I copied everything in this file and pasted into my &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; class. This is the only way to get the JavaScript bindings into the &lt;code&gt;AudioWorkletGlobalScope&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, I copied the &lt;code&gt;.wasm&lt;/code&gt; file to a location where the browser could load it using &lt;code&gt;fetch()&lt;/code&gt;. At the top of my worklet file, I had the following code which I knew would need to be adjusted.&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="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wasm&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;cachedTextDecoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ignoreBOM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fatal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;cachedTextDecoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&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;cachedUint8Memory0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUint8Memory0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteLength&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// wasm-pack generated code ...&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I replaced this code with the following:&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="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wasm&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;cachedTextDecoder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// decode call will be made later&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUint8Memory0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteLength&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedUint8Memory0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// wasm-pack generated JavaScript&lt;/span&gt;

&lt;span class="c1"&gt;// Notice, I removed the exports.&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;An Instance of &lt;code&gt;TextDecoder&lt;/code&gt; class needs to be available in the &lt;code&gt;AudioWorkletGlobalScope&lt;/code&gt;, but the audio worklet scope does not allow the &lt;code&gt;TextDecoder&lt;/code&gt; class's constructor to be used. I used the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt;'s &lt;code&gt;MessagePort&lt;/code&gt; to give the audio worklet a &lt;code&gt;TextDecoder&lt;/code&gt; instance.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting Up the WebAssembly Module
&lt;/h3&gt;

&lt;p&gt;In order to pass the WebAssembly module to the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt;, I knew I would need to call &lt;code&gt;WebAssembly.compile()&lt;/code&gt; in the main thread and pass it to my audio processor. To do this, I needed to call both &lt;code&gt;fetch()&lt;/code&gt; and &lt;code&gt;WebAssembly.compileStreaming()&lt;/code&gt; like this:&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="c1"&gt;// index.js&lt;/span&gt;

&lt;span class="c1"&gt;// We will need the worklet node later.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-synth-proto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compileStreaming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/library.wasm&lt;/span&gt;&lt;span class="dl"&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;module&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Pass the module to the AudioWorkletProcessor&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I originally did this in an &lt;code&gt;async&lt;/code&gt; function so that I could use &lt;code&gt;await&lt;/code&gt; to get the return value directly. Here, I'm using a callback with a promise because this pattern is more common.&lt;br&gt;
Once I had a &lt;code&gt;WebAssembly&lt;/code&gt; module instance, I passed it to the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; using the &lt;code&gt;MessagePort&lt;/code&gt; instance like this:&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="c1"&gt;// index.js&lt;/span&gt;

&lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compileStreaming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/library.wasm&lt;/span&gt;&lt;span class="dl"&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;module&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Now that the module has been created, it can be passed to the processor.&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init-wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;wasmData&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Using the Module in the AudioWorkletProcessor
&lt;/h3&gt;

&lt;p&gt;To use the WebAssembly module, it needed to be instantiated from inside the audio worklet thread. The first step in this process was to set up a message listener for for the &lt;code&gt;MessagePort&lt;/code&gt; instance. I did this in the constructor of the &lt;code&gt;AudioWorkletProcessor&lt;/code&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="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onmessage&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;onmessage&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Check to make sure the message we receive is the correct type.&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init-wasm&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="c1"&gt;// Finish instantiating the WebAssembly module&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;Now that there is an &lt;code&gt;onmessage&lt;/code&gt; listener for the &lt;code&gt;MessagePort&lt;/code&gt;, the worklet can listen for the message sent by the main thread.&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="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onmessage&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;onmessage&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Check to make sure the message we receive is the correct type.&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init-wasm&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="nx"&gt;cachedTextDecoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Load returns a promise&lt;/span&gt;
            &lt;span class="nf"&gt;load&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;wasmData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getImports&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;mod&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Once the WebAssembly module has been instantiated, it needs to be finalized&lt;/span&gt;
                &lt;span class="c1"&gt;// so that it can be accessed later.&lt;/span&gt;
                &lt;span class="nf"&gt;finalizeInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mod&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="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once the worklet receives the WebAssembly module from the main thread, it needs to call the &lt;code&gt;load()&lt;/code&gt; function copied from the wasm-pack output so that the WebAssembly module can be properly instantiated. Finally, the audio processor thread needs to call the &lt;code&gt;finalizeInit()&lt;/code&gt; function to ensure that it can continue to access the WebAssembly code.&lt;/p&gt;

&lt;p&gt;Now that all the setup is complete, the audio thread can use the &lt;code&gt;SineOsc&lt;/code&gt; struct by calling the JavaScript wrapper functions.&lt;br&gt;
Here is how I setup the oscillator:&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="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onmessage&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;onmessage&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Check to make sure the message we receive is the correct type.&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init-wasm&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="nx"&gt;cachedTextDecoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Load returns a promise&lt;/span&gt;
            &lt;span class="nf"&gt;load&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;wasmData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getImports&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;mod&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Once the WebAssembly module has been instantiated, it needs to be finalized&lt;/span&gt;
                &lt;span class="c1"&gt;// so that it can be accessed later.&lt;/span&gt;
                &lt;span class="nf"&gt;finalizeInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mod&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="c1"&gt;// Create the oscillator instance.&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;osc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SineOsc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleRate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now that the audio thread has created an oscillator, that oscillator can be called to do the actual sound generation.&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="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;osc&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;osc&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Get the first output channel.&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="nx"&gt;output&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;channel&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// populate the channel's buffer with samples from the WebAssembly code.&lt;/span&gt;
                &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Remember the first argument for the sample method is the pitch we want to &lt;/span&gt;
                    &lt;span class="c1"&gt;// synthesize and the second argument is the volume.&lt;/span&gt;
                    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;osc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wasm not instantiated yet&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  What Next?
&lt;/h2&gt;

&lt;p&gt;At this point, I have demonstrated how to  adapt &lt;code&gt;wasm-pack&lt;/code&gt;'s output so that it can be used in an &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; file. The next step is to start building out the features necessary for a usable synthesizer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you want to read more about this project, feel free to follow me or read my other posts in this series.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Introduction to the series:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/speratus" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393577%2F6b04ceaa-83fa-4388-ad69-0cd2599e34df.png" alt="speratus"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Building a Browser-Based Synthesizer Using Rust and WebAssembly&lt;/h2&gt;
      &lt;h3&gt;Andrew Luchuk ・ Apr 19 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#rust&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webassembly&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Source code for this prototype:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/speratus" rel="noopener noreferrer"&gt;
        speratus
      &lt;/a&gt; / &lt;a href="https://github.com/speratus/web-synth-proto2" rel="noopener noreferrer"&gt;
        web-synth-proto2
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Web Synthesizer prototype 2
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Websynth Prototype&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This project is a proof of concept for using Rust to generate samples for a Web Audio API backed synthesizer.&lt;/p&gt;
&lt;p&gt;You can read an introductiont to the project on &lt;a href="https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl" rel="nofollow"&gt;dev.to&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Dependencies&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;To build this project you will need the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rust-lang.org/" rel="nofollow noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rustwasm.github.io/wasm-pack/installer/" rel="nofollow noopener noreferrer"&gt;wasm-pack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Building&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;To build the Rust components of this project, simply run&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;wasm-pack build --target web&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;See &lt;a href="https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl" rel="nofollow"&gt;this post&lt;/a&gt; for details regarding how to integrate it into a web page.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;This project can be run using Visual Studio Code's "Live Server" extension. Simply install it, and follow the instructions to go live.
Once you have the server running, navigate to the "www" directory to see the web page.&lt;/p&gt;
&lt;p&gt;If you don't have Visual Studio Code, you should also be able to open &lt;code&gt;index.html&lt;/code&gt; in the &lt;code&gt;www&lt;/code&gt; directory in any modern web browser
Although I haven't thoroughly tested this method, I don't think you will run…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/speratus/web-synth-proto2" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>rust</category>
      <category>javascript</category>
      <category>webassembly</category>
    </item>
    <item>
      <title>How to Use Rust Code in a JavaScript Worklet (Without wasm-pack)</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Fri, 28 Apr 2023 16:00:00 +0000</pubDate>
      <link>https://dev.to/speratus/i-built-this-despite-a-flaw-in-rusts-webassembly-toolchain-38p2</link>
      <guid>https://dev.to/speratus/i-built-this-despite-a-flaw-in-rusts-webassembly-toolchain-38p2</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl"&gt;I recently posted about how I have wanted to build a synthesizer and that I finally found the technologies I needed to make it happen.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step in my project was to build a prototype. The first step of this process was to generate a sine wave and have it be played through the speakers. Once I had achieved this first step, I could start building more complex features on this foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;After taking a good look through the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API" rel="noopener noreferrer"&gt;Web Audio API documentation&lt;/a&gt;, I decided that the best way for my synthesizer to output sound to the speakers was through the use of the &lt;code&gt;AudioWorkletNode&lt;/code&gt; combined with an &lt;code&gt;AudioWorkletProcessor&lt;/code&gt;. This combination of two nodes would allow me to generate audio in a background thread which could then be played through the speakers.&lt;/p&gt;

&lt;p&gt;If I wanted to take a different approach, I would need to extend &lt;code&gt;AudioNode&lt;/code&gt; and implement the audio generation by using much less documented features. Since I could find no documentation on extending &lt;code&gt;AudioNode&lt;/code&gt;, I wanted to avoid extending it for as long as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing an Oscillator
&lt;/h2&gt;

&lt;p&gt;Now I was ready to start writing Rust code. Almost all the documentation and tutorials I was able to find online recommend using &lt;a href="https://rustwasm.github.io/wasm-pack/installer/" rel="noopener noreferrer"&gt;&lt;code&gt;wasm-pack&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once I had followed the setup tutorials, I added the following code to my &lt;code&gt;lib.rs&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[wasm_bindgen]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;SineOsc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cycler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[wasm_bindgen]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SineOsc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// This number is the base from which `sine` is calculated&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;consts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.sample_rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cycler&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Keeps track of the position within the wave&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cycler&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Reset position if it gets too large&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cycler&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.sample_rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cycler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Control the volume by multiplying gain by the sine.&lt;/span&gt;
        &lt;span class="n"&gt;gain&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="nf"&gt;.sin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;SineOsc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;At this point, I had a basic oscillator. Passing a pitch (in hertz) and gain value between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; to the &lt;code&gt;sample()&lt;/code&gt; function would produce a single number which can be added to the audio buffer. Calling &lt;code&gt;sample()&lt;/code&gt; repeatedly produces the sequence of numbers need to create an audible sine wave.&lt;/p&gt;

&lt;p&gt;To build this project, I ran &lt;code&gt;wasm-pack build&lt;/code&gt; which compiles the Rust code to a &lt;code&gt;.wasm&lt;/code&gt; file and generates JavaScript bindings which can be used to call the Rust code. I integrated my newly generated &lt;code&gt;.wasm&lt;/code&gt; file into my prototype JavaScript code. And that's when I started running into problems.&lt;/p&gt;
&lt;h2&gt;
  
  
  Roadblocks
&lt;/h2&gt;

&lt;p&gt;In order to use an &lt;code&gt;AudioWorkletNode&lt;/code&gt;, one must first set up a separate file with a class that extends the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; interface in it. The &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; class must be defined in a separate file because the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; interface only exists in the &lt;code&gt;AudioWorkletGlobalScope&lt;/code&gt; which is an independent thread from the main thread of JavaScript execution. Because JavaScript does not support multithreading, any multi-threaded behavior must be achieved using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API" rel="noopener noreferrer"&gt;Web Workers API&lt;/a&gt; - which can only run a JavaScript file in the background instead of branching like typical multi-threaded applications.&lt;/p&gt;

&lt;p&gt;At first, I tried to follow the tutorials' instructions for importing my newly minted WebAssembly package. But based on the console errors I kept getting, I quickly discovered that the &lt;code&gt;AudioWorkletGlobalContext&lt;/code&gt; does not support importing modules.&lt;/p&gt;

&lt;p&gt;Next, I tried to copy and paste the code from the JavaScript package directly into the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; file and load it from there. But the &lt;code&gt;AudioWorkletGlobalScope&lt;/code&gt; doesn't support &lt;code&gt;fetch()&lt;/code&gt; which is required to read the &lt;code&gt;.wasm&lt;/code&gt; file behind the scenes, so this solution didn't work either.&lt;/p&gt;

&lt;p&gt;I then tried passing the imported JavaScript package from the main JavaScript file to the &lt;code&gt;AudioWorkletProcessor&lt;/code&gt; via &lt;code&gt;AudioWorkletNode&lt;/code&gt;'s &lt;code&gt;MessagePort&lt;/code&gt; instance. That didn't work because using the &lt;code&gt;MessagePort&lt;/code&gt; relies on the objects being passed being copyable, and JavaScript functions are not copyable. I tried variant after variant of these solutions, and nothing I did could get it to work.&lt;/p&gt;

&lt;p&gt;Eventually, I stumbled upon this GitHub issue:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/drager/wasm-pack/issues/689" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Support using wasm-pack in Worklets (particularly AudioWorklet)
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#689&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Smona" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F7091399%3Fv%3D4" alt="Smona avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Smona" rel="noopener noreferrer"&gt;Smona&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/drager/wasm-pack/issues/689" rel="noopener noreferrer"&gt;&lt;time&gt;Jul 21, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;💡 Feature description&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;One of the key use cases for WebAssembly is audio processing. wasm-pack doesn't currently support AudioWorklets (purportedly the future of custom audio processing on the web) with any of its current &lt;code&gt;--target&lt;/code&gt; options.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;web&lt;/code&gt; and &lt;code&gt;no-modules&lt;/code&gt; targets get close, but error out during instantiation because the AudioWorklet context is lacking several browser APIs which the JS wrappers expect. This problem may extend to other Worker/Worklet contexts, but I've only attempted this with AudioWorklets.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;💻 Basic example&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;my_processor.worklet.js&lt;/p&gt;
&lt;div class="highlight highlight-source-js js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-v"&gt;MyProcessor&lt;/span&gt; &lt;span class="pl-k"&gt;extends&lt;/span&gt; &lt;span class="pl-v"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-en"&gt;constructor&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-smi"&gt;super&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-k"&gt;import&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"../pkg/audio"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;then&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;module&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-smi"&gt;this&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;_wasm&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;module&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;

  &lt;span class="pl-en"&gt;process&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;inputs&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;outputs&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;parameters&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-c1"&gt;!&lt;/span&gt;&lt;span class="pl-smi"&gt;this&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;_wasm&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-c1"&gt;true&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;

    &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;output&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;outputs&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-c1"&gt;0&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;
    &lt;span class="pl-smi"&gt;this&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;_wasm&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;exports&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;process&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;this&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;_outPtr&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-smi"&gt;this&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;_size&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;channel&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt; &lt;span class="pl-s1"&gt;channel&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pl-s1"&gt;output&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;length&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt; &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;channel&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-s1"&gt;output&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s1"&gt;channel&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;set&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;this&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;_outBuf&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;

    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-c1"&gt;true&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/drager/wasm-pack/issues/689" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Finally, I knew why I couldn't figure out how to make this work. The answer was simple, &lt;code&gt;wasm-pack&lt;/code&gt; does not support Worklet compilation targets.&lt;/p&gt;

&lt;p&gt;In my opinion, this is a significant deficiency in the Rust to WebAssembly toolchain because Worklets are some of the use cases which could most benefit from using WebAssembly. Worklets are used to do computation intensive tasks in the background, tasks which could further be optimized by offloading them to WebAssembly code that runs at near-native speeds.&lt;/p&gt;

&lt;p&gt;This discovery was proved to be a major roadblock to getting a prototype working, but I wasn't out of ideas yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;I did a few quick searches, and discovered that Rust actually already has a WebAssembly compilation target &lt;em&gt;built in&lt;/em&gt;. Unfortunately, because the features that &lt;code&gt;wasm-pack&lt;/code&gt; provides are so much more useful than what are available using only the built in compilation target, there are basically no tutorials on how to use Rust WebAssembly without using &lt;code&gt;wasm-pack&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nonetheless, after some digging, I found an old project that compiled Rust WebAssembly code without using &lt;code&gt;wasm-pack&lt;/code&gt; and I adapted what I learned from that project to my use case.&lt;/p&gt;

&lt;p&gt;The cost of this approach was that I would no longer have JavaScript bindings for my Rust &lt;code&gt;struct&lt;/code&gt;s because the JavaScript bindings are a feature provided by &lt;code&gt;wasm-pack&lt;/code&gt;. So, I adapted my sampling function so that it no longer needed a &lt;code&gt;struct&lt;/code&gt; and this is what I ended up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;samplex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Does the same thing as above, but statelessly&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;consts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;gain&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="nf"&gt;.sin&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;from here, all I had to do was run&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo build &lt;span class="nt"&gt;--target&lt;/span&gt; wasm32-unknown-unknown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and it would produce a &lt;code&gt;.wasm&lt;/code&gt; file ready for use.&lt;/p&gt;

&lt;p&gt;I learned how to pass the WebAssembly module to a Worklet while reading the &lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/compile#using_compile" rel="noopener noreferrer"&gt;Mozilla Developer Network&lt;/a&gt; article on the &lt;code&gt;WebAssembly.compile()&lt;/code&gt; function. Armed with that knowledge, this is what my two JavaScript files ended up looking like:&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="c1"&gt;// index.js&lt;/span&gt;

 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startBtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start-sound&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Load and compile our WebAssembly module&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bin&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;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compileStreaming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/wasm_demo.wasm&lt;/span&gt;&lt;span class="dl"&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AudioContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Add our processor to the Worklet&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioWorklet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processor.js&lt;/span&gt;&lt;span class="dl"&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;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-synth-proto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init-wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;wasmData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Connect to the speakers&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Make sure sound can be stopped to prevent it from getting annoying&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stopBtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stop-sound&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;stopBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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="c1"&gt;// User must click to start sound&lt;/span&gt;
  &lt;span class="nx"&gt;startBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setup&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// processor.js&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSynthProcessor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AudioWorkletProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cycler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Setup `MessagePort` so we can receive WebAssembly &lt;/span&gt;
        &lt;span class="c1"&gt;// module from the main thread&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onmessage&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleRate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;onmessage&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Receive WebAssembly module from main thread&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init-wasm&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="c1"&gt;// Declare this as an async function so we can use `await` keyword&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// We need to instantiate the module to use it&lt;/span&gt;
                    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mod&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;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instantiate&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;wasmData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_wasm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mod&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Caught error in instantiating wasm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&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="c1"&gt;// Call the setup function            &lt;/span&gt;
            &lt;span class="nf"&gt;instance&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="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_wasm&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_wasm&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&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;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="nx"&gt;output&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;channel&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;880&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                    &lt;span class="c1"&gt;// Call our WebAssembly function&lt;/span&gt;
                    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_wasm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;samplex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sampleRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="c1"&gt;// Add Sample to audio buffer&lt;/span&gt;
                    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;resetPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleRate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;pitch&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resetPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wasm not instantiated yet&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="c1"&gt;// Must return `true` to continue processing audio&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="c1"&gt;// register our processor with the `AudioWorkletGlobalContext`&lt;/span&gt;
&lt;span class="nf"&gt;registerProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-synth-proto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebSynthProcessor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Time for Improvement
&lt;/h2&gt;

&lt;p&gt;While this new solution worked, it wasn't ideal because there was no good way for me to track state in the Rust code, which I knew would prove to be problematic once I started making my synthesizer more advanced.&lt;/p&gt;

&lt;p&gt;But, as I worked on redesigning my code to work without the need for &lt;code&gt;wasm-pack&lt;/code&gt;, the puzzle pieces started to fall into place, and I began to see that, despite its flaws, I might still be able to use &lt;code&gt;wasm-pack&lt;/code&gt; for this web-based synthesizer.&lt;/p&gt;

&lt;p&gt;All it would take is a little adapting...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In my next article, I will describe my attempt to reincorporate &lt;code&gt;wasm-pack&lt;/code&gt; into my synthesizer project.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Introduction to this project:&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/speratus" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393577%2F6b04ceaa-83fa-4388-ad69-0cd2599e34df.png" alt="speratus"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Building a Browser-Based Synthesizer Using Rust and WebAssembly&lt;/h2&gt;
      &lt;h3&gt;Andrew Luchuk ・ Apr 19 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#rust&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webassembly&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>rust</category>
      <category>javascript</category>
      <category>webassembly</category>
    </item>
    <item>
      <title>Building a Browser-Based Synthesizer Using Rust and WebAssembly</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Wed, 19 Apr 2023 13:00:00 +0000</pubDate>
      <link>https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl</link>
      <guid>https://dev.to/speratus/building-a-browser-based-synthesizer-using-rust-and-webassembly-3kpl</guid>
      <description>&lt;p&gt;Ever since I learned the math behind sine waves, I've been fascinated by the idea of building my own synthesizer, however rudimentary it might turn out to be.&lt;/p&gt;

&lt;p&gt;For those who don't know what a synthesizer is, it's a configurable software musical instrument which can generate periodic waves which can mimic the sounds of existing instruments, or create sounds that would be impossible to reproduce on any physical instrument.&lt;/p&gt;

&lt;p&gt;I loved the idea of directly applying mathematics to a problem and having it translate into a meaningful phenomenon. Then my imagination would run wild with all the things that I might be able to do with a self-made synthesizer.&lt;/p&gt;

&lt;p&gt;In practice, I can probably achieve anything I could imagine doing with a self-built synthesizer using a Digital Audio Workstation combined with a good synthesizer plugin, but that never stopped me from imagining.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Goals
&lt;/h2&gt;

&lt;p&gt;I've wanted to build a larger Rust project for a while now, and I realized that this would be a great language in which to build the synthesizer.&lt;/p&gt;

&lt;p&gt;Rust performs at a near-native level and doesn't have a garbage collector, making it ideal for applications that have to perform large numbers of operations per second.&lt;/p&gt;

&lt;p&gt;Depending on the file format and the desired audio quality, a synthesizer needs to generate between 44,100 and 192,000 points of data per second at a bare minimum, so clearly performance is going to matter in any medium to large synthesizer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blockers
&lt;/h2&gt;

&lt;p&gt;I had an idea and a language in which to build that idea. So, I began researching systems level APIs for sending an audio signal to a device's speakers. And then, almost immediately, I decided I didn't want to use system level APIs for playing audio.&lt;/p&gt;

&lt;p&gt;You see, I develop mainly on Windows, so after taking a rudimentary glance at the documentation for sending a signal to audio output devices on Windows, I began to realize that developing a solution for sending my newly generated audio signal to the speakers was going to be quite a bit harder than I had anticipated.&lt;/p&gt;

&lt;p&gt;This was in the days before ChatGPT and its power to almost immediately connect the dots for such sophisticated problems. As a result, I decided building a Synthesizer would be more trouble than I really wanted to put into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter The Web Audio API
&lt;/h2&gt;

&lt;p&gt;A few weeks ago, I was reading the Mozilla Developer Network docs and stumbled upon the &lt;a href="https://developer.mozilla.org/en-US/docs/web/api/web_audio_api" rel="noopener noreferrer"&gt;Web Audio API&lt;/a&gt;. Then, I had a flash of inspiration.&lt;/p&gt;

&lt;p&gt;I knew Rust could compile to &lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly" rel="noopener noreferrer"&gt;WebAssembly&lt;/a&gt; which is essentially a browser-based pseudo machine language that can have serious performance benefits over vanilla JavaScript.&lt;/p&gt;

&lt;p&gt;Now that I knew there was an API for playing audio in JavaScript, and even some APIs for &lt;em&gt;generating&lt;/em&gt; audio from JavaScript, all I had to do was build in Rust, compile to WebAssembly, and utilize the Web Audio API to do the hard work of sending the audio signal to the device speakers. This was the solution I was looking for to get my synthesizer started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Easier Said Than Done
&lt;/h2&gt;

&lt;p&gt;But, as often happens, I'm only two weeks into this project and have already encountered hurdles I could not have foreseen. These problems have forced me to push the existing solutions for both Rust-based WebAssembly and the Web Audio API to their limits to find a solution.&lt;/p&gt;

&lt;p&gt;I've had to abandon my starting codebase and restart several times just to find a solution for using WebAssembly in the context I needed it. But I have found a solution that works and is generic enough to be applicable to a wide variety of situations. In so doing, I have greatly increased my understanding of WebAssembly as a technology, and hopefully, in writing this, I will be able to expand your understanding too.&lt;/p&gt;

&lt;p&gt;In my next post, I will describe how I discovered a severe flaw in the current Rust toolchain for building WebAssembly and my current, rudimentary solution to compensate for that flaw.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>javascript</category>
      <category>webassembly</category>
    </item>
    <item>
      <title>What I Learned by Deploying a Discord Bot with Kubernetes</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Tue, 28 Feb 2023 03:12:03 +0000</pubDate>
      <link>https://dev.to/speratus/what-i-learned-by-deploying-a-discord-bot-with-kubernetes-22d6</link>
      <guid>https://dev.to/speratus/what-i-learned-by-deploying-a-discord-bot-with-kubernetes-22d6</guid>
      <description>&lt;p&gt;If you haven't seen my entry in the Linode + Dev Hackathon, I recently built a &lt;a href="https://dev.to/speratus/meet-casper-the-astral-librarian-bmf"&gt;Discord bot and deployed it on Linode's cloud using Kubernetes&lt;/a&gt;. As I was unfamiliar with &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;, I learned quite a lot from the process of deploying a working application with it.&lt;/p&gt;

&lt;p&gt;I thought I would share some of my thoughts from the experience as well as summarize the concepts that I learned to help anybody else interested in learning how to use Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Features I like
&lt;/h2&gt;

&lt;p&gt;Kubernetes offers several key features that I found very attractive formy project such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Automatic rebooting of failed containers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Container replication, meaning that if one instance of a container goes down, traffic is automatically redirected to a healthy container, preventing service interruptions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No downtime rollouts and rollbacks --- because containers can be replicated, updates and rollbacks can be deployed in such a way that the updates result in zero downtime for end users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, because containers can be distributed across multiple cloud machines, if one machine goes down, Kubernetes, can redirect all the web traffic to other healthy machines, again preventing disruptions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overall thoughts on using Kubernetes
&lt;/h2&gt;

&lt;p&gt;Overall, I really enjoyed using Kubernetes. Unlike most of the projects I have hosted on the cloud where I have to set up a cloud instance, log in, run a bunch of commands to configure it correctly, then setup a bunch of DNS records, change firewall rules, etc., using Kubernetes was really simple: create a cluster, run &lt;code&gt;kubectl apply -f&lt;/code&gt; several times,&lt;br&gt;
and my project was live.&lt;/p&gt;

&lt;p&gt;Getting to the point where I knew exactly which commands to run and how to setup my object files was a more difficult journey, but overall it was worth the time put into it.&lt;/p&gt;

&lt;p&gt;The other downside of running a project with Kubernetes is the cost. Running a Kubernetes cluster with the recommended number of machines in it is more expensive than I would typically prefer for a project, but if high availability is a priority, then a Kubernetes cluster is probably an investment that's worth the money.&lt;/p&gt;
&lt;h2&gt;
  
  
  Concepts I Learned
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Pod
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/" rel="noopener noreferrer"&gt;A Pod&lt;/a&gt; is the core unit of work in a Kubernetes environment. Pods the code you deployed in containers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/architecture/nodes/" rel="noopener noreferrer"&gt;Nodes&lt;/a&gt; represent the underlying hardware on which pods run. Pods are not necessarily tied to specific nodes and nodes do not need to be limited to running only one pod (or one single type of pod).&lt;/p&gt;

&lt;p&gt;It's important to separate the concept of nodes from the concept of code execution in Kubernetes because the nodes themselves aren't running your code, rather the pods run your code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/" rel="noopener noreferrer"&gt;Services&lt;/a&gt; group pods together under a single IP. Services are a little bit like load balancers. They take distributed pods and combine them under a single umbrella. Services are not one-to-one analogous to load balancers, though because services can group together different components under a single IP.&lt;/p&gt;

&lt;p&gt;For example, one could configure a microservice Pod and a website&lt;br&gt;
hosting Pod to be combined in a single service. Two different types of execution, one IP address for both types.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configmap
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/configuration/configmap/" rel="noopener noreferrer"&gt;Config maps&lt;/a&gt; are the most unfamiliar concept I had to deal with when deploying my Discord Bot. They way I used config maps, they were kind of like if I had a tiny redis database attached to a Pod that was pretending to be a file --- a little complicated, I know.&lt;/p&gt;

&lt;p&gt;Basically, in the pod, the configmap functions as a file. In the mind of the Kubernetes cluster, however, the config map is more like a bunch of key-value pairs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Secret
&lt;/h3&gt;

&lt;p&gt;Finally, the last Kubernetes concept I learned was the concept of&lt;br&gt;
&lt;a href="https://kubernetes.io/docs/concepts/configuration/secret/" rel="noopener noreferrer"&gt;Secrets&lt;/a&gt;. In my environment, the secrets I used functioned very similarly to environment variables, but with added security features to prevent them from being read directly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Would I recommend Kubernetes for your project?
&lt;/h2&gt;

&lt;p&gt;Possibly. If you want to learn Kubernetes, or want to create a project which is intended to have as little downtime as possible, then yes I would heartily recommend using a Kubernetes cluster. Otherwise, if you are planning on hosting a small project for friends and family that you don't intend to leave running for a long time, then Kubernetes is probably overkill.&lt;/p&gt;

&lt;p&gt;That said, I quite enjoyed the process of learning how to use and deploy a Kubernetes cluster and hope to help out anyone with a similar interest. I'm happy to answer any questions you might have below.&lt;/p&gt;

&lt;p&gt;Kubernetes Documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/home/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/home/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My entry in the Linode + Dev hackathon:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/speratus" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393577%2F6b04ceaa-83fa-4388-ad69-0cd2599e34df.png" alt="speratus"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/speratus/meet-casper-the-astral-librarian-bmf" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Meet Casper, the Astral Librarian ✨, A Discord Bot for Searching the Web&lt;/h2&gt;
      &lt;h3&gt;Andrew Luchuk ・ Feb 21 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#llm&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#claude&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#gemini&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#discuss&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>watercooler</category>
      <category>indonesia</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>Meet Casper, the Astral Librarian ✨, A Discord Bot for Searching the Web</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Tue, 21 Feb 2023 00:26:34 +0000</pubDate>
      <link>https://dev.to/speratus/meet-casper-the-astral-librarian-bmf</link>
      <guid>https://dev.to/speratus/meet-casper-the-astral-librarian-bmf</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;Casper, the Astral Librarian, is a &lt;a href="https://discord.com/developers/docs/intro" rel="noopener noreferrer"&gt;Discord bot&lt;/a&gt; for searching the internet. Unlike other web searching discord bots, Casper does not restrict search results to a single search engine, instead returning results from a whole host of search engines.&lt;/p&gt;

&lt;p&gt;Out of the box, Casper supports a number of features provided by the underlying search engine, &lt;a href="https://github.com/searxng/searxng" rel="noopener noreferrer"&gt;SearXNG&lt;/a&gt;, including searching specific engines by formatting queries like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;!&amp;lt;ENGINE_NAME&amp;gt; my search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For example,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;!reddit nvidia 3000 series review
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These features are described in greater detail in the &lt;a href="https://docs.searxng.org/user/index.html" rel="noopener noreferrer"&gt;SearXNG documentation&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a list of some of the search engines Casper currently supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;google&lt;/li&gt;
&lt;li&gt;bing&lt;/li&gt;
&lt;li&gt;duckduckgo&lt;/li&gt;
&lt;li&gt;qwant&lt;/li&gt;
&lt;li&gt;reddit&lt;/li&gt;
&lt;li&gt;stackoverflow&lt;/li&gt;
&lt;li&gt;github&lt;/li&gt;
&lt;li&gt;bitbucket&lt;/li&gt;
&lt;li&gt;gitlab&lt;/li&gt;
&lt;li&gt;docker hub&lt;/li&gt;
&lt;li&gt;deviant art&lt;/li&gt;
&lt;li&gt;imdb&lt;/li&gt;
&lt;li&gt;pypi&lt;/li&gt;
&lt;li&gt;npm&lt;/li&gt;
&lt;li&gt;packagist&lt;/li&gt;
&lt;li&gt;rubygems&lt;/li&gt;
&lt;li&gt;yahoo&lt;/li&gt;
&lt;li&gt;vimeo&lt;/li&gt;
&lt;li&gt;youtube&lt;/li&gt;
&lt;li&gt;twitter&lt;/li&gt;
&lt;li&gt;wolfram alpha&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to these features, I plan to add some exciting features like allowing users to add their own search engines to Casper as well as user and channel based customization options.&lt;/p&gt;

&lt;p&gt;If things go really well, I may also port Casper to other messaging platforms too!&lt;/p&gt;
&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Wacky Wildcards&lt;/li&gt;
&lt;li&gt;Integration Innovators&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;Discord invite link:&lt;br&gt;
&lt;a href="https://discord.com/api/oauth2/authorize?client_id=1056051428575170752&amp;amp;permissions=2147485696&amp;amp;scope=bot" rel="noopener noreferrer"&gt;Invite Casper to your Server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code:&lt;br&gt;
&lt;a href="https://github.com/speratus/indexor-discord-bot" rel="noopener noreferrer"&gt;https://github.com/speratus/indexor-discord-bot&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;Here is a series of screenshots demonstrating Casper in Use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1ft9ze74hukhvq6yp8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1ft9ze74hukhvq6yp8r.png" alt="Slash command suggestion" width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2b2gz8wycf1fj6stmph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2b2gz8wycf1fj6stmph.png" alt="Typing a search query" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgm2pwwix6xq0p13a4sef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgm2pwwix6xq0p13a4sef.png" alt="Results from the search" width="752" height="763"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Screenshots of Kubernetes config
&lt;/h4&gt;

&lt;p&gt;List of nodes in Kubernetes cluster according to Kubernetes control panel (identifying information has been removed):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnj6gavbzvbseew8mutxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnj6gavbzvbseew8mutxy.png" alt="Nodes in Kubernetes resource pool" width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same list, but showing the nodes running as instances running in Linode's control panel (identifying information has been removed):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsamn6ber6m103138tjvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsamn6ber6m103138tjvh.png" alt="Linodes incorporated into Kubernetes resource pool" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Casper is a Discord bot built with &lt;a href="https://python.org" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://discordpy.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;discord.py&lt;/a&gt;, &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;, &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;, and &lt;a href="https://github.com/searxng/searxng/tree/master" rel="noopener noreferrer"&gt;SearXNG.&lt;/a&gt;. The main goal of Casper is to allow users to search for web results directly from within Discord. Secondary goals include a high degree of flexibility, enabling users to search using their preferred search engine, and, to that end, supporting the widest array of search engines possible.&lt;/p&gt;

&lt;p&gt;Finally, Casper allows users to share search results with each other, enabling them to establish trust and common sources of information as well as a discussion of the quality of sources.&lt;/p&gt;

&lt;p&gt;There are several major components of Casper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/speratus/indexor-discord-bot" rel="noopener noreferrer"&gt;The bot itself&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/speratus/indexor-core" rel="noopener noreferrer"&gt;search library containing the main search features&lt;/a&gt;. This library is what will enable Casper to be ported to other messaging platforms&lt;/li&gt;
&lt;li&gt;The SearXNG Instance, powering web-wide searches&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;Main Casper source code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/speratus" rel="noopener noreferrer"&gt;
        speratus
      &lt;/a&gt; / &lt;a href="https://github.com/speratus/indexor-discord-bot" rel="noopener noreferrer"&gt;
        indexor-discord-bot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Discord Bot that searches everywhere on the internet
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Casper (Formerly, Indexor)&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Casper is a Discord bot that searches the web for you. Casper gets the best results from around the web and returns them
directly to your Discord channel.&lt;/p&gt;
&lt;p&gt;Unlike other web searching Discord bots, Casper is not restricted to getting results from a single search engine. Instead
Casper is powered by the metasearch engine &lt;a href="https://github.com/searxng/searxng" rel="noopener noreferrer"&gt;SearXNG&lt;/a&gt; to get results from many sources
simultaneously.&lt;/p&gt;
&lt;p&gt;In addition to Casper's current features, there are many exciting features planned for future updates, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple pages of results&lt;/li&gt;
&lt;li&gt;Results caching for faster response times&lt;/li&gt;
&lt;li&gt;Support for getting results from specific search engines&lt;/li&gt;
&lt;li&gt;User-Added search engines (Anything powered by the OpenSearch standard)&lt;/li&gt;
&lt;li&gt;Server and User based custom configurations&lt;/li&gt;
&lt;li&gt;Direct messaging the bot to get answers from anywhere on the web&lt;/li&gt;
&lt;li&gt;Support for other message platforms such as Slack, Telegram, Matrix.org, and others.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The easiest way to get Access to Casper is to follow…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/speratus/indexor-discord-bot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Search functionality core library:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/speratus" rel="noopener noreferrer"&gt;
        speratus
      &lt;/a&gt; / &lt;a href="https://github.com/speratus/indexor-core" rel="noopener noreferrer"&gt;
        indexor-core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Supporting library for the Casper Discord bot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Indexor Core&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;This library provides the core searching functionality required by the Casper discord bot. At the moment, its features
are fairly minimal, but the majority of Casper's planned features will be added here.&lt;/p&gt;
&lt;p&gt;Examples of which features will be supported by this library:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Results caching&lt;/li&gt;
&lt;li&gt;Improved support for getting results from specific search engines&lt;/li&gt;
&lt;li&gt;User based customization options&lt;/li&gt;
&lt;li&gt;User-added search engines&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;You can install &lt;code&gt;indexor_core&lt;/code&gt; by running the following command:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install git+https://github.com/speratus/indexor-core.git#egg=indexor_core&lt;/pre&gt;

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

&lt;/div&gt;
&lt;p&gt;Here is a basic usage example:&lt;/p&gt;
&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;indexor_core&lt;/span&gt;.&lt;span class="pl-s1"&gt;config&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-v"&gt;Config&lt;/span&gt;
&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;indexor_core&lt;/span&gt;.&lt;span class="pl-s1"&gt;searcher&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;search&lt;/span&gt;

&lt;span class="pl-s1"&gt;search_xng_instance_url&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;'https://example.com'&lt;/span&gt;

&lt;span class="pl-s1"&gt;c&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;Config&lt;/span&gt;(&lt;span class="pl-s1"&gt;engine_url&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;search_xng_instance_url&lt;/span&gt;)

&lt;span class="pl-s1"&gt;results&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;search&lt;/span&gt;(&lt;span class="pl-s"&gt;'hello world'&lt;/span&gt;, &lt;span class="pl-s1"&gt;c&lt;/span&gt;)&lt;/pre&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/speratus/indexor-core" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;&lt;br&gt;
The Indexor core library contains the primary search feature and will contain other planned features such as results caching and user based searching preferences.

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://mit-license.org/" rel="noopener noreferrer"&gt;MIT License&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I came up with the idea for Casper on a whim, thinking how interesting it would be to get search results directly in a Discord server.&lt;/p&gt;

&lt;p&gt;I also saw this as an opportunity learn a couple of technologies I had been interested in, but had never created any projects with: &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;I deployed Casper on top of Linode's Kubernetes engine. I chose Linode Kubernetes engine for this project so that it would be easy to scale, update and rollback as necessary. This also lets me exercise my interest in learning Kubernetes and deploying an application using it.&lt;/p&gt;

&lt;p&gt;To deploy Casper on Linode's Kubernetes engine, I had to overcome several obstacles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Packaging the source code as a Docker image to which I could transfer necessary project information while keeping it out of the source code for the sake of privacy
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; casper:1.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Creating a deployment for the SearXNG instances that had the configuration required to be compatible with the Casper source code
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng-deploy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng/searxng&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INSTANCE_NAME&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;casper-engine'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BASE_URL&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://n.n.n.n'&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;settings&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/searxng/settings.yml&lt;/span&gt;
              &lt;span class="na"&gt;subPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;settings.yml&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;settings&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng-settings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Creating a Kubernetes service for the SearXNG instances so that they could be load balanced as well as simultaneously enabling the Casper source to communicate with the instances and preventing the SearXNG instances from being accessible outside of the Kubernetes Cluster
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lb-searxng&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;searxng&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Creating a &lt;code&gt;configmap&lt;/code&gt; for the SearXNG instance that could be read as the &lt;code&gt;settings.yml&lt;/code&gt; file and which also includes the required values to enable Casper to function.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create configmap searxng-settings &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PATH/TO/FILE/searxng/settings.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Creating a Kubernetes secret to store the Discord bot's token without exposing it to outside access.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Creating a deployment for the bot itself which drew from the necessary secrets and had the proper environment variables to communicate with the SearXNG instances.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;casper-deploy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;casper&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;casper&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;casper-bot&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;speratus/casper:1.0.2&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DISCORD_TOKEN&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENGINE_URL&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://n.n.n.n'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once I had tested out each of these steps in detail and identified working settings for each component, deployment was as easy as running a few commands. Once that was done, Casper was live with no headaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; In these samples, I replaced IP address with &lt;code&gt;n&lt;/code&gt; to indicate that anybody wishing to follow along should use their own information instead. I also used &lt;code&gt;...&lt;/code&gt; to indicate regular values that need to be replaced with the information specific to your context as well.&lt;/p&gt;
&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;SearXNG's documentation for creating and running an instance:&lt;br&gt;
&lt;a href="https://docs.searxng.org/admin/index.html" rel="noopener noreferrer"&gt;https://docs.searxng.org/admin/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SearXNG Source:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/searxng" rel="noopener noreferrer"&gt;
        searxng
      &lt;/a&gt; / &lt;a href="https://github.com/searxng/searxng" rel="noopener noreferrer"&gt;
        searxng
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SearXNG is a free internet metasearch engine which aggregates results from various search services and databases. Users are neither tracked nor profiled.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="rst"&gt;
&lt;div&gt;
&lt;a href="https://searxng.org" rel="nofollow noopener noreferrer"&gt;&lt;img alt="SearXNG" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fsearxng%2Fsearxng%2Fmaster%2Fclient%2Fsimple%2Fsrc%2Fbrand%2Fsearxng.svg" width="512px"&gt;
&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;SearXNG is a &lt;a href="https://en.wikipedia.org/wiki/Metasearch_engine" rel="nofollow noopener noreferrer"&gt;metasearch engine&lt;/a&gt;. Users are neither tracked nor profiled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/searxng" rel="noopener noreferrer"&gt;&lt;img alt="Organization" src="https://camo.githubusercontent.com/59c4ae90c56a54b1472d4276514c5b8e601da4f0a5fec2d641e214aa8933ff56/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6f7267616e697a6174696f6e2d3330353066663f7374796c653d666c61742d737175617265266c6f676f3d73656172786e67266c6f676f436f6c6f723d6666662663616368655365636f6e64733d3836343030"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.searxng.org" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Documentation" src="https://camo.githubusercontent.com/6f751b53a08bc2fc55db95cfb33c574ed7838b7ec9c65c35a0e845c5a6a1acde/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63756d656e746174696f6e2d3330353066663f7374796c653d666c61742d737175617265266c6f676f3d72656164746865646f6373266c6f676f436f6c6f723d6666662663616368655365636f6e64733d3836343030"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/searxng/searxng/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img alt="License" src="https://camo.githubusercontent.com/8865dcb0346af3093c39a2d1d16c1ac1944a6b8e915905859c68e80a9a36c326/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f73656172786e672f73656172786e673f7374796c653d666c61742d737175617265266c6162656c3d6c6963656e736526636f6c6f723d3330353066662663616368655365636f6e64733d3836343030"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/searxng/searxng/commits/master/" rel="noopener noreferrer"&gt;&lt;img alt="Commits" src="https://camo.githubusercontent.com/d832c1c393099cc67abc9a120951dff9bb6ab8127f223350e698f5d82073648f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6d6d69742d61637469766974792f792f73656172786e672f73656172786e672f6d61737465723f7374796c653d666c61742d737175617265266c6162656c3d636f6d6d69747326636f6c6f723d3330353066662663616368655365636f6e64733d33363030"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://translate.codeberg.org/projects/searxng/" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Translated" src="https://camo.githubusercontent.com/a69c2bc53ee6d4fddb07ffc476cab98446ce1bf397442f78c3d09ce930c086a0/68747470733a2f2f696d672e736869656c64732e696f2f7765626c6174652f70726f67726573732f73656172786e673f7365727665723d68747470732533412532462532467472616e736c6174652e636f6465626572672e6f7267267374796c653d666c61742d737175617265266c6162656c3d7472616e736c6174656426636f6c6f723d3330353066662663616368655365636f6e64733d3836343030"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;To install SearXNG, see &lt;a href="https://docs.searxng.org/admin/installation.html" rel="nofollow noopener noreferrer"&gt;Installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To fine-tune SearXNG, see &lt;a href="https://docs.searxng.org/admin/settings/index.html" rel="nofollow noopener noreferrer"&gt;Configuration guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Further information on &lt;em&gt;how-to&lt;/em&gt; can be found &lt;a href="https://docs.searxng.org/admin/index.html" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;If you have questions or want to connect with others in the community,
we have two official channels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://matrix.to/#/#searxng:matrix.org" rel="nofollow noopener noreferrer"&gt;#searxng:matrix.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.libera.chat/?channel=#searxng" rel="nofollow noopener noreferrer"&gt;#searxng @ libera.chat&lt;/a&gt; (bridged to Matrix)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;
&lt;p&gt;See &lt;a href="https://github.com/searxng/searxng/blob/master/CONTRIBUTING.rst" rel="noopener noreferrer"&gt;CONTRIBUTING&lt;/a&gt; for more details.&lt;/p&gt;

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

&lt;/div&gt;
&lt;p&gt;This project is licensed under the GNU Affero General Public License (AGPL-3.0).
See &lt;a href="https://github.com/searxng/searxng/blob/master/LICENSE" rel="noopener noreferrer"&gt;LICENSE&lt;/a&gt; for more details.&lt;/p&gt;

&lt;/div&gt;



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


&lt;h4&gt;
  
  
  Planned Features
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Multiple pages of results&lt;/li&gt;
&lt;li&gt;Results caching for faster response times&lt;/li&gt;
&lt;li&gt;Improved support for getting results from specific search engines&lt;/li&gt;
&lt;li&gt;User-added search engines (Any sites supporting the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/OpenSearch" rel="noopener noreferrer"&gt;OpenSearch&lt;/a&gt; standard)&lt;/li&gt;
&lt;li&gt;Server and User based settings&lt;/li&gt;
&lt;li&gt;Direct messaging Casper to get results in addition to using the slash command&lt;/li&gt;
&lt;li&gt;Support for other messaging platforms such as Slack, Telegram, Matrix.org, and others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Unsupported features
&lt;/h5&gt;

&lt;p&gt;Currently, Casper does not support SearXNG's special queries features.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>claude</category>
      <category>gemini</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Making Our ⚛ Components Reusable♻️</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Sat, 01 Aug 2020 20:30:54 +0000</pubDate>
      <link>https://dev.to/speratus/making-our-components-reusable-4451</link>
      <guid>https://dev.to/speratus/making-our-components-reusable-4451</guid>
      <description>&lt;p&gt;React’s value add for frontend developers is that it makes single page web app development much easier by combining the well understood syntax of HTML with the scripting capabilities of JavaScript in an intuitive and convenient way.&lt;/p&gt;

&lt;p&gt;One of React’s &lt;em&gt;most important&lt;/em&gt; features that is easy for new developers to overlook is component reusability. We need to be building React components that are designed to be reused throughout the UI.&lt;/p&gt;

&lt;p&gt;I get it though, it can be hard to see how a component can be reused. I hope to be able to pass on some tips that I’ve learned during my journey into React to help keep components reusable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Start with the planning stage
&lt;/h1&gt;

&lt;p&gt;In the last post in the series, I broke down a series of wireframes into a component hierarchy. Detailed planning is the first step to identifying reusable components.&lt;/p&gt;

&lt;p&gt;When looking at a mockup or a wireframe, it’s critical to identify parts of the UI which are identical to other parts of the UI or are extremely similar but with minor variations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aristotle and UI
&lt;/h2&gt;

&lt;p&gt;The Greek philosopher Aristotle formalized thought regarding an object’s essence. According to Aristotle, an object’s essence is the set of characteristics that make the object what it is and without which it would not be what it is.&lt;/p&gt;

&lt;p&gt;For example, we could say that the essence of a button is its clickability. All buttons are clickable and perform some action when clicked. Similarly, if a part of a UI is never clickable, then we can say that it is not a button.&lt;/p&gt;

&lt;p&gt;In contrast to an object’s essence, Aristotle held that objects also have “accidental” characteristics. Basically what Aristotle meant by the term “accidental” is “not essential”. That is, an accidental characteristic is something which can be removed from an object without making the object something other than what it is.&lt;/p&gt;

&lt;p&gt;In our example, a button’s color, shape, or text would all be accidental characteristics because they can all be changed without making the button not a button. A red button is still a button.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In Aristotle’s thought, an “accidental” characteristic is not one which occurs by chance, but rather a characteristic which can be altered without changing the object into a different kind of object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How does all this relate to reusability ♻️?
&lt;/h2&gt;

&lt;p&gt;When identifying reusable components, first look for all the parts of the UI which share essential characteristics. Identify UI elements which are accidental characteristics of the components to which they belong, so that you can see all the features that it shares in common with similar components.&lt;/p&gt;

&lt;p&gt;Reusable components share the same set of essential characteristics in &lt;strong&gt;every&lt;/strong&gt; part of the UI, even though some of their accidental characteristics might change between parts of the UI.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building Reusable components
&lt;/h1&gt;

&lt;p&gt;If you haven’t already, create a new react app for our forum project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When it’s finished, navigate to the new project and install missing dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @mdi/js @mdi/react bulma rbx &lt;span class="se"&gt;\&lt;/span&gt;
  react-router react-router-dom &lt;span class="se"&gt;\ &lt;/span&gt;
  graphql-request redux react-redux &lt;span class="se"&gt;\ &lt;/span&gt;
  immer easy-redux-reducers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here’s a brief explanation of the dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://bulma.io" rel="noopener noreferrer"&gt;Bulma&lt;/a&gt;, &lt;a href="https://github.com/dfee/rbx" rel="noopener noreferrer"&gt;rbx&lt;/a&gt;: npm packages to use the bulma framework with react&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@mdi/js&lt;/code&gt;, &lt;code&gt;@mdi/react&lt;/code&gt;: packages to use the material design icon font with react&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;react-router&lt;/code&gt;, &lt;code&gt;react-router-dom&lt;/code&gt;: allows us to have multiple pages in one react app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;graphql-request&lt;/code&gt;: allows us to easily query our GraphQL backend.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://redux.js.org" rel="noopener noreferrer"&gt;redux&lt;/a&gt;, &lt;code&gt;react-redux&lt;/code&gt;: helps us manage complex application state&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://immerjs.github.io/immer/docs/introduction" rel="noopener noreferrer"&gt;immer&lt;/a&gt;: allows us to maintain immutability but also to modify state objects directly.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/speratus/easy-redux-reducers" rel="noopener noreferrer"&gt;easy-redux-reducers&lt;/a&gt;: a tiny package to eliminate the need for writing switch statements in redux reducers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once those are finished installing, we’re ready to begin building reusable components&lt;/p&gt;
&lt;h1&gt;
  
  
  Delete unnecessary files
&lt;/h1&gt;

&lt;p&gt;Remove the files &lt;code&gt;index.css&lt;/code&gt;, &lt;code&gt;app.css&lt;/code&gt;, &lt;code&gt;logo.svg&lt;/code&gt;, &lt;code&gt;favicon.ico&lt;/code&gt; and all the references to those files. We won’t need them and they’ll just get in the way.&lt;/p&gt;
&lt;h1&gt;
  
  
  Creating our first reusable component
&lt;/h1&gt;

&lt;p&gt;Let’s tackle the most reused component in our component hierarchy: &lt;code&gt;Field&lt;/code&gt;. If you look back at the last post, you’ll see that this field is probably the most reused component in the whole hierarchy.&lt;/p&gt;

&lt;p&gt;For clarity, I’m calling &lt;code&gt;Field&lt;/code&gt; &lt;code&gt;FormField&lt;/code&gt; in the actual code to reduce ambiguity since there is a &lt;code&gt;field&lt;/code&gt; component in Bulma.&lt;/p&gt;

&lt;p&gt;Here’s my code for &lt;code&gt;FormField&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;// src/components/FormField.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rbx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FormField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Field&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="nc"&gt;Label&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;props&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="nc"&gt;Label&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="nc"&gt;Control&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="nc"&gt;Input&lt;/span&gt; 
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
                &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&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="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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Control&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="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;FormField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;Field&lt;/code&gt;, &lt;code&gt;Label&lt;/code&gt;, &lt;code&gt;Control&lt;/code&gt;, and &lt;code&gt;Input&lt;/code&gt; components are all components from &lt;code&gt;rbx&lt;/code&gt; required to use Bulma styles and make sure that they stay consistent.&lt;/p&gt;

&lt;p&gt;Notice that I have not actually passed any values (other than the “text” property) to any of the components. This is key to keeping a component reusable. We need to make sure it behaves predictably in whatever context we use it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FormField&lt;/code&gt; does not maintain any state, but rather expects an &lt;code&gt;onChange&lt;/code&gt; prop so that it’s parent component can keep track of state management. Since &lt;code&gt;FormField&lt;/code&gt; is a functional component, getting the value of the &lt;code&gt;Input&lt;/code&gt; component would have been challenging.&lt;/p&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;TopicTitle&lt;/code&gt; component
&lt;/h2&gt;

&lt;p&gt;Let’s look at another example. Here’s my code for the &lt;code&gt;TopicTitle&lt;/code&gt; component:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rbx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TopicTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;onClick&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Title&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Title&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="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;withRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TopicTitle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This component displays the title of a topic and also acts as a link to the topic itself. Again, by using props, I can make this component highly reusable with minimal effort. I wrapped the whole component in &lt;code&gt;react-router&lt;/code&gt;’s &lt;code&gt;withRouter()&lt;/code&gt; function to enable it to properly integrate with the browser’s history API. &lt;/p&gt;
&lt;h1&gt;
  
  
  Go build some reusable♻️ components
&lt;/h1&gt;

&lt;p&gt;I hope I have been able to give you some tips regarding how to make React components reusable. As always, feel free to ask me questions in the comments.&lt;/p&gt;

&lt;p&gt;The code for this part of the series is available on &lt;a href="https://github.com/speratus/miniforum-frontend/tree/part1-reusability" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/speratus" rel="noopener noreferrer"&gt;
        speratus
      &lt;/a&gt; / &lt;a href="https://github.com/speratus/miniforum-frontend" rel="noopener noreferrer"&gt;
        miniforum-frontend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The React frontend for the Miniforum repo
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;This project was bootstrapped with &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Available Scripts&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;In the project directory, you can run:&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;code&gt;yarn start&lt;/code&gt;&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;Runs the app in the development mode.&lt;br&gt;
Open &lt;a href="http://localhost:3000" rel="nofollow noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; to view it in the browser.&lt;/p&gt;
&lt;p&gt;The page will reload if you make edits.&lt;br&gt;
You will also see any lint errors in the console.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;code&gt;yarn test&lt;/code&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Launches the test runner in the interactive watch mode.&lt;br&gt;
See the section about &lt;a href="https://facebook.github.io/create-react-app/docs/running-tests" rel="nofollow noopener noreferrer"&gt;running tests&lt;/a&gt; for more information.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;code&gt;yarn build&lt;/code&gt;&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Builds the app for production to the &lt;code&gt;build&lt;/code&gt; folder.&lt;br&gt;
It correctly bundles React in production mode and optimizes the build for the best performance.&lt;/p&gt;
&lt;p&gt;The build is minified and the filenames include the hashes.&lt;br&gt;
Your app is ready to be deployed!&lt;/p&gt;
&lt;p&gt;See the section about &lt;a href="https://facebook.github.io/create-react-app/docs/deployment" rel="nofollow noopener noreferrer"&gt;deployment&lt;/a&gt; for more information.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;code&gt;yarn eject&lt;/code&gt;&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note: this is a one-way operation. Once you &lt;code&gt;eject&lt;/code&gt;, you can’t go back!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you aren’t satisfied with the build tool and configuration…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/speratus/miniforum-frontend" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>react</category>
      <category>javascript</category>
      <category>reusable</category>
      <category>components</category>
    </item>
    <item>
      <title>Django Intro From a Rails Perspective</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Sat, 25 Jul 2020 19:12:58 +0000</pubDate>
      <link>https://dev.to/speratus/django-intro-from-a-rails-perspective-m52</link>
      <guid>https://dev.to/speratus/django-intro-from-a-rails-perspective-m52</guid>
      <description>&lt;p&gt;If you’re a new developer, you may have started off your web development journey by learning &lt;a href="https://rubyonrails.org/" rel="noopener noreferrer"&gt;Ruby on Rails&lt;/a&gt;. Rails is a great starting point, but maybe you now want to expand your horizons a bit and learn a new framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://djangoproject.com" rel="noopener noreferrer"&gt;Django&lt;/a&gt; is a good choice of a web framework, to extend your knowledge with. It’s well established and well supported with lots  of resources out there to help you learn. Here’s some of the basics that you’ll need to know before getting started.&lt;/p&gt;

&lt;p&gt;Django is written in Python which makes it a particularly excellent choice if you want to integrate an application with data science tools.&lt;/p&gt;

&lt;h1&gt;
  
  
  Top Django Challenges
&lt;/h1&gt;

&lt;p&gt;There are a few things that make the Django framework harder to work with than Rails. In some ways, these make it more difficult to use for beginners, though in my opinion, they are ultimately not much more challenging.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Django uses different names for things
&lt;/h2&gt;

&lt;p&gt;Rails is an MVC framework. Models, Views, and Controllers are clearly defined in Rails. Django, on the other hand, is not explicitly an MVC framework, although you can change some of the terms around to get something fairly similar to MVC.&lt;/p&gt;

&lt;p&gt;So here’s a translation of each of the major parts of MVC into Django’s terminology:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rails&lt;/th&gt;
&lt;th&gt;Django&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View&lt;/td&gt;
&lt;td&gt;Template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controller&lt;/td&gt;
&lt;td&gt;View&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can see why Django is confusing now. What Rails calls a &lt;code&gt;controller&lt;/code&gt;, Django calls a &lt;code&gt;view&lt;/code&gt;. Django views perform roughly the same function as Rails &lt;code&gt;controller&lt;/code&gt; actions, though. Each Django &lt;code&gt;view&lt;/code&gt; processes a request and returns a response. There are technical differences between how Rails &lt;code&gt;controller&lt;/code&gt; actions work and Django views, but the analogy is pretty solid.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Routing is more verbose
&lt;/h2&gt;

&lt;p&gt;Rails has a nice little DSL for defining routes to controller actions. Django developers, however, usually have to specify how each route maps to each view. &lt;/p&gt;

&lt;p&gt;A few years ago, Django developers had to use &lt;a href="https://ruby-doc.org/core-2.7.1/Regexp.html" rel="noopener noreferrer"&gt;regular expressions&lt;/a&gt; to describe url paths. If you’ve ever had to work with regular expressions you didn’t understand, you can imagine how frustrating that could be.&lt;/p&gt;

&lt;p&gt;Fortunately, these days Django has become more user-friendly and has made crafting url paths somewhat easier (but still not as convenient as Rails).&lt;/p&gt;

&lt;p&gt;Part of the reason Django’s routing is more difficult to understand is that Django does not follow Rails’ convention over configuration mentality. Rails expects developers to follow standard conventions, allowing rails to do some of the hard work for the developer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Top Django Benefits
&lt;/h1&gt;

&lt;p&gt;Don’t let Django’s greater difficulty deter you from trying it out, though. Django has some huge advantages over Rails in other areas.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. No More Migrations
&lt;/h2&gt;

&lt;p&gt;Rails developers have to run highly specific commands and write some boilerplate code to tell Rails how to change tables in the site’s database. Django developers, however, don’t often have to worry about writing migrations because Django takes care of migrations under the hood.&lt;/p&gt;

&lt;p&gt;Django models are written entirely in python code. When Django detects that a model has been changed, it’ll warn the developer that it’s time to make migrations. Actually creating the migrations is a super simple process: just run a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py makemigrations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Django will then figure out what’s changed in the model and update the schema accordingly. &lt;/p&gt;

&lt;p&gt;As a side note, the fact that Django models are written in Python is something I really appreciate because it means if I ever have questions about the current schema, I don’t have to open up a schema file and sift through unintuitive lists of ruby commands. Instead, I just open up the model I want to know about and the answer is right there.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Out of the box support for Authentication and Authorization
&lt;/h2&gt;

&lt;p&gt;If you’ve ever had to deal with authentication in Rails, you know that it can be super confusing the first couple of times. &lt;em&gt;(What is BCrypt and how do I get it to hash the password correctly, again? And once I have gotten all that sorted out, how exactly do I keep track of a user’s authentication status across requests?)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Django comes with an authentication system right out of the box. Django has a robust User model that already takes care of password hashing and authentication. Django even gives you views and templates to handle user registration, logging in, password resets, etc.&lt;/p&gt;

&lt;p&gt;Django also has an authorization system right out of the box to help developers control which users have access to which resources. Compared to Rails, this is a huge advantage, because in my opinion an application framework should have expectations regarding how authorization should work.&lt;/p&gt;

&lt;p&gt;In fact, Rails’ lack of an authorization is such a problem, that I actually wrote my own authorization library which is &lt;a href="https://rubygems.org/gems/rails-action-authorization" rel="noopener noreferrer"&gt;available on RubyGems&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/speratus" rel="noopener noreferrer"&gt;
        speratus
      &lt;/a&gt; / &lt;a href="https://github.com/speratus/rails-action-authorization" rel="noopener noreferrer"&gt;
        rails-action-authorization
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An authorization system for Ruby on Rails
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;There are other solutions for authorization for Rails, but I designed mine to be extremely lightweight.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Built in Administration tools
&lt;/h2&gt;

&lt;p&gt;Django has a built in administration site which developers can use to interact directly with the data in the database, allowing developers to create, update, and delete objects with ease. Granted, the Rails console allows developers to do many of the same things, but the fact that there is a pre-built dedicated site for administration is a huge advantage if a non-programmer team member needs to make some adjustments.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rails or Django, Which is Better?
&lt;/h1&gt;

&lt;p&gt;In my opinion, it really depends on the context to decide which is better. &lt;/p&gt;

&lt;p&gt;If you need to build an app in a really short time, rails might be the better option, as it is often quicker to build an app in Rails than in Django.&lt;/p&gt;

&lt;p&gt;On the other hand, if you need more flexibility than a RESTful application, Django might be a better choice as it doesn’t make any assumptions about what you’re building.&lt;/p&gt;

&lt;p&gt;If (for some reason) you &lt;em&gt;need&lt;/em&gt; your application to run on a Windows server, then Django is probably a better choice. Rails and Windows do not play nicely together in my experience.&lt;/p&gt;

&lt;p&gt;But if all you need is a small application that won’t have a lot of users and does one main job,  rails could be sufficient. It all depends on what you need.&lt;/p&gt;

&lt;p&gt;I hope you’ve found this guide useful, and I’d be happy to try to answer any questions you might have in the comments.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>django</category>
      <category>technology</category>
      <category>development</category>
    </item>
    <item>
      <title>Wireframes and Component Hierarchy</title>
      <dc:creator>Andrew Luchuk</dc:creator>
      <pubDate>Sun, 19 Jul 2020 18:44:01 +0000</pubDate>
      <link>https://dev.to/speratus/wireframes-and-component-hierarchy-53np</link>
      <guid>https://dev.to/speratus/wireframes-and-component-hierarchy-53np</guid>
      <description>&lt;p&gt;Welcome Back! It’s been a little bit longer than I planned between my last post in this series and this one, but I should be back on track soon. This series picks up where the last series left off:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/speratus" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393577%2F6b04ceaa-83fa-4388-ad69-0cd2599e34df.png" alt="speratus"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/speratus/backend-wrap-up-1lfd" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Backend Wrap Up&lt;/h2&gt;
      &lt;h3&gt;Andrew Luchuk ・ Jun 27 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Wireframes
&lt;/h1&gt;

&lt;p&gt;Wireframing helps developers by laying out the look of a UI in advance. Knowing how the UI will look is not only useful for making sure the UI is clean and usable, but also helps developers by enabling them to identify which parts of a UI can be reused.&lt;/p&gt;

&lt;p&gt;I’ve created a few &lt;em&gt;basic&lt;/em&gt; wireframes to give a simple idea of how the UI should be laid out when it’s done. As I’ve mentioned before, I am by no means the world’s best frontend engineer or UI designer, so I tried to make the UI look roughly like it is made up of &lt;a href="https://bulma.io/" rel="noopener noreferrer"&gt;Bulma&lt;/a&gt; components, which I’ll be using for the frontend.&lt;/p&gt;

&lt;p&gt;Users will be greeted with a sign in page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feicxkaq9efavc0ouxzax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feicxkaq9efavc0ouxzax.png" alt="Sign-in Wireframe" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If they do not have an account, they can click the sign up button to get one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcv42zjm5lz1g64r3vuff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcv42zjm5lz1g64r3vuff.png" alt="Sign-up Wireframe" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once logged in, users will be greeted by a list of posts, and after clicking one, they will see the post detail page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1vmzup41lxeytk3iprav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1vmzup41lxeytk3iprav.png" alt="Topic Wireframe" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there are replies to the topic, it will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft6a4ri5gsdqmny3unnsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft6a4ri5gsdqmny3unnsc.png" alt="Topic With Reply" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, when replying to a post, users will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhsd8rvts5qwlc16n0ilv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhsd8rvts5qwlc16n0ilv.png" alt="Reply form" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Component Hierarchy
&lt;/h1&gt;

&lt;p&gt;Once the wireframes are finished, we can begin to analyze the UI to identify reusable components of the UI. The UI analysis process is fairly straightforward. Essentially, the developer takes each part of the UI and breaks it down into components that can't be broken down any further.&lt;/p&gt;

&lt;p&gt;I'm not going to go through the whole process here because it would take many words to describe something which is much more easily understood through images. If analyzing the UI is new to you, then the React docs have an excellent tutorial to help you understand the process: &lt;a href="https://reactjs.org/docs/thinking-in-react.html" rel="noopener noreferrer"&gt;Thinking in React&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve gone ahead and created some simple charts to demonstrate how the components should work together. Identical names indicate that the component is to be reused in multiple places. Finally, since we will be using redux to share state across components, we won’t need to worry about making sure state flows in an easy way.&lt;/p&gt;

&lt;p&gt;For the Login page, the component tree will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7gsykhsuzm19sprggip8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7gsykhsuzm19sprggip8.png" alt="Sign-in Hierarchy" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sign up page components:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqqmictlcy6g4kzqrur89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqqmictlcy6g4kzqrur89.png" alt="Sign-up Hierarchy" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main page hierarchy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdmcslfszm4k8ncclyqwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdmcslfszm4k8ncclyqwx.png" alt="Main page Hierarchy" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, the topic page is going to be the most complex page with a hierarchy something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr4unextuy6yoz1ghmc2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr4unextuy6yoz1ghmc2y.png" alt="Topic page Component Hierarchy" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each reply is going to be made up of a few more components, much like the topic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fevql4xl0d2fwxpzo2zqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fevql4xl0d2fwxpzo2zqn.png" alt="Reply Hierarchy" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know it’s a lot to take in, but you won’t need to remember this, it just gives a skeleton around which to build the react page.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s next
&lt;/h1&gt;

&lt;p&gt;As promised, this post starts a new series (which is itself part of a larger series) covering the frontend of our mini forum application. &lt;/p&gt;

&lt;p&gt;Here’s the first post of the series:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/speratus" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393577%2F6b04ceaa-83fa-4388-ad69-0cd2599e34df.png" alt="speratus"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/speratus/build-a-forum-app-from-code-to-deploy-3lcc" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Build a Forum App, from Code to Deploy&lt;/h2&gt;
      &lt;h3&gt;Andrew Luchuk ・ May 23 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;In keeping with the plan laid out there, this series will cover the following topics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wireframing and component Hierarchy (this post)&lt;/li&gt;
&lt;li&gt;Writing tests for components and building the basic components&lt;/li&gt;
&lt;li&gt;Querying the backend with GraphQL&lt;/li&gt;
&lt;li&gt;Tying all the pieces together to complete the frontend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unfortunately, because I’m working on another project at the moment, I may not be able to post in this series every week, but I’ll do my best to keep on schedule.&lt;/p&gt;

&lt;p&gt;Thank you all for reading, and I hope you find it helpful!&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
  </channel>
</rss>
