<?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: yysun</title>
    <description>The latest articles on DEV Community by yysun (@yysun).</description>
    <link>https://dev.to/yysun</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%2F84039%2F2cae70eb-6ba6-456d-a34f-02f1032938bd.png</url>
      <title>DEV Community: yysun</title>
      <link>https://dev.to/yysun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yysun"/>
    <language>en</language>
    <item>
      <title>Bringing the LLM Wiki Idea to a Codebase</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Sun, 12 Apr 2026 20:43:09 +0000</pubDate>
      <link>https://dev.to/yysun/bringing-the-llm-wiki-idea-to-a-codebase-22go</link>
      <guid>https://dev.to/yysun/bringing-the-llm-wiki-idea-to-a-codebase-22go</guid>
      <description>&lt;p&gt;Andrej Karpathy’s LLM Wiki idea is compelling because it treats knowledge as something that can be gradually ingested, organized, queried, and improved over time. That same idea applies surprisingly well to a codebase.&lt;/p&gt;

&lt;p&gt;A repository is not just a pile of files. It is a living body of knowledge: architecture, concepts, flows, conventions, tradeoffs, and accumulated decisions. The challenge is that this knowledge is often scattered across source files, configs, docs, and human memory. A wiki built for an LLM can help turn that into something navigable.&lt;/p&gt;

&lt;p&gt;For code projects, the core ideas of &lt;strong&gt;ingest&lt;/strong&gt;, &lt;strong&gt;query&lt;/strong&gt;, and &lt;strong&gt;lint&lt;/strong&gt; still hold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ingest&lt;/strong&gt; builds and updates the project wiki from the source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query&lt;/strong&gt; uses the wiki plus source verification to answer questions about the codebase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lint&lt;/strong&gt; checks the wiki itself for drift, contradictions, missing coverage, and weak links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That already makes the LLM Wiki concept useful for software projects. But codebases have one advantage that many other knowledge collections do not: &lt;strong&gt;git&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why codebases are a particularly good fit
&lt;/h2&gt;

&lt;p&gt;Most project knowledge systems either rescan everything every time or rely on manual upkeep. A codebase, however, already has built-in version control. That gives us a natural way to make wiki maintenance incremental.&lt;/p&gt;

&lt;p&gt;The initial ingest can be based on the repository at &lt;code&gt;HEAD&lt;/code&gt;. After that, the wiki records the last ingested commit. Future ingests do not need to rescan the whole repo. They only need to look at what changed between that saved commit and the new &lt;code&gt;HEAD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means git gives us, almost for free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changed-file detection&lt;/li&gt;
&lt;li&gt;rename and deletion tracking&lt;/li&gt;
&lt;li&gt;a natural checkpoint for incremental updates&lt;/li&gt;
&lt;li&gt;a practical way to mark stale wiki pages&lt;/li&gt;
&lt;li&gt;a much cheaper ingest loop over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the wiki stays grounded in the current codebase, while git provides the mechanism for maintaining it efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model
&lt;/h2&gt;

&lt;p&gt;The model is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ingest the project from &lt;code&gt;HEAD&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Save the current commit SHA in the wiki index&lt;/li&gt;
&lt;li&gt;On the next run, diff from &lt;code&gt;last_commit&lt;/code&gt; to &lt;code&gt;HEAD&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update only the affected pages&lt;/li&gt;
&lt;li&gt;Advance the checkpoint only when the changed set has been fully processed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps &lt;code&gt;HEAD&lt;/code&gt; as the source of truth while using git history as the maintenance engine.&lt;/p&gt;

&lt;p&gt;That distinction matters. The wiki is not meant to become a commit log or historical archive. Its main job is to explain the project as it exists now. Git just makes it possible to keep that explanation fresh without starting from scratch every time. The uploaded skill draft reflects exactly that approach: source of truth is git-tracked files at &lt;code&gt;HEAD&lt;/code&gt;, while incremental ingest is driven by the saved &lt;code&gt;last_commit&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What the wiki should do
&lt;/h2&gt;

&lt;p&gt;A code-project wiki is most useful when it acts as a structured knowledge layer over the repository.&lt;/p&gt;

&lt;p&gt;It should capture things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;major features and modules&lt;/li&gt;
&lt;li&gt;important concepts and abstractions&lt;/li&gt;
&lt;li&gt;entities such as schemas, models, and types&lt;/li&gt;
&lt;li&gt;request or execution flows&lt;/li&gt;
&lt;li&gt;notable fixes and architecture shifts&lt;/li&gt;
&lt;li&gt;open gaps and stale areas worth revisiting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there, the three core workflows, ingest, query and lint become very natural.&lt;/p&gt;

&lt;p&gt;That is where the LLM Wiki idea becomes more than passive documentation. It becomes an active system for maintaining project understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent skill
&lt;/h2&gt;

&lt;p&gt;I packaged this idea as an agent skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add yysun/awesome-agent-world &lt;span class="nt"&gt;--skill&lt;/span&gt; git-wiki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is to make the pattern reusable: ingest the codebase once, keep a wiki under &lt;code&gt;.wiki&lt;/code&gt;, and then let the agent maintain it incrementally as the project evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;What makes the LLM Wiki idea powerful is not just that it produces summaries. It creates a feedback loop between source material, structured knowledge, and future questions.&lt;/p&gt;

&lt;p&gt;For a codebase, that loop is even stronger because git gives us a built-in notion of change. Instead of rebuilding understanding from scratch, we can carry it forward commit by commit.&lt;/p&gt;

&lt;p&gt;That is the real opportunity here: treat the repository not just as code, but as a knowledge system with memory, structure, and maintenance built in.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>wiki</category>
      <category>rag</category>
    </item>
    <item>
      <title>Effective Agent Instruction</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Wed, 25 Jun 2025 18:08:20 +0000</pubDate>
      <link>https://dev.to/yysun/effective-agent-instruction-2k20</link>
      <guid>https://dev.to/yysun/effective-agent-instruction-2k20</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;You would think AI coding is simply tell the coding agent what you want, and then you can sit back and enjoy the work AI has accomplished. Wrong! Often you return to find a thousand commits that have completely ruined your codebase, and far from your original intention.&lt;/p&gt;

&lt;p&gt;This is the reality of AI coding. The coding agent does not understand your requirements unless you provide them clearly. The agent will follow your instructions to the letter, but if those instructions are vague or incorrect, the results will be far from what you expected.&lt;/p&gt;

&lt;p&gt;In this article, I will share my experience of using AI coding agents like GitHub Copilot create a &lt;strong&gt;Statement of Work (SOW)&lt;/strong&gt; between you and the coding agent. This SOW approach will ensure that the agent delivers what you want, rather than what it thinks you want.&lt;/p&gt;

&lt;p&gt;Here is the workflow I have been using to create a SOW with AI coding agents.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define the Requirements&lt;/strong&gt;: I describe my requirements. No need to be robust. I let AI create the document for me with prompts like:"&lt;em&gt;focus on &lt;code&gt;what&lt;/code&gt;, not &lt;code&gt;how&lt;/code&gt;, not optimization&lt;/em&gt;". Once I have the requirement doc, I will ask AI to verify it: "&lt;em&gt;Review requirements → think hard ensure no flaw → provide suggestions → wait for confirmation.&lt;/em&gt;"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implementation Plan&lt;/strong&gt;: Once both AI and I are happy with the requirement doc, I will ask AI to create an implementation: "&lt;em&gt;Create a implementation plan → save to &lt;code&gt;docs/plan/plan-{name}.md&lt;/code&gt; → wait for confirmation.&lt;/em&gt;"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tests and Acceptance Criteria&lt;/strong&gt;: A good new is that AI usually creates the test scenrios and acceptance criteria automatically. I do a final review and approve AI to proceed with the implementation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can see are many repeaititive steps in the process of typing same prompts again and again. To make it easier, I have created a set of command aliasin in CLAUDE.md for Claude Code. Or in copilot-ininstructions.md for GitHub Copilot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command Alias
&lt;/h2&gt;

&lt;p&gt;I have the following as the custom prompt to the coding agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Command Keywords&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**!!**&lt;/span&gt;: Create requirements → focus on &lt;span class="sb"&gt;`what`&lt;/span&gt;, not &lt;span class="sb"&gt;`how`&lt;/span&gt;, no plan → save to &lt;span class="sb"&gt;`docs/requirements/req-{name}.md`&lt;/span&gt; → wait for confirmation;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**AA**&lt;/span&gt;: Create a detailed functional implementation plan (no optimization) as check list → save the list to &lt;span class="sb"&gt;`docs/plan/plan-{name}.md`&lt;/span&gt; → wait for confirmation;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**AP**&lt;/span&gt;: Review requirements → think hard ensure no flaw → provide suggestions → wait for confirmation;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**AS**&lt;/span&gt;: Execute plan → implement step-by-step → mark done in plan → git stage changed and commit;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**!!!**&lt;/span&gt;: Update the requirements, plan, and implement;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Workflow
&lt;/h2&gt;

&lt;p&gt;I usually following the steps below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I describe ideas and !! to create a requirement document.&lt;/li&gt;
&lt;/ul&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%2Fwzxw7nifd7mssm4tqjg4.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%2Fwzxw7nifd7mssm4tqjg4.png" alt="\!\!Create Requirements" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When requirements are ready, I use a lot AP, AP, AP … to review and confirm the requirements.&lt;/li&gt;
&lt;/ul&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%2Fscsgw6b4cxy4hxu4kg8f.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%2Fscsgw6b4cxy4hxu4kg8f.png" alt="AP - Review Requirements" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then, I use &lt;code&gt;AA&lt;/code&gt; to create an implementation plan. AI analyzes the current code base and identifies what needs to be change.&lt;/li&gt;
&lt;/ul&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%2Fwfsc2bza9m2cgpqa7es5.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%2Fwfsc2bza9m2cgpqa7es5.png" alt="AS - Create Implementation Plan" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not rush to implement yet. Use &lt;code&gt;AP&lt;/code&gt; again and again to ensure the plan is right. You will be supprized.&lt;/li&gt;
&lt;/ul&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%2Ft1sxjoiv7x33hjmhf8ll.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%2Ft1sxjoiv7x33hjmhf8ll.png" alt="AP - Review Implementation Plan" width="800" height="425"&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%2Ftz7wn9pkxgm6asgwj29c.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%2Ftz7wn9pkxgm6asgwj29c.png" alt="Clarify Questions" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only when we are cool with plan, I will use &lt;code&gt;AS&lt;/code&gt; to let AI start implementation.&lt;/li&gt;
&lt;/ul&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%2F19v5mbuouldbivi5q8vs.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%2F19v5mbuouldbivi5q8vs.png" alt="AS - Implement the Plan" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, AI takes over and write code step by step.&lt;/li&gt;
&lt;/ul&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%2Fp2jizgm8u05lias5ryvl.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%2Fp2jizgm8u05lias5ryvl.png" alt="AI Execution" width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If I changed my mind, I can always use &lt;code&gt;!!!&lt;/code&gt; to update the requirements, plan, and implementation. AI will re-evaluate the plan and code accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After all, this approach will ensure the source code to have better chance to meet our requirements.&lt;/p&gt;

&lt;p&gt;We will also have good the requirement and execution result documentation.The documents are extremely important. We can use for analysis, verification and even reimplement in the future. They are the &lt;strong&gt;true source code&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. One More Thing
&lt;/h2&gt;

&lt;p&gt;The approach above applies to all coding agents. It does not require the code agents to provide facilitates on things like design mode, ask mode, act mode, and etc. Just use plain old prompts, the LLM is smart enough to understand the command alias to execute the workflow including when to start to code.&lt;/p&gt;

&lt;p&gt;It worked very well for me in the GitHub Copilot Agent Mode with Claude Sonnet 3/4. Not so well with GPT and Gemini though.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Conclusion
&lt;/h2&gt;

&lt;p&gt;The coding paradigm is shifting, from vibe coding to effective agent instruction. By creating a SOW between you and the coding agent, you can ensure the agent will deliver what you want. By using the command alias, you can speed up the process and concentrate on the requirements and implementation plan, rather than the typing prompts again and again.&lt;/p&gt;

&lt;p&gt;BTW, Here is Github repository that contains the command alias &lt;a href="https://github.com/yysun/collage-cli" rel="noopener noreferrer"&gt;collage-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding with AI!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>vibecoding</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>AI-Powered Documentation: Make Your Codebase Self-Explanatory</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Fri, 06 Jun 2025 22:18:42 +0000</pubDate>
      <link>https://dev.to/yysun/ai-powered-documentation-make-your-codebase-self-explanatory-231g</link>
      <guid>https://dev.to/yysun/ai-powered-documentation-make-your-codebase-self-explanatory-231g</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Andrej Karpathy recently introduced the idea of &lt;a href="https://x.com/karpathy/status/1886192184808149383" rel="noopener noreferrer"&gt;"vibe coding" on X (formerly Twitter)&lt;/a&gt;, which is a process where we develop apps but &lt;strong&gt;"forget that the code even exists"&lt;/strong&gt;. I believe in this approach, but I also have a fundamental need: code understanding: what AI has executed; does it fulfill requirements, and is it safe? &lt;/p&gt;

&lt;p&gt;Through documentation can solve the problem. Imagine opening a project, you will see a &lt;code&gt;docs&lt;/code&gt; folder that has the architecture, features, and changes documents. And each source code file contains a comment block about what it is for, how it works. These documents can help us understand the code base better.  &lt;/p&gt;

&lt;p&gt;However, documentation is a difficult task. In fact, according to the Agile practices, due to time constraints, comprehensive documentation is sometimes sacrificed in favor of rapid coding and delivery. Can we even expect having up-to-date documents? &lt;/p&gt;

&lt;p&gt;Well, the good news is that AI can do the documentation tasks.  In this post, we’ll explore two powerful prompts you can ask AI to do the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Describe Each Source File
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure each source file begins with a comment block summarizing its purpose and logic.

&lt;ul&gt;
&lt;li&gt;If no block exists, create one before editing.&lt;/li&gt;
&lt;li&gt;After completing changes, update this block to reflect the changes.&lt;/li&gt;
&lt;li&gt;Always make the comment block clear and concise.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This prompt will add a comment block to source code files summarizing its purpose and logic. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below is a simple example.&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="cm"&gt;/**
 * userController.js
 *
 * Purpose:
 *   - Handles HTTP requests related to user accounts.
 *     • GET /users/:id → fetch user by ID
 *     • POST /users    → create a new user
 *     • PUT /users/:id → update user information
 *     • DELETE /users/:id → delete a user
 *
 * Logic Overview:
 *   1. Validate request payloads (using Joi schema).
 *   2. Interact with UserService to perform CRUD operations on the database.
 *   3. Send appropriate HTTP status codes and JSON responses.
 *
 * Last Updated:
 *   2025-06-05  by Jane Doe (Refactored to use async/await and centralized error handler)
 */&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;validateUserPayload&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;../validators/userValidator&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="nx"&gt;UserService&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;../services/UserService&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;handleError&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;../utils/errorHandler&lt;/span&gt;&lt;span class="dl"&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&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;user&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;UserService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;err&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="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;// …rest of the CRUD handlers…&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having a comment block for each file is helpful because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It explains what the file is for and how it generally works. The information is good for human and for AI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By reading the comments, AI the overall design context, special logic or important points. AI can generate code more acuurately and prevent accidental errors or unintended consequences.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It provide valueable detail for bothcode review and security analysis in the future.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Make a Feature Documentation Library
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure features are documented in the &lt;code&gt;./docs&lt;/code&gt; directory.

&lt;ul&gt;
&lt;li&gt;Before modifying code, review existing files in &lt;code&gt;./docs&lt;/code&gt; to understand current implementation.&lt;/li&gt;
&lt;li&gt;If no appropriate documentation exists, create a new Markdown file in &lt;code&gt;./docs&lt;/code&gt; outlining your analysis.&lt;/li&gt;
&lt;li&gt;After completing changes, update or add documentation in &lt;code&gt;./docs&lt;/code&gt; to match the new code.&lt;/li&gt;
&lt;li&gt;Finally, check the &lt;code&gt;./docs&lt;/code&gt; folder to see which files exist and decide if any need updating or deletion based on your changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you’re adding a new “Bulk Email” feature to your CRM. Here’s how an AI generated document could look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Bulk Email Feature&lt;/span&gt;

&lt;span class="gu"&gt;## Purpose&lt;/span&gt;
Allow admins to send a templated email to multiple contacts at once.

&lt;span class="gu"&gt;## High-Level Flow&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Admin uploads a CSV of email addresses  
&lt;span class="p"&gt;2.&lt;/span&gt; System validates addresses via &lt;span class="sb"&gt;`validateCSV()`&lt;/span&gt;  
&lt;span class="p"&gt;3.&lt;/span&gt; API enqueues emails in SendGrid batch queue  
&lt;span class="p"&gt;4.&lt;/span&gt; Worker process sends out messages and logs results

&lt;span class="gu"&gt;## Data Model&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`EmailBatch`&lt;/span&gt; (id, templateId, status, createdAt)  
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`EmailRecipient`&lt;/span&gt; (batchId, email, status, errorMessage)

&lt;span class="gu"&gt;## API Endpoints&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`POST /api/bulk-email/start`&lt;/span&gt;  
  • Request Body: &lt;span class="sb"&gt;`{ templateId: string, csvFile: File }`&lt;/span&gt;  
  • Response: &lt;span class="sb"&gt;`{ batchId: string }`&lt;/span&gt;  
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`GET /api/bulk-email/status/:batchId`&lt;/span&gt;  
  • Response: &lt;span class="sb"&gt;`{ status: "pending" | "in_progress" | "completed", sentCount: number, failedCount: number }`&lt;/span&gt;

&lt;span class="gu"&gt;## Validation Rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; CSV file max 10,000 rows  
&lt;span class="p"&gt;-&lt;/span&gt; Template must exist and be enabled  
&lt;span class="p"&gt;-&lt;/span&gt; Rate limit: 1 email batch per 5 minutes per org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have a&lt;code&gt;docs&lt;/code&gt; foler that contains many such markdown files house deeper explanations — API design decisions, architecture diagrams, usage examples, and more.&lt;/p&gt;

&lt;p&gt;Instead of scattering notes, diagrams, or instructions across private notes or comments, the dedicated &lt;code&gt;./docs&lt;/code&gt; is a sigle source of truth everyone knows exactly where to look. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Automate the Documentation
&lt;/h2&gt;

&lt;p&gt;Writing the comment blocks and features documents once is great; keeping it current is game-changing. &lt;/p&gt;

&lt;p&gt;You can put these two prompts into your AI code assistants’ system prompts, they will take effect each time you ask AI to make changes. It will keep the documents up to date all the time.&lt;/p&gt;

&lt;p&gt;Each AI code assistant has its own way of customizing system prompts. In the case of Github Copilot, we can create and save the above in the file ‘./gihub/copilot-instructions.md, see &lt;a href="https://code.visualstudio.com/docs/copilot/copilot-customization" rel="noopener noreferrer"&gt;Customize chat responses in VS Code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Documenting code isn’t something to be sacrificed anymore. Using the two prompts as system prompts, AI will create comprehensive documents to make your repository friendly and self-explanatory. — saving you time, reducing confusion, and even helping AI itself when working on it in the future.&lt;/p&gt;

&lt;p&gt;Happy documenting!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>vide</category>
      <category>ai</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Elevate Your AI-Driven Coding Workflow</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Tue, 03 Jun 2025 16:30:56 +0000</pubDate>
      <link>https://dev.to/yysun/elevate-your-ai-driven-coding-workflow-596k</link>
      <guid>https://dev.to/yysun/elevate-your-ai-driven-coding-workflow-596k</guid>
      <description>&lt;p&gt;Working with AI code assistants like GitHub Copilot, you need more than just simple, one-off, “write code” prompts. You can use  some advanced techniques to create a structured, iterative process that ensures clarity, code quality, and alignment with your objectives. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Advanced AI-Driven Coding Techniques
&lt;/h2&gt;

&lt;p&gt;Here are some techniques I usually found useful and correspondent prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request a plan, review and confirm:&lt;/strong&gt; “provide your plan in a concise bullet list and wait for my confirmation before proceeding”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request multiple options:&lt;/strong&gt; “provide implementation options and comparisons and wait for me to confirm before proceeding”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate step by step:&lt;/strong&gt; “apply the changes step by step and wait for me to say "next" before proceeding to the next step”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep docs in sync:&lt;/strong&gt; Eliminate outdated or missing documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these prompts transforms the AI assistant into a structured collaborator that follows a reproducible workflow.&lt;/p&gt;

&lt;p&gt;can be transformative—automating repetitive tasks, accelerating development, and offering creative suggestions. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Setting Up Prompt Alias
&lt;/h2&gt;

&lt;p&gt;You have noticed though typing long instructions each time can become tedious. To solve the problem, we introduce prompt aliases—short, “magic words” that trigger the advanced behaviors described above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AA:&lt;/strong&gt; Request a concise plan before writing code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CC:&lt;/strong&gt; Compare implementation options.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SS:&lt;/strong&gt; Apply changes incrementally, confirming at each step.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GG:&lt;/strong&gt; Auto-generate or update documentation, including mermaid diagrams if needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All we need to do is create a system prompt for your AI coding assistant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- I will use the following words to indicate how you should proceed with the code changes:
  - "AA": provide your plan in a concise bullet list and wait for my confirmation before proceeding.
  - "CC": provide implementation options and comparisons and wait for me to confirm before proceeding.
  - "SS": apply the changes step by step and wait for me to say "next" before proceeding to the next step.
  - "GG": summarize the features you implemented into a markdown file into the docs folder. 
      - If the file does not exist, create a new markdown file with existing features and the new changes.
      - If the file already exists, update the file by consolidating existing features with new changes.
      - Use mermaid diagrams if needed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each AI code assistant has its own way of customizing system prompts. In the case of Github Copilot, we can create and save the above in the file ‘./gihub/copilot-instructions.md, see &lt;a href="https://code.visualstudio.com/docs/copilot/copilot-customization" rel="noopener noreferrer"&gt;Customize chat responses in VS Code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. A Sample Interaction
&lt;/h2&gt;

&lt;p&gt;Once customized the system prompt of AI code assistant, you can use the prompt alias like below:&lt;/p&gt;

&lt;p&gt;Imagine you want to add a “purchase history” endpoint to your e-commerce API. Here’s how to orchestrate the AI assistant:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Plan Phase (AA):&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;You type:&lt;/strong&gt; implement "purchase history" retrieval endpoint AA  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then AI returns a plan:

&lt;ol&gt;
&lt;li&gt;Create or modify the &lt;code&gt;purchase_history&lt;/code&gt; database schema.
&lt;/li&gt;
&lt;li&gt;Add a service layer function to fetch purchase records.
&lt;/li&gt;
&lt;li&gt;Implement an Express route &lt;code&gt;/purchase-history&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Write unit tests for the new route and service.
&lt;/li&gt;
&lt;li&gt;Update documentation in &lt;code&gt;docs/FEATURES.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;You can review and confirm.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Compare Options (CC):&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;You type:&lt;/strong&gt; design purchase history database. CC  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The AI lists:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Relational join table&lt;/strong&gt; (Pros: ACID compliance; Cons: join complexity)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB collection&lt;/strong&gt; (Pros: flexible schema; Cons: eventual consistency)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis caching layer&lt;/strong&gt; (Pros: fast lookup; Cons: non‑persistent)
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;You reply:
Let’s proceed with option 1 (relational join table). &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Step‑by‑Step Implementation (SS):&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;You type&lt;/strong&gt;: Start coding the purchase history feature.  SS  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; The AI generates a database migration for a new &lt;code&gt;purchase_history&lt;/code&gt; table (fields: &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;product_id&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt;, &lt;code&gt;timestamp&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;You review the SQL, run migrations locally, then say “next.”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2:&lt;/strong&gt; The AI writes the service function &lt;code&gt;getPurchaseHistory(userId)&lt;/code&gt; that queries the join table.
&lt;/li&gt;
&lt;li&gt;You run a unit test, say “next.”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3:&lt;/strong&gt; The AI implements the Express route &lt;code&gt;/api/purchase-history/:userId&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;You verify functionality with Postman, then say “next.”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 4:&lt;/strong&gt; The AI generates unit tests for the route.
&lt;/li&gt;
&lt;li&gt;You run tests, confirm all pass, then say “next.”&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Documentation (GG):&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;You type:&lt;/strong&gt; GG  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The AI checks for &lt;code&gt;docs/FEATURES.md&lt;/code&gt;. If missing, it creates the file with a header “# Features,” adds a “## Purchase History” section, includes a description, endpoint details, sample request/response, and a mermaid sequence diagram.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Of course, these aliases can be used independently. &lt;/p&gt;

&lt;p&gt;And you can change them to whatever magic word you like, as long as they are easy to type and easy to memorize!  &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Conclusion
&lt;/h2&gt;

&lt;p&gt;Adopting advanced prompts elevates your AI-driven coding workflow from sporadic code suggestions to a structured, collaborative process. You gain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity and Focus:&lt;/strong&gt; Eliminate scope creep with upfront planning.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informed Decisions:&lt;/strong&gt; Evaluate trade-offs before coding.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality Control:&lt;/strong&gt; Vet every change to catch bugs early.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Up‑to‑Date Documentation:&lt;/strong&gt; Automate or update docs to reduce technical debt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using prompt aliases saves your time of typing the prompts and makes you more productive.&lt;/p&gt;

&lt;p&gt;Embracing these powerful prompt aliases now to focus on evaluating code quality also achieves unparalleled efficiency. Start today and experience the transformation.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Use AppRun with React</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Sat, 29 May 2021 19:39:50 +0000</pubDate>
      <link>https://dev.to/yysun/use-apprun-with-react-3152</link>
      <guid>https://dev.to/yysun/use-apprun-with-react-3152</guid>
      <description>&lt;p&gt;It only takes one line of code to use the &lt;a href="https://apprun.js.org/docs/architecture/" rel="noopener noreferrer"&gt;elm-inspired AppRun architecture&lt;/a&gt; in React apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; is a popular JavaScript library for building user interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apprun.js.org/" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; is an &lt;a href="https://apprun.js.org/docs/architecture/" rel="noopener noreferrer"&gt;elm-inspired event-driven&lt;/a&gt; library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using AppRun and React in conjunction is one of the best ways to build a web app. In this post, I will explain why and how-to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are new to AppRun, please visit the &lt;a href="https://apprun.js.org/docs" rel="noopener noreferrer"&gt;AppRun Docs&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  An Example
&lt;/h2&gt;

&lt;p&gt;Let's use the code from the &lt;a href="https://reactjs.org/docs/hooks-overview.html" rel="noopener noreferrer"&gt;React Hooks Doc&lt;/a&gt; as an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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&lt;/span&gt;&lt;span class="dl"&gt;'&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;Example&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 a new state variable, which we'll call "count"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&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="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same app using the AppRun looks like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&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;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the AppRun way is easier to understand. They are explained below.&lt;/p&gt;

&lt;h2&gt;
  
  
  AppRun Logic
&lt;/h2&gt;

&lt;p&gt;Inspired by Elm, AppRun Application logic is broken down into three separated parts in the AppRun architecture.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State (a.k.a. Model) — the state of your application&lt;/li&gt;
&lt;li&gt;View — a function to display the state&lt;/li&gt;
&lt;li&gt;Update — a collection of event handlers to update the state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All applications and components have the same architecture. So when you want to understand any applications, you can always start with looking for where the &lt;em&gt;state&lt;/em&gt; is, where the &lt;em&gt;view&lt;/em&gt; is, and where the &lt;em&gt;update&lt;/em&gt; is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use AppRun in React App
&lt;/h2&gt;

&lt;p&gt;If you like the AppRun architecture, it is very easy to use AppRun in React apps. All you need to do is converting the AppRun component to a React component by calling the &lt;em&gt;toReact&lt;/em&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;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;Component&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;apprun/esm/component&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="nx"&gt;toReact&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;apprun/react&lt;/span&gt;&lt;span class="dl"&gt;'&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;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&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;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&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;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="nx"&gt;update&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toReact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&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;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The React VDOM uses JSX. AppRun VDOM also uses JSX. They are similar. However, React VDOM does not have directives. So you cannot use the AppRun &lt;em&gt;$onclick&lt;/em&gt; directive. Instead, you need to use the React &lt;em&gt;onClick&lt;/em&gt; attribute.&lt;/p&gt;

&lt;p&gt;Now, with just one line conversion to React component, we successfully used the AppRun component in a React app.&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%2Fyntfce1pjhew7b6asl7m.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%2Fyntfce1pjhew7b6asl7m.png" alt="apprun-react" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can visit &lt;a href="https://github.com/yysun-apprun" rel="noopener noreferrer"&gt;https://github.com/yysun-apprun&lt;/a&gt; to see an example React project created by the &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App Cli&lt;/a&gt; that uses AppRun components.&lt;/p&gt;

&lt;p&gt;Or you can visit the live Demo site: &lt;a href="https://replit.com/@yysun/apprun-react" rel="noopener noreferrer"&gt;https://replit.com/@yysun/apprun-react&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%2Fgttyfz8mokebdyx2qkqn.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%2Fgttyfz8mokebdyx2qkqn.png" alt="apprun-react-replit" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AppRun Benefits
&lt;/h2&gt;

&lt;p&gt;Having the elm-inspired architecture in React apps, we have many benefits. I summarize them briefly here.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;state&lt;/em&gt;, &lt;em&gt;view&lt;/em&gt;, and &lt;em&gt;update&lt;/em&gt; are function have only dependencies to their input parameters. Without external dependency makes the three functions almost &lt;em&gt;pure&lt;/em&gt;, which means it's easy to reason, easy to test, and easy to maintain.&lt;/p&gt;

&lt;p&gt;For example,  you can see that by making it event-driven, the &lt;em&gt;update&lt;/em&gt;, a collection of the event handlers, can live outside the React component w/o the dependency to the &lt;em&gt;setState&lt;/em&gt; function. Thus, you can use modules to organize them and test them easily.&lt;/p&gt;

&lt;p&gt;We provide the &lt;em&gt;state&lt;/em&gt;, &lt;em&gt;view&lt;/em&gt;, and &lt;em&gt;update&lt;/em&gt; to AppRun and wait for AppRun to call them following the Hollywood Principle (Don't call us. We call you). AppRun uses a state management system and event pub-sub system to combine the &lt;em&gt;state&lt;/em&gt;, &lt;em&gt;view&lt;/em&gt;, and &lt;em&gt;update&lt;/em&gt; together.&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%2Ffw769u78ojwobkpazxtb.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%2Ffw769u78ojwobkpazxtb.png" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more information, please visit the &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun Site&lt;/a&gt;, &lt;a href="https://apprun.js.org/docs" rel="noopener noreferrer"&gt;AppRun Docs Site&lt;/a&gt;,&lt;/p&gt;

&lt;p&gt;Or read the &lt;a href="https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/" rel="noopener noreferrer"&gt;AppRun Book from Apress&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/99fad1f024c274a3d752a1583cf125037583811c/68747470733a2f2f696d616765732e737072696e6765722e636f6d2f7367772f626f6f6b732f6d656469756d2f393738313438343234303638372e6a7067" alt="Order from Amazon" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoy it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post updated from using &lt;strong&gt;three&lt;/strong&gt; lines of code to just &lt;strong&gt;one line&lt;/strong&gt; of code on May 30, 2021.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Make Code Run in Your Docs</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Sun, 23 May 2021 16:06:25 +0000</pubDate>
      <link>https://dev.to/yysun/make-code-run-in-your-docs-4800</link>
      <guid>https://dev.to/yysun/make-code-run-in-your-docs-4800</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The recently updated &lt;a href="https://apprun.js.org/docs" rel="noopener noreferrer"&gt;AppRun Docs Site&lt;/a&gt; has made the code snippets in the documents runnable and editable, making the technical documentation interactive and much more fun to use.&lt;/p&gt;

&lt;p&gt;The site is built with &lt;a href="https://squidfunk.github.io/mkdocs-material/" rel="noopener noreferrer"&gt;Material for MkDocs&lt;/a&gt;, a beautiful and powerful tool for building technical documentation site. We extended it by adding a web component built with &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; to deliver the interactive experiences.&lt;/p&gt;

&lt;p&gt;In this post, I Will explain how it's made. Let's start with reviewing the user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Experience
&lt;/h2&gt;

&lt;p&gt;Technical documents usually have code snippets. Often the code has syntax highlighted for easy reading. However, users usually can only see screenshots but not live results of the code. Screenshots have limitations. For example, when describing how to make animation, a static screenshot is not helpful. We need a way to display the live code execution results.&lt;/p&gt;

&lt;h3&gt;
  
  
  See the Results
&lt;/h3&gt;

&lt;p&gt;You can visit the &lt;a href="https://apprun.js.org/docs/directive/#custom-directive" rel="noopener noreferrer"&gt;AppRun Docs Page&lt;/a&gt; to see a live animation.&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%2F1da6f59c33jatqyo0imc.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%2F1da6f59c33jatqyo0imc.png" alt="run code" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Try the Code
&lt;/h3&gt;

&lt;p&gt;Furthermore, users might have been inspired by the code examples and want to try different ideas. Traditionally, they could copy and paste the code to run it in their code editors. It would be nice for users to edit the code right on the doc site and see the results.&lt;/p&gt;

&lt;p&gt;You can click the "Try the Code" button of the &lt;a href="https://apprun.js.org/docs/directive/#custom-directive" rel="noopener noreferrer"&gt;AppRun Docs Page&lt;/a&gt;. It opens the AppRun Playground with an editor and preview pane to play the code.&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%2Fy0dc7t2lw0txqab2vus7.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%2Fy0dc7t2lw0txqab2vus7.png" alt="edit code" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user experiences have much improved with the capabilities of seeing the code results and trying the code in technical documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Author Experience
&lt;/h2&gt;

&lt;p&gt;Not only is it much more attractive to the readers, but also the authors will feel it much more enjoyable when writing the documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Present the Live Code
&lt;/h3&gt;

&lt;p&gt;Traditionally, authors copy and paste the code snippets from their testing projects into the markdown documents as code blocks. The limitation is that they can only present the code but not the running code. Sometimes, it would be hard to describe the code behaviour. For example, describing a calculator could need a long text, but it could be easier to present the calculator for users to click.&lt;/p&gt;

&lt;p&gt;You can visit the &lt;a href="https://apprun.js.org/docs/architecture-ideas/state-machine/#model-a-calculator" rel="noopener noreferrer"&gt;AppRun Docs Page&lt;/a&gt; to see a running calculator.&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%2Fyx244b2z9vkjooyl1f7i.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%2Fyx244b2z9vkjooyl1f7i.png" alt="hide source" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All we need to do is to add a web component, called &lt;em&gt;apprun-play&lt;/em&gt; under the code blocks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ``js
  // code snippets
  ``
  &amp;lt;apprun-play&amp;gt;&amp;lt;/apprun-play&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Control the Presentation
&lt;/h3&gt;

&lt;p&gt;You probably have noticed that the page shows only the results but not the source code. It is because we can control whether to show the source code. We can also decide whether to see the "Try the Code" button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ``js
  // code snippets
  ``
  &amp;lt;apprun-play hide_src="true" hide_button="true"&amp;gt;&amp;lt;/apprun-play&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can visit the &lt;a href="https://apprun.js.org/docs/architecture/#ceremony-vs-essence" rel="noopener noreferrer"&gt;AppRun Docs Page&lt;/a&gt; to see an example of only displaying the running results.&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%2Fldvvrmu1juty4jt7ezvo.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%2Fldvvrmu1juty4jt7ezvo.png" alt="hide try-the-code button" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can present the code snippets, but we can also embed whole applications because the &lt;em&gt;apprun-play&lt;/em&gt; web component supports HTML.&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%2Fnfwlatbkx39bpijwihhl.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%2Fnfwlatbkx39bpijwihhl.png" alt="Embed Apps" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can use the &lt;a href="https://squidfunk.github.io/mkdocs-material/reference/code-blocks/#embedding-external-files" rel="noopener noreferrer"&gt;embedding external files&lt;/a&gt; feature of &lt;a href="https://squidfunk.github.io/mkdocs-material/" rel="noopener noreferrer"&gt;Material for MkDocs&lt;/a&gt;. This way, the markdown document does not include the source code and can remain simple and clean.&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;textarea&amp;gt;
  --8&amp;lt;-- "real-world.html"
  &amp;lt;/textarea&amp;gt;
  &amp;lt;apprun-play style="height:350px" hide_src="true" hide_button="true"&amp;gt;&amp;lt;/apprun-play&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automatic Test the Code
&lt;/h3&gt;

&lt;p&gt;When it displays the code result automatically means that it is automatic testing of the code, which tells the author if the code works as expected.&lt;/p&gt;

&lt;p&gt;Also, while writing, the authors can come up with new ideas. With &lt;em&gt;apprun-play&lt;/em&gt; web component, they can edit the code and see the live results. Once it's done, they can copy and paste the code back into the document.&lt;/p&gt;

&lt;p&gt;Overall, the &lt;em&gt;apprun-play&lt;/em&gt; web component is a helpful tool for the document author.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It's Made
&lt;/h2&gt;

&lt;p&gt;Web components/custom elements are safe in the markdown documents. We can build web components out of the &lt;a href="https://apprun.js.org/docs/component/" rel="noopener noreferrer"&gt;AppRun Components&lt;/a&gt; quickly.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;apprun-play&lt;/em&gt; web component is an AppRun component that gets the source code from its previous sibling element, a &lt;em&gt;textarea&lt;/em&gt;, or a &lt;em&gt;div&lt;/em&gt; with highlighted code. Then, the &lt;em&gt;apprun-play&lt;/em&gt; web component creates an iframe for the code.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://github.com/yysun/apprun/blob/master/src/apprun-play.tsx" rel="noopener noreferrer"&gt;source code here&lt;/a&gt; and the &lt;a href="https://raw.githubusercontent.com/yysun/apprun/master/dist/apprun-play.js" rel="noopener noreferrer"&gt;compiled code here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, you can add it to the configuration file of Material for MkDocs, &lt;em&gt;mkdocs.yml&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;extra_css&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;assets/vendor/codemirror/codemirror.css&lt;/span&gt;

&lt;span class="na"&gt;extra_javascript&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;assets/vendor/codemirror/codemirror.js&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;assets/vendor/codemirror/mode/javascript/javascript.js&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;assets/vendor/codemirror/mode/xml/xml.js&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;assets/vendor/codemirror/mode/jsx/jsx.js&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;assets/apprun-play.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The &lt;em&gt;apprun-play&lt;/em&gt; web component is ready for use in all the markdown documents.&lt;/p&gt;

&lt;p&gt;Finally, the AppRun Docs Site Github project is: &lt;a href="https://github.com/apprunjs/apprun-docs/" rel="noopener noreferrer"&gt;https://github.com/apprunjs/apprun-docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please enjoy and send pull requests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: the cover image is a water colour painting I painted from the one by my favourite English painter, John Yardley.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>jamstack</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A Dev Server Supports ESM</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Sun, 13 Dec 2020 21:27:34 +0000</pubDate>
      <link>https://dev.to/yysun/a-dev-server-supports-esm-3cea</link>
      <guid>https://dev.to/yysun/a-dev-server-supports-esm-3cea</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Although we use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules" rel="noopener noreferrer"&gt;JavaScript modules&lt;/a&gt; (ESM) extensively while coding nowadays, we still cannot deploy the module-based code yet because the browsers don't know how to handle global modules.  E.g., When developing applications using &lt;a href="https://github.com/yysun/apprun" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt;, we need a globe module of &lt;em&gt;apprun&lt;/em&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&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;apprun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browsers don't know how to import &lt;em&gt;apprun&lt;/em&gt;. Therefore, We still need to use JavaScript bundlers such as webpack, rollup, or parcel to bundle the modules. &lt;/p&gt;

&lt;p&gt;But at least now, we can use the modules to speed up the development process. Recently, the Snowpack team introduced the concept of &lt;a href="https://www.snowpack.dev/concepts/how-snowpack-works" rel="noopener noreferrer"&gt;Unbundled Development&lt;/a&gt;, which is to leverage modules for speeding up the development process. &lt;/p&gt;

&lt;p&gt;In the past, I was thinking to find or build a tool to convert the global modules to the modules links on &lt;em&gt;unpkg&lt;/em&gt; after compilation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;a href="https://unpkg.com" rel="noopener noreferrer"&gt;npm package CDN&lt;/a&gt;, unpkg.com &lt;a href="https://github.com/mjackson/unpkg/issues/34" rel="noopener noreferrer"&gt;supports delivering modules&lt;/a&gt; for along time. We can load &lt;em&gt;apprun&lt;/em&gt; as a module from &lt;em&gt;unpkg&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&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;https://unpkg.com/apprun?module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, it seems that a development server is a different and better idea. So, I forked the live-server and made a development server for AppRun.&lt;/p&gt;

&lt;p&gt;This post is to introduce the AppRun development server, called &lt;a href="https://github.com/yysun/apprun-dev-server" rel="noopener noreferrer"&gt;&lt;em&gt;apprun-dev-server&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  apprun-dev-server
&lt;/h1&gt;

&lt;p&gt;This is a static web server for developing JavaScript/TypeScript using ES modules following the concept of &lt;a href="https://www.snowpack.dev/concepts/how-snowpack-works" rel="noopener noreferrer"&gt;Unbundled Development&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It serves the ES Modules from unpkg.com.&lt;/li&gt;
&lt;li&gt;Based on &lt;a href="https://www.npmjs.com/package/live-server" rel="noopener noreferrer"&gt;live-server&lt;/a&gt;, so it reloads the page automatically&lt;/li&gt;
&lt;li&gt;Also, it detects &lt;a href="https://github.com/yysun/apprun" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; and can replace the module/Component while keeping the application &lt;em&gt;state&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&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%2F92ivb1hxw5ycyhed5xnz.gif" 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%2F92ivb1hxw5ycyhed5xnz.gif" width="760" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The best part of the apprun-dev-server is that it does NOT require any code in our components to handle the hot module replacement. It retains the component state; replaces the module; and then puts the state back. All done automatically.&lt;/p&gt;

&lt;p&gt;If you want to refresh the state, you can reload the page in the browser by pressing F5 (on Windows) or Command+R (on Mac).&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Use
&lt;/h1&gt;

&lt;p&gt;You export Component as the default module export.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apprun&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AboutComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&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;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&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;Then, you use the Component in the main file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;About&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;./About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;About&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you use a module-type script tag in HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;AppRun SPA&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/dist/main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turn on the compiler, TypeScript, or Babel in watch mode. And then, start the apprun-dev-server using npx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx apprun-dev-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apprun-dev-server monitors the file changes. If the changed JavaScript files (*.js) file have global modules. Apprun-dev-server replaces the global module's references to &lt;em&gt;unpkg&lt;/em&gt;. In the server console, if you see the file names that have some dots '......' in front, they are the files modified.&lt;/p&gt;

&lt;p&gt;Apprun-dev-server injects JavaScript code snippets in the index.html just like live-server. Also, Apprun-dev-server adds logic to detect AppRun and replace AppRun components.&lt;/p&gt;

&lt;p&gt;You can download an example app to give it a try.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx degit yysun/apprun-esm-server my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configuration
&lt;/h1&gt;

&lt;p&gt;Create a apprun-dev-server.config.js in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8181&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set the server port. Defaults to 8080.&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP.&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set root directory that's being served. Defaults to cwd.&lt;/span&gt;
  &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// When false, it won't load your browser by default.&lt;/span&gt;
  &lt;span class="na"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// comma-separated string for paths to ignore&lt;/span&gt;
  &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// When set, serve this file (server root relative) for every 404 (useful for single-page applications)&lt;/span&gt;
  &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Waits for all changes, before reloading. Defaults to 0 sec.&lt;/span&gt;
  &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="c1"&gt;// Mount a directory to a route.&lt;/span&gt;
  &lt;span class="na"&gt;logLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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;h1&gt;
  
  
  Future Plan
&lt;/h1&gt;

&lt;p&gt;Don't want apprun-dev-server to invoke compilers/loaders. It is perfectly fine to use the TypeScript compiler in watch mode. Apprun-dev-server is a webserver to serve modules. Nothing else.&lt;/p&gt;

&lt;p&gt;Webpack is still needed and recommended for building production code for now.&lt;/p&gt;

&lt;p&gt;The node-modules folder size is a problem. Apprun-dev-server can run from npx. It does not need to live in the node-modules. However, it does not get away from npm install and huge node-modules folder, because we still need referenced packages, ESLint, Jest... Good luck with future npm improvement.&lt;/p&gt;

&lt;p&gt;Based on the opinions above, I will keep the apprun-dev-server simple. KISS!&lt;/p&gt;

&lt;p&gt;Give it a try and send pull requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yysun/apprun-dev-server" rel="noopener noreferrer"&gt;https://github.com/yysun/apprun-dev-server&lt;/a&gt;&lt;/p&gt;

</description>
      <category>esm</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>module</category>
    </item>
    <item>
      <title>ORM for .NET 5 Records</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Sat, 21 Nov 2020 22:42:38 +0000</pubDate>
      <link>https://dev.to/yysun/orm-for-net-5-records-4h38</link>
      <guid>https://dev.to/yysun/orm-for-net-5-records-4h38</guid>
      <description>&lt;p&gt;Object-Relational Mapping (ORM, O/R mapping tool) is a tool for converting data between object-oriented languages and relational databases. When programming using C#, an ORM tool helps to reduce the tedious field to field mapping work. The most famous one is the Entity Framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  DragonCore ORM
&lt;/h2&gt;

&lt;p&gt;Entity Framework and other ORM tools usually have a load of features, which makes them complicated and hard to control. I feel I need a very simple ORM tool that just can load data from the SQL server into C# objects and execute stored procedures. Therefore, I have created a simple ORM tool, call &lt;a href="https://www.nuget.org/packages/dragon" rel="noopener noreferrer"&gt;Dragon&lt;/a&gt; since .NET framework 1.1 and used it in many production projects. It has been updated to leverage new C# features along with the major C# version releases, such as generics, auto-properties, anonymous types, tuple destruction, and etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nuget.org/packages/dragoncore" rel="noopener noreferrer"&gt;DragonCore&lt;/a&gt; is a port of Dragon to .NET 5 to support the latest and greatest C# 9 features, in particular the record types. &lt;/p&gt;

&lt;p&gt;To use the DragonCore, install the NuGet package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add package DragonCore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  From Class To Record
&lt;/h2&gt;

&lt;p&gt;The recent .NET 5 release announced C# 9 &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9" rel="noopener noreferrer"&gt;record type&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;C# 9.0 introduces record types, which are a reference type that provides synthesized methods to provide value semantics for equality. Records are immutable by default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before the .NET 5 release, we use regular C# class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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, we can use C# 9 &lt;em&gt;record type&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&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;Although changing the keywords from &lt;em&gt;class&lt;/em&gt; to &lt;em&gt;record&lt;/em&gt; and from &lt;em&gt;set&lt;/em&gt; to &lt;em&gt;init&lt;/em&gt; does not look like big changes, we actually have implemented the concept of &lt;em&gt;immutable reference types&lt;/em&gt;. No need to understand the in-depth theory, you only need to know the &lt;em&gt;immutable reference types&lt;/em&gt; is better than regular &lt;em&gt;class&lt;/em&gt; for loading data from the database and passing data to other layers of applications. Of course, you can review all the benefits from the &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#record-types" rel="noopener noreferrer"&gt;record type document&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There is a short-hand syntax to create a &lt;em&gt;record type&lt;/em&gt;, which is also known as a &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/exploration/records" rel="noopener noreferrer"&gt;&lt;em&gt;positional record&lt;/em&gt;&lt;/a&gt;. We can re-write the above &lt;em&gt;User&lt;/em&gt; record as &lt;em&gt;positional record&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The C# compiler creates the constructor, properties, and destructors out of the &lt;em&gt;positional record&lt;/em&gt;. DragonCore supports the &lt;em&gt;positional record&lt;/em&gt; syntax.&lt;/p&gt;

&lt;h1&gt;
  
  
  Strongly Typed Mapping
&lt;/h1&gt;

&lt;p&gt;DragonCore can execute SQL queries and create C# strongly typed objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*connection string*/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;@"select UserId, Email from UserProfile"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class/record property names don't need to match the table/view column names. The class/record property names match the field names in the SQL select statements. Therefore, we can use SQL select to define column alias to match the property names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;@"select UserId as Id, Email from UserProfile"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, we can have more class properties than the columns returned from the query. Extra columns are ignored, but the query will still return all the columns from the SQL server. Be aware to always be specific on the columns in production code and not to use "SELECT *".   &lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Query&lt;/em&gt; method also supports calling stored procedures for creating objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TestUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TestMemberShip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TestUserRole&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"GetAllUserInfo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also the &lt;em&gt;QueryValue&lt;/em&gt; method that creates a SQL command and runs ExecuteScalar to return a single value from the SQL server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Query Parameters
&lt;/h1&gt;

&lt;p&gt;Query parameters are passed in as anonymous types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
    select UserId, Email from UserProfile 
    where UserId=@UserId"&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="n"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to name parameters and pass data through the parameters easily.&lt;/p&gt;

&lt;h1&gt;
  
  
  Multiple Recordsets
&lt;/h1&gt;

&lt;p&gt;The &lt;em&gt;Query&lt;/em&gt; method supports up to 3 recordsets. The result objects are returned in a Tuple. We can use &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/deconstruct" rel="noopener noreferrer"&gt;&lt;em&gt;tuple destruction&lt;/em&gt;&lt;/a&gt; to unpack variables from the tuple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TestUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TestMemberShip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TestUserRole&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
  select * from dbo.UserProfile
  Select * from dbo.webpages_Membership
  select * from dbo.webpages_Roles"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Execute Stored Procedure
&lt;/h1&gt;

&lt;p&gt;The &lt;em&gt;Execute&lt;/em&gt; method is for executing stored procedures. It creates a SQL command and runs ExecuteNonQuery.&lt;/p&gt;

&lt;h1&gt;
  
  
  Manage Transactions
&lt;/h1&gt;

&lt;p&gt;Use the &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transactionscope?view=net-5.0" rel="noopener noreferrer"&gt;TransactionScope&lt;/a&gt; guaranteeing that database queries can commit or rollback as a single unit of work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*connection string*/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TransactionScope&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TransactionScope&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;

        &lt;span class="c1"&gt;// The Complete method commits the transaction. If an exception has been thrown, the transaction is rolled back.&lt;/span&gt;
        &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TransactionAbortedException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TransactionAbortedException Message: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;I only want a simple tool to map SQL recordsets to C# objects. No &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design#:~:text=of%20Work%20patterns.-,The%20Repository%20pattern,from%20the%20domain%20model%20layer." rel="noopener noreferrer"&gt;repository pattern&lt;/a&gt; or &lt;a href="https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application" rel="noopener noreferrer"&gt;unit of work pattern&lt;/a&gt;. I can handle transactions with stored procedures or &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transactionscope?view=net-5.0" rel="noopener noreferrer"&gt;TransactionScope&lt;/a&gt;. If you like me, give DragonCore ORM a try.&lt;/p&gt;

&lt;p&gt;DragonCore ORM has only one class, called Database, which has four methods: &lt;em&gt;Open&lt;/em&gt;, &lt;em&gt;Execute&lt;/em&gt;, &lt;em&gt;QueryValue&lt;/em&gt;, and &lt;em&gt;Query&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt;: opens database connection using a connection string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt;: creates a command and runs ExecuteNonQuery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QueryValue&lt;/strong&gt;: creates a command and runs ExecuteScalar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query&lt;/strong&gt;: creates a command with SQL statement(s) or stored procedure name and creates objects. The Query method supports up to 3 multiple recordsets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Source Code
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/yysun/dragon-core" rel="noopener noreferrer"&gt;https://github.com/yysun/dragon-core&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pull Requests are welcome. Have fun coding.&lt;/p&gt;

&lt;p&gt;(C) Copyright 2020, Yiyi Sun&lt;/p&gt;

</description>
      <category>net5</category>
      <category>orm</category>
      <category>c</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Rust WebAssembly and AppRun</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Mon, 30 Mar 2020 15:32:10 +0000</pubDate>
      <link>https://dev.to/yysun/rust-webassembly-and-apprun-3bei</link>
      <guid>https://dev.to/yysun/rust-webassembly-and-apprun-3bei</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webassembly.org/" rel="noopener noreferrer"&gt;WebAssembly&lt;/a&gt; has many different definitions on the Internet. I like the one from &lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; the most, which says WebAssembly is a new binary assembly-like language that can run in the modern web browsers at near-native speed. There are &lt;a href="https://github.com/appcypher/awesome-wasm-langs" rel="noopener noreferrer"&gt;many tools&lt;/a&gt; to compile code written in C/C++, Rust, Go, C#, etc. to be WebAssembly. It tells us that we can create high-performance code, but not using JavaScript/TypeScript&lt;/p&gt;

&lt;p&gt;I decided to play with Rust. &lt;a href="https://www.rust-lang.org/what/wasm" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; is another hot buzzword. It is a relatively new programming language focused on performance and safety, especially safe concurrency. -- Wikipedia&lt;/p&gt;

&lt;p&gt;This post describes how to create a WebAssembly package using Rust and use it in the &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; applications from a JavaScript/TypeScript developer point of view. You will see the minimum steps of adding and using WebAssembly into your JavaScript/TypeScript project. &lt;/p&gt;

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

&lt;p&gt;First, you will need the Rust toolchain, including rustup, rustc, and cargo for compiling Rust code, and &lt;a href="https://rustwasm.github.io/wasm-pack/" rel="noopener noreferrer"&gt;wasm-pack&lt;/a&gt; for building, testing and publishing Rust-generated WebAssembly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Rust
&lt;/h3&gt;

&lt;p&gt;To install Rust on Mac/Linux, run the following command in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On Windows, I enabled the &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10" rel="noopener noreferrer"&gt;Windows Subsystem for Linux&lt;/a&gt; and used Rust in the Linux terminal.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install wasm-pack
&lt;/h3&gt;

&lt;p&gt;Once installed Rust, run the following command in the terminal.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo install wasm-pack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Believe it or not, that's all you need to create WebAssembly. Let's go back to the JavaScript/TypeScript world. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you start from scratch, follow the next section to create an AppRun project. &lt;/li&gt;
&lt;li&gt;If you already have an existing project, jump to the section of Create WebAssembly Project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Create AppRun Project
&lt;/h3&gt;

&lt;p&gt;Run the commands to create an AppRun project:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir your-app-name
cd your-app-name
npx apprun -i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Wait a few minutes for installing the npm packages, and then run the npm command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You will see a hello world application running.&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%2F0v0lkfuto7d4lxh1639i.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%2F0v0lkfuto7d4lxh1639i.png" alt="AppRun Hello World" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
AppRun Hello World



&lt;p&gt;Next, we will add WebAssembly to this project.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create WebAssembly Project
&lt;/h3&gt;

&lt;p&gt;Let's create a Rust project by running the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo new wasm --lib 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The command creates a folder called &lt;em&gt;wasm&lt;/em&gt; and two files under the folder &lt;em&gt;your-app-name/wasm&lt;/em&gt;: &lt;em&gt;Cargo.toml&lt;/em&gt; and &lt;em&gt;src/lib.rs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It is a regular Rust project, not a WebAssembly yet. You will need to add &lt;em&gt;wasm-bindgen&lt;/em&gt; as the dependency to make it target WebAssembly. Open &lt;em&gt;Cargo.toml&lt;/em&gt; and add the following sections.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2.60"
js-sys = "0.3.37"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://rustwasm.github.io/" rel="noopener noreferrer"&gt;wasm-bindgen&lt;/a&gt; is a Rust library that facilitates high-level interactions between wasm modules and JavaScript. &lt;a href="https://crates.io/crates/js-sys" rel="noopener noreferrer"&gt;js-sys&lt;/a&gt; is the waw bindings to JS global APIs for projects using wasm-bindgen. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, you can use wasm-pack to build a WebAssembly.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd wasm
wasm-pack build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Use WebPack
&lt;/h3&gt;

&lt;p&gt;Since the AppRun project is a WebPack project, we can use the &lt;a href="https://github.com/wasm-tool/wasm-pack-plugin" rel="noopener noreferrer"&gt;wasm-pack-plugin&lt;/a&gt; to unify the build process that creates the WebAssembly and JavaScript code at the same time. Go ahead to add the package:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @wasm-tool/wasm-pack-plugin -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And add the wasm-pack-plugin into the &lt;em&gt;webpack.config.js&lt;/em&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WasmPackPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@wasm-tool/wasm-pack-plugin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WasmPackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;crateDirectory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="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;Also, because of the wasm-pack-plugin generates the &lt;em&gt;dynamic import&lt;/em&gt; module, you need to modify &lt;em&gt;tsconfig.json&lt;/em&gt; file to set the module to be &lt;em&gt;esnext&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, the npm scripts: &lt;em&gt;npm start&lt;/em&gt; and &lt;em&gt;npm run build&lt;/em&gt; will build the TypeScript code as well the Rust code.&lt;/p&gt;

&lt;p&gt;Let's write some Rust code.&lt;/p&gt;
&lt;h2&gt;
  
  
  WebAssembly and AppRun
&lt;/h2&gt;

&lt;p&gt;We will demonstrate two interactions between the WebAssembly and the AppRun application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call the WebAssembly from the AppRun application&lt;/li&gt;
&lt;li&gt;Call the AppRun application from the WebAssembly&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Call WebAssembly
&lt;/h3&gt;

&lt;p&gt;First, we create a Rust function in the &lt;em&gt;wasm/src/lib.rs&lt;/em&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="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;wasm_bindgen&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&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="nd"&gt;#[wasm_bindgen]&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;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&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;b&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;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This function adds two numbers. We can make a counter application from it. Here is the counter application in AppRun.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&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;apprun&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;wasm&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../wasm/pkg&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="nx"&gt;wasm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world - AppRun !&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;count&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;count&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="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&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;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&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;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can see from the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wasm-pack has created a JavaScript module that we can import dynamically. &lt;/li&gt;
&lt;li&gt;We can call the WebAssembly function just like a regular JavaScript function from a module.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running the application, we have a counter that uses the WebAssembly function.&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%2Fdmy2qkqqtlyxed4qovlf.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%2Fdmy2qkqqtlyxed4qovlf.png" alt="Counter with WASM" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;
Counter with WASM



&lt;p&gt;Next, let's see how does the WebAssembly function call AppRun functions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Call the AppRun
&lt;/h3&gt;

&lt;p&gt;Open &lt;em&gt;wasm/src/lib.rs&lt;/em&gt; file and add the following functions.&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;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;#[wasm_bindgen(js_namespace&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;app)]&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&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(start)]&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;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hello world from rust"&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;ul&gt;
&lt;li&gt;The first function named &lt;em&gt;run&lt;/em&gt; binds to the AppRun &lt;em&gt;app.run&lt;/em&gt; function. &lt;/li&gt;
&lt;li&gt;The second function named &lt;em&gt;start&lt;/em&gt; runs automatically when the WebAssembly is loaded.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;start&lt;/em&gt; function calls the &lt;em&gt;run&lt;/em&gt; function to send a '&lt;a class="mentioned-user" href="https://dev.to/hello"&gt;@hello&lt;/a&gt;' event to AppRun.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back to AppRun code, we will handle the '&lt;a class="mentioned-user" href="https://dev.to/hello"&gt;@hello&lt;/a&gt;' event.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&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;apprun&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;wasm&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../wasm/pkg&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="nx"&gt;wasm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&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;state&lt;/span&gt; &lt;span class="o"&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;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({...});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hello&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;state&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;state&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, when the application starts, it displays the messages sent from the WebAssembly.&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%2Fatljaqot7q08qcu9rk9m.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%2Fatljaqot7q08qcu9rk9m.png" alt="Message from WASM" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;
Message from wasm



&lt;p&gt;We have successfully made the two-way interactions between the WebAssembly and the AppRun application. &lt;/p&gt;
&lt;h2&gt;
  
  
  Souce Code
&lt;/h2&gt;

&lt;p&gt;You can run the live demo: &lt;a href="https://yysun.github.io/apprun-rust" rel="noopener noreferrer"&gt;https://yysun.github.io/apprun-rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Or visit the source.&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/yysun" rel="noopener noreferrer"&gt;
        yysun
      &lt;/a&gt; / &lt;a href="https://github.com/yysun/apprun-rust" rel="noopener noreferrer"&gt;
        apprun-rust
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AppRun Rust Demo App
    &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;h2 class="heading-element"&gt;AppRun Rust Demo&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;This is an &lt;a href="https://github.com/yysun/apprun" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; app template for developing WebAssembly using Rust.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You need the &lt;a href="https://www.rust-lang.org/tools/install" rel="nofollow noopener noreferrer"&gt;Rust&lt;/a&gt; tool chain, and &lt;a href="https://rustwasm.github.io/wasm-pack/" rel="nofollow noopener noreferrer"&gt;wasm-pack&lt;/a&gt; installed first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;em&gt;npm start&lt;/em&gt; to start the dev server&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;npm run build&lt;/em&gt; to build for production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have fun.&lt;/p&gt;

&lt;p&gt;(C) Copyright 2020, Yiyi Sun&lt;/p&gt;

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


&lt;p&gt;You also can use this project as an AppRun application template. Run the command to create your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx degit yysun/apprun-rust my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This post should give you a quick start to use Rust/WebAssembly in the AppRun applications. The demo project shows the two technologies interact with each other very well. You can use the demo project as a template.&lt;/p&gt;

&lt;p&gt;We have now opened the door to a new world. There are much more potentials to explorer.&lt;/p&gt;

</description>
      <category>apprun</category>
      <category>rust</category>
      <category>webassembly</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Serverless App Using Firebase and AppRun</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Thu, 26 Mar 2020 18:29:54 +0000</pubDate>
      <link>https://dev.to/yysun/serverless-app-on-firebase-using-apprun-1k46</link>
      <guid>https://dev.to/yysun/serverless-app-on-firebase-using-apprun-1k46</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I have been writing about the application architecture without REST, which includes the &lt;a href="https://dev.to/yysun/create-a-phoenix-liveview-like-app-in-js-with-apprun-dc8"&gt;underlying architecture using WebSockets&lt;/a&gt; and the &lt;a href="https://dev.to/yysun/database-driven-applications-using-websockets-2b9o"&gt;database-driven architecture&lt;/a&gt;. In this post, I will continue the journey to make a serverless application architecture using Firebase and &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will see how easy it is to use AppRun's event system with the Firebase stack to develop applications that have the full business logic process capabilities, such as authentication, authorization, request logging, and real-time database, and without REST layer.&lt;/p&gt;

&lt;p&gt;Finally, we can make the application a serverless deployment to Firebase.&lt;/p&gt;

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

&lt;p&gt;The example application uses the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firebase Cloud Firestore as the backend database&lt;/li&gt;
&lt;li&gt;Firebase Cloud Functions for business logic process&lt;/li&gt;
&lt;li&gt;Firebase Hosting to host the frontend&lt;/li&gt;
&lt;li&gt;Firebase Authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="//firebase.google.com"&gt;Firebase&lt;/a&gt; is Google's mobile platform that helps you quickly develop high-quality apps and grow your business. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I will focus on the architecture instead of step by step instructions. If you are not familiar with the Firebase suite of products, please visit &lt;a href="https://firebase.google.com/docs" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; and search for the tutorials.&lt;/p&gt;

&lt;p&gt;The architecture can be summarized in the diagram below. &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%2Fn2pbntxlu9p2d7ftbi41.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%2Fn2pbntxlu9p2d7ftbi41.png" alt="Architecture" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;
Figure 1. Architecture Diagram



&lt;p&gt;Let's get into the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event Pub-Sub Using FireStore
&lt;/h3&gt;

&lt;p&gt;The center of the architecture is the Firebase Cloud Firestore. Firestore is a real-time database that keeps your data in-sync across client apps. When one client saves the data, FireStore pushes the data to all other clients. &lt;/p&gt;

&lt;p&gt;In the AppRun applications, we use &lt;em&gt;app.on&lt;/em&gt; to publish events. If we save the events to FireStore, the events can be handled by other applications. It is the step (1) shown in Figure 1 above.&lt;/p&gt;

&lt;p&gt;Firestore also triggers Cloud Functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business Logic Process Using Cloud Functions
&lt;/h3&gt;

&lt;p&gt;Cloud Functions is Google Cloud's serverless compute platform. It runs on the server, not in the client apps. Therefore it is the best technology for business logic processing, authentication, and authorization. Functions are serverless. Functions run on Google's server, so we don't need to provision, manage, or upgrade the server.&lt;/p&gt;

&lt;p&gt;The Functions are event-driven (the magic word, I love). Firestore can trigger Functions upon data updates. When we save the events into FireStore, FireStore triggers the Function to handle the events automatically. It is the step (2) in Figure 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-Time Data Sync Using FireStore.
&lt;/h3&gt;

&lt;p&gt;During the Functions event handling, it writes the updated data back to FireStore (step (3) in Figure 1). FireStore pushes the update to the frontend applications (step (4) in Figure 1). The frontend application listens to FireStore changes and publishes AppRun events for the frontend logic process to run. &lt;/p&gt;

&lt;p&gt;Now, the event handling cycle is completed. Let's see it in action with an example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;The example is a ToDo application.&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%2Fsiavm31erdel8ea0asgj.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%2Fsiavm31erdel8ea0asgj.png" alt="Todo App" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;
Figure 2. ToDo Application



&lt;h3&gt;
  
  
  Save Events to FireStore
&lt;/h3&gt;

&lt;p&gt;As usual, in the AppRun applications, we convert the DOM events into AppRun events. E.g., When users click the &lt;em&gt;add&lt;/em&gt; button, we publish the //: event.&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;// in JSX&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;add&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;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@create-todo&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The //: event handler saves the event into FireStore.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`events`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;uid&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There is a top-level collection, called &lt;em&gt;events&lt;/em&gt; in FireStore. We save the user id (obtained using Firebase anonymous authentication), event name (@create-todo), and event parameters (the new to-do item).&lt;/p&gt;

&lt;p&gt;FireStore triggers our Function, which is monitoring the &lt;em&gt;events&lt;/em&gt; collection.&lt;/p&gt;
&lt;h3&gt;
  
  
  Handle Events in Functions
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;events/{Id}&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="nf"&gt;onWrite&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;change&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;uid&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dat&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;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&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;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@create-todo&lt;/span&gt;&lt;span class="dl"&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@update-todo&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;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@delete-todo&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;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@delete-all-todo&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;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="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;The Function destructs the user id, event name, and event parameters and handles it accordingly, e.g., it adds a new Todo item data into FireStore upon the '@create-todo' event. And so on so forth.&lt;/p&gt;

&lt;p&gt;FireStore then pushes the data change to the frontend.&lt;/p&gt;
&lt;h3&gt;
  
  
  Real-Time Data in Frontend
&lt;/h3&gt;

&lt;p&gt;In the frontend, we subscribe to the &lt;em&gt;onSnapshot&lt;/em&gt; of FireStore and publish the AppRun event, '@show-all'.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/todos`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snapshot&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@show-all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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, we are back to our AppRun application world, in which you can see the three familiar parts: &lt;em&gt;state&lt;/em&gt;, &lt;em&gt;view&lt;/em&gt;, and &lt;em&gt;update&lt;/em&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apprun&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;filter&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="na"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@create-todo&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@update-todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@delete-todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@delete-all-todo&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@show-all&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&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;The Firebase ToDo application shares the same architecture as in the &lt;a href="https://dev.to/yysun/database-driven-applications-using-websockets-2b9o"&gt;Database-Driven Application Post&lt;/a&gt;. They are only different in events. The Firebase ToDo application saves the events to FireStore. The Database-Driven Application sends and receives the events through the WebSockets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are new to AppRun, read the &lt;a href="https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/" rel="noopener noreferrer"&gt;AppRun Book&lt;/a&gt; or visit &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun Docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Live Demo and Source Code
&lt;/h2&gt;

&lt;p&gt;You can play with the live demo at &lt;a href="https://apprun-demo.firebaseapp.com" rel="noopener noreferrer"&gt;https://apprun-demo.firebaseapp.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Or visit the project on Github.&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/yysun" rel="noopener noreferrer"&gt;
        yysun
      &lt;/a&gt; / &lt;a href="https://github.com/yysun/apprun-firebase" rel="noopener noreferrer"&gt;
        apprun-firebase
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A serverless application using Firebase and AppRun
    &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;h2 class="heading-element"&gt;AppRun Firebase Serverless App&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/yysun/apprun-firebase/architecture.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fyysun%2Fapprun-firebase%2FHEAD%2Farchitecture.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;em&gt;npm start&lt;/em&gt; to start the dev server&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;npm test&lt;/em&gt; to run unit tests&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;npm run build&lt;/em&gt; to build for production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an application built with &lt;a href="https://github.com/yysun/apprun" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt;.&lt;/p&gt;

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


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The AppRun event pub-sub pattern looks so simple (just &lt;em&gt;app.run&lt;/em&gt; and &lt;em&gt;app.on&lt;/em&gt;), yet so powerful. It is not only useful inside the frontend app. It shines more in crossing process boundaries, such as in the cases of &lt;a href="https://dev.to/yysun/create-a-phoenix-liveview-like-app-in-js-with-apprun-dc8"&gt;WebSockets&lt;/a&gt;, &lt;a href="https://github.com/yysun/apprun-apress-book/tree/master/Chapter_05" rel="noopener noreferrer"&gt;Web Workers&lt;/a&gt;, &lt;a href="https://github.com/apprunjs/apprun-electron-forge" rel="noopener noreferrer"&gt;Electron Apps&lt;/a&gt;, Firebase of course, and more ...&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; and build event-driven applications.&lt;/p&gt;

</description>
      <category>apprun</category>
      <category>serverless</category>
      <category>firebase</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Avoid Spaghetti Code using AppRun</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Tue, 24 Mar 2020 00:57:06 +0000</pubDate>
      <link>https://dev.to/yysun/apprun-helps-to-avoid-spaghetti-code-1835</link>
      <guid>https://dev.to/yysun/apprun-helps-to-avoid-spaghetti-code-1835</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently I was asked to refresh an old application that has the so-called spaghetti code. There are different levels of problems. Many can be solved just refactoring to use new JavaScript language features such as using modules. However, two problems are hard to solve without the help of a framework, which I call them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct State Update&lt;/li&gt;
&lt;li&gt;Rendering Fragments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the post, I will show you how &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; can help to solve the problems. Therefore we can avoid spaghetti code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;I cannot show the real production code I am dealing with, so I made an abstracted example to demonstrate the problems. As usual, I am using a &lt;em&gt;counter&lt;/em&gt; example that has two buttons. One to increase the counter. The other one to decrease the &lt;em&gt;counter&lt;/em&gt;. Also, I made it a litter complicated to show how many times each button is clicked.&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%2Fhdjy2w33ipeqdv9wxbea.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%2Fhdjy2w33ipeqdv9wxbea.png" alt="Counter" width="242" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Code
&lt;/h2&gt;

&lt;p&gt;The code below uses jQuery. jQuery is a library that provides the convenience to access and manipulation of the DOM. It does not provide any architectural guidance. jQuery code is similar to the vanilla JavaScript code that can go wild.&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="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="c1"&gt;// global state&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count_plus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count_minus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// state update&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;
      &lt;span class="nx"&gt;count_plus&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;

      &lt;span class="c1"&gt;// rendering&lt;/span&gt;
      &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#total&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#plus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`+ (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// state update&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;
      &lt;span class="nx"&gt;count_minus&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;

      &lt;span class="c1"&gt;// rendering&lt;/span&gt;
      &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#total&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#minus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`- (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count_minus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#plus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&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="nx"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#minus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&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="nx"&gt;minus&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;You can see from the above code that event handlers &lt;em&gt;plus&lt;/em&gt; and &lt;em&gt;minus&lt;/em&gt; have the problem patterns. They update the state directly. They also render the DOM in different pieces. &lt;/p&gt;

&lt;p&gt;But the real problem is that there isn't a way to break them further. The state has to be shared globally. And the rendering has to be different in each click event.&lt;/p&gt;

&lt;p&gt;In much more complicated real applications, the logic could be long and tangled even more. &lt;/p&gt;

&lt;h2&gt;
  
  
  AppRun
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/yysun/apprun" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; is the framework that can solve the two problems. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are new to AppRun, read the &lt;a href="https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/" rel="noopener noreferrer"&gt;AppRun Book&lt;/a&gt; or visit &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun Docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  State Management
&lt;/h3&gt;

&lt;p&gt;AppRun is a &lt;em&gt;state&lt;/em&gt; management system. It is also an event-driven system that has an event lifecycle. During an AppRun event lifecycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppRun let you update the &lt;em&gt;state&lt;/em&gt; when needed&lt;/li&gt;
&lt;li&gt;AppRun let you create a virtual DOM out of the &lt;em&gt;state&lt;/em&gt; when needed&lt;/li&gt;
&lt;li&gt;AppRun renders the virtual DOM when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sort of following the Hollywood Principle (Don't call us. We call you.) here, we provide code pieces to AppRun and wait for AppRun to call them. &lt;/p&gt;

&lt;p&gt;We write functions to update the &lt;em&gt;state&lt;/em&gt;. AppRun gives the &lt;em&gt;current state&lt;/em&gt;. We create a new &lt;em&gt;state&lt;/em&gt; based on the &lt;em&gt;current state&lt;/em&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="na"&gt;count_minus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count_minus&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;const&lt;/span&gt; &lt;span class="nx"&gt;plus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="na"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count_plus&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be able to concentrate on the parts that are needed to update. We can spread out the rest of the &lt;em&gt;state&lt;/em&gt; using the spread operator. Also, because there is no reference to a shared global object, it is very easy to unit test the &lt;em&gt;state&lt;/em&gt; update logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  DOM Rendering
&lt;/h3&gt;

&lt;p&gt;We also write a &lt;em&gt;view&lt;/em&gt; function that AppRun will call with the &lt;em&gt;state&lt;/em&gt; as the input parameter. We usually use JSX in the &lt;em&gt;view&lt;/em&gt; function to create a virtual DOM, which is just data structure. The &lt;em&gt;view&lt;/em&gt; function does not render the DOM. AppRun renders the DOM using a diffing algorithm. It only renders the DOM that is needed to change. Therefore, we only need one &lt;em&gt;view&lt;/em&gt; function for all events. AppRun takes care of the differential rendering accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count_minus&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;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;
  &amp;lt;button onclick="app.run('minus')"&amp;gt;- (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count_minus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="app.run('plus')"&amp;gt;+ (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;lt;/button&amp;gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;view&lt;/em&gt; function always returns the same result as long as the &lt;em&gt;state&lt;/em&gt; is the same. It also does not change the &lt;em&gt;state&lt;/em&gt; or anything outside the function, which means it has no side effects. We can make the &lt;em&gt;view&lt;/em&gt; function a &lt;em&gt;pure function&lt;/em&gt;. There are many benefits of using &lt;em&gt;pure function&lt;/em&gt;, including but not limited to the unit testing. It makes the UI code easy to unit test.&lt;/p&gt;

&lt;p&gt;Using AppRun, we have a &lt;em&gt;counter&lt;/em&gt; application made from the &lt;em&gt;state, _view&lt;/em&gt;, and &lt;em&gt;update&lt;/em&gt; as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// initial state object&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;count&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="na"&gt;count_plus&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="na"&gt;count_minus&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="c1"&gt;// one view function to render the state, its' a pure function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count_minus&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;html&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;
  &amp;lt;button onclick="app.run('minus')"&amp;gt;- (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count_minus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="app.run('plus')"&amp;gt;+ (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;lt;/button&amp;gt;
`&lt;/span&gt;

&lt;span class="c1"&gt;// collection of state updates, state is immutable&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="na"&gt;count_minus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count_minus&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;const&lt;/span&gt; &lt;span class="nx"&gt;minus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="na"&gt;count_plus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count_plus&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minus&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the AppRun state management and DOM differential rendering in place, we no longer have the problem mixing state update with DOM rendering. &lt;/p&gt;

&lt;p&gt;Usually, at this moment, I will show you the live demo on glitch. This time, I will show the interactive notebook I made on observable HQ. I feel I like the notebook more and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://observablehq.com/@yysun/apprun-helps-to-avoid-spaghetti-code" rel="noopener noreferrer"&gt;https://observablehq.com/@yysun/apprun-helps-to-avoid-spaghetti-code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;No matter how complex the application is, we will always have three parts, the &lt;em&gt;state&lt;/em&gt;, &lt;em&gt;view&lt;/em&gt;, and &lt;em&gt;update&lt;/em&gt;. We no longer mix the state update with DOM rendering. Because the three parts are totally decoupled, our codebase is so much easier to understand, test, and maintain.&lt;/p&gt;

</description>
      <category>apprun</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Create a Phoenix LiveView Like App in JS with AppRun</title>
      <dc:creator>yysun</dc:creator>
      <pubDate>Sat, 21 Mar 2020 16:23:23 +0000</pubDate>
      <link>https://dev.to/yysun/create-a-phoenix-liveview-like-app-in-js-with-apprun-dc8</link>
      <guid>https://dev.to/yysun/create-a-phoenix-liveview-like-app-in-js-with-apprun-dc8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When I was creating the &lt;a href="https://github.com/yysun/apprun-websockets" rel="noopener noreferrer"&gt;AppRun Websockets Template&lt;/a&gt;, I thought I was the only crazy person to push and run the 1 + 1 calculation on the server-side until I saw &lt;a href="https://www.youtube.com/watch?v=U_Pe8Ru06fM" rel="noopener noreferrer"&gt;this video&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/U_Pe8Ru06fM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Phoenix LiveViewis a server-side solution using the &lt;a href="https://elixir-lang.org" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt; programming language.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My &lt;a href="https://apprun.js.org" rel="noopener noreferrer"&gt;AppRun&lt;/a&gt; WebSockets solution shares the same idea with &lt;a href="https://github.com/phoenixframework/phoenix_live_view" rel="noopener noreferrer"&gt;Phoenix LiveView&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, the AppRun solution is 100% JavaScript. For those JavaScript/TypeScript developers that are not ready to learn another programming language, the AppRun solution is for you.&lt;/p&gt;

&lt;p&gt;This post is a step by step instruction of how to create a WebSockets based AppRun application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Project
&lt;/h2&gt;

&lt;p&gt;To get started, run the following commands in the terminal or command shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx degit apprunjs/apprun-websockets my-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You will see a single page application using Bootstrap. &lt;/p&gt;
&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;The project has a typical express JS project structure. &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%2F9jhhtgn8zcmy0e8hlbdp.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%2F9jhhtgn8zcmy0e8hlbdp.png" alt="Project Structure" width="400" height="1336"&gt;&lt;/a&gt;&lt;br&gt;Figure 1. Project Structure
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;server&lt;/em&gt; directory has the server-side code&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;server/index.js&lt;/em&gt; is the webserver&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;src&lt;/em&gt; directory has the client-side code&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;public&lt;/em&gt; directory has the static assets &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;public/index.html&lt;/em&gt; is the default web page of the app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project also has a few npm scripts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;npm start:client&lt;/em&gt;: compiles and watches the client-side app&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;npm start:server&lt;/em&gt;: starts the webserver&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;npm start&lt;/em&gt;: starts client and server&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;npm run build&lt;/em&gt;: build the client-side app for production&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Understand the Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Client Side
&lt;/h3&gt;

&lt;p&gt;On the &lt;em&gt;Home&lt;/em&gt; page of the SPA, there are two counters. One runs locally in the browser. One runs on the server.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apprun&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&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;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num&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;state&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&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;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="nx"&gt;locally&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//ws:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;$onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//ws:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="nx"&gt;through&lt;/span&gt; &lt;span class="nx"&gt;web&lt;/span&gt; &lt;span class="nx"&gt;sockets&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@add&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&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;state&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;They all use the AppRun event-driven programming model to trigger the state update and render lifecycle. The local counter uses local event directive. The server counter uses a global event //ws:, which means the send it to sever. The event parameters are &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&gt;, 1 or &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&gt; -1. &lt;/p&gt;

&lt;p&gt;The &lt;em&gt;main.tsx&lt;/em&gt; has five lines of code to send the event to the server through the web socket. The event name is &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&gt;. The event parameter is 1 or -1.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&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;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ws://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//ws:&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;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&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;
  
  
  Server Side
&lt;/h3&gt;

&lt;p&gt;On the server-side, index.js creates an express server and listen to the web socket communication. When it receives messages, it publishes the messages using AppRun.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apprun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apprun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./add&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&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;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &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="k"&gt;try&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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;apprun&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;error&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Yes. AppRun runs on the server too to provide server-side event-driven programming. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;em&gt;add.js&lt;/em&gt; is a server-side module that handles the &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&gt; event. It does the calculation to update the &lt;em&gt;state&lt;/em&gt;. Then, in &lt;em&gt;index.js&lt;/em&gt;, it sends results back to the web socket as an event using the same event name &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apprun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;
  
  
  Back to Client
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;main.tsx&lt;/em&gt; receives the event from the web socket. It just needs to publish as it is. The event is a global event that has the name &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&gt;. The home page then handles the &lt;a class="mentioned-user" href="https://dev.to/add"&gt;@add&lt;/a&gt; event to get the state calculated on the server.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ws&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="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&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;state&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;We can summarize the process in the diagram below. &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%2Fpvittiwomh5rxyngm72f.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%2Fpvittiwomh5rxyngm72f.png" alt="Events" width="800" height="379"&gt;&lt;/a&gt;&lt;br&gt;Figure 2. Events Between Client and Server
&lt;/p&gt;
&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;You can use the &lt;a href="https://github.com/apprunjs/apprun-websockets" rel="noopener noreferrer"&gt;AppRun—WebSockets template&lt;/a&gt; as the start point. The template has all you need to create your Phoenix LiveView like applications. &lt;/p&gt;

&lt;p&gt;Or you can copy about 20 lines of JS code from the &lt;em&gt;main.tsx&lt;/em&gt; and &lt;em&gt;index.js&lt;/em&gt; into your existing application to start leveraging the power of WebSockets. E.g., &lt;a href="https://dev.to/yysun/database-driven-applications-using-websockets-2b9o"&gt;database-driven applications using WebSockets&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Live Demo
&lt;/h2&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/apprun-websockets?previewSize=100&amp;amp;path=index.html" alt="apprun-websockets on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Because we use JavaScript, our applications are full-featured SPA. We can have &lt;a href="https://apprunjs.github.io/apprun-bootstrap/" rel="noopener noreferrer"&gt;Bootstrap, D3, ChartJS and, even JQuery plug-ins&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The AppRun WebSockets solution is so simple that it does not even worth being an npm package. Use the &lt;a href="https://github.com/apprunjs/apprun-websockets" rel="noopener noreferrer"&gt;AppRun—WebSockets template&lt;/a&gt; or copy about 20 lines of code into your codebase, you will have Phoenix LiveView like applications. &lt;/p&gt;

&lt;p&gt;One last thing to mention is that Phoenix LiveView does the server-side rendering (SSR), which is also &lt;a href="https://github.com/yysun/apprun-ssr" rel="noopener noreferrer"&gt;trivial using AppRun&lt;/a&gt;. However, I favor the Progress Web App (PWA) over SSR because PWA provides offline, home screen icon, and many other features. There is also an &lt;a href="https://github.com/apprunjs/apprun-pwa-workbox" rel="noopener noreferrer"&gt;AppRun template for PWA&lt;/a&gt;.  &lt;/p&gt;

</description>
      <category>apprun</category>
      <category>javascript</category>
      <category>elixir</category>
      <category>websockets</category>
    </item>
  </channel>
</rss>
