<?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>Forem: Maksim</title>
    <description>The latest articles on Forem by Maksim (@maksimrv).</description>
    <link>https://forem.com/maksimrv</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%2F295233%2F7e6c5864-7161-4b97-b9bb-137434ba9a7e.jpg</url>
      <title>Forem: Maksim</title>
      <link>https://forem.com/maksimrv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/maksimrv"/>
    <language>en</language>
    <item>
      <title>JavaScript in IDE scripting console</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Wed, 18 Sep 2024 12:37:21 +0000</pubDate>
      <link>https://forem.com/maksimrv/javascript-in-ide-scripting-console-9c9</link>
      <guid>https://forem.com/maksimrv/javascript-in-ide-scripting-console-9c9</guid>
      <description>&lt;p&gt;&lt;a href="https://www.jetbrains.com/help/idea/ide-scripting-console.html" rel="noopener noreferrer"&gt;Official script example&lt;/a&gt; written in JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function main() {
  let sum = 0;
  let arr = "35907 77134 453661 175096 23673 29350".split(" ");
  arr.forEach((it) =&amp;gt; sum += it.length);

  com.intellij.openapi.ui.Messages.showInfoMessage((sum / arr.length).toString(), "test");
}

main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IDEA uses &lt;a href="https://www.graalvm.org/latest/reference-manual/js/" rel="noopener noreferrer"&gt;GraalJS&lt;/a&gt; to run the script. So you can use &lt;a href="https://www.graalvm.org/latest/reference-manual/js/JavaInteroperability/#access-java-from-javascript" rel="noopener noreferrer"&gt;interop between JavaScript and Java&lt;/a&gt; to access Java objects.&lt;/p&gt;

&lt;p&gt;JavaScript runtime also has a global variable IDE which reference an instance of &lt;a href="https://github.com/JetBrains/intellij-community/blob/master/platform/lang-impl/src/com/intellij/ide/script/IDE.java" rel="noopener noreferrer"&gt;com.intellij.ide.script.IDE&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IDE.print("Hello World!")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>jetbrains</category>
      <category>javascript</category>
      <category>idea</category>
    </item>
    <item>
      <title>Note: Setup Prometheus playground</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Sun, 10 Dec 2023 19:14:33 +0000</pubDate>
      <link>https://forem.com/maksimrv/note-setup-prometheus-playground-3511</link>
      <guid>https://forem.com/maksimrv/note-setup-prometheus-playground-3511</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Download latest version of Prometheus from &lt;a href="https://prometheus.io/download/" rel="noopener noreferrer"&gt;website&lt;/a&gt; and extract from archive, or just use script like this
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PROME_VERSION="2.45.1" &amp;amp;&amp;amp;\
PROME_OS="darwin-amd64" &amp;amp;&amp;amp;\
PROME_FILE="prometheus-${PROME_VERSION}.${PROME_OS}.tar.gz" &amp;amp;&amp;amp;\
curl -L "https://github.com/prometheus/prometheus/releases/download/v${PROME_VERSION}/${PROME_FILE}" -o "/tmp/${PROME_FILE}" &amp;amp;&amp;amp;\
tar xvzf "/tmp/${PROME_FILE}" -C "/tmp"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create Prometheus config file
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; /tmp/prometheus.yml &amp;lt;&amp;lt;EOF
global:
  scrape_interval: 15s
  external_labels:
    monitor: 'codelab-monitor'

scrape_configs:
  - job_name: 'test'
    scrape_interval: 1s
    static_configs:
      - targets: ['localhost:3000']
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run Prometheus passing config file using --config.file argument
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/tmp/prometheus-2.45.1.darwin-amd64/prometheus --config.file=/tmp/prometheus.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In our &lt;code&gt;prometheus.yaml&lt;/code&gt; we have defined getting metrics from localhost:3000 . Let's create simple http server which hold metrics
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; /tmp/index.js &amp;lt;&amp;lt;'EOF'
require('http').createServer(function (req, res) {
  if (req.url === '/metrics') {
    const metricName = 'foo';
    const metricType = 'gauge';
    const metricValue = 1;
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write(`# TYPE ${metricName} ${metricType}\n`);
    res.end(`${metricName} ${metricValue}\n`);
    return;
  }
  res.writeHead(404, {'Content-Type': 'text/plain'});
  res.end('Not found\n');
}).listen(3000, () =&amp;gt; console.log(new Date(), 'Listening on port 3000'));
EOF

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start server
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --watch /tmp/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Open Prometheus graph UI
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;open http://localhost:9090/graph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Play with Prometheus 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;P.S.&lt;/p&gt;

&lt;p&gt;Instead of handwritten server, you can use &lt;a href="https://github.com/prometheus/pushgateway" rel="noopener noreferrer"&gt;Pushgateway&lt;/a&gt; + curl&lt;/p&gt;

</description>
      <category>prometheus</category>
    </item>
    <item>
      <title>A one story about problem with partitioned table in PostgreSQL</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Wed, 01 Nov 2023 18:34:51 +0000</pubDate>
      <link>https://forem.com/maksimrv/a-one-story-about-problem-with-partitioned-table-in-postgresql-433j</link>
      <guid>https://forem.com/maksimrv/a-one-story-about-problem-with-partitioned-table-in-postgresql-433j</guid>
      <description>&lt;p&gt;A one story about performance problem with partitioned table in PostgreSQL.&lt;/p&gt;

&lt;p&gt;Let’s consider the use case where we have table “foo” and track history of changes in this table through trigger which write data to history table “foo_history”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[app]
     -1. insert-&amp;gt;[foo]
                   -2. after insert-&amp;gt;[foo trigger]
                                               -3. insert-&amp;gt;[foo_history]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;“foo_history” uses partitions because potentially it could be big and data from this table would be deleted and collected in a cold storage from time to time. The simplest way to create a partition is create .. partition of..:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create table foo_history_p2 partition of foo_history for
  values from (&amp;lt;date-from&amp;gt;) to (&amp;lt;date-to&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this way requires &lt;a href="https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITIONING-DECLARATIVE-MAINTENANCE" rel="noopener noreferrer"&gt;&lt;strong&gt;ACCESS EXCLUSIVE lock&lt;/strong&gt;&lt;/a&gt; on a &lt;strong&gt;parent table&lt;/strong&gt;. This means that no other operations could be done on this table at the time when we create the partition. Usually, create partition does not take too much. But, what would be if in our application we use some kind of OLAP(Online Analytic Processing) queries over this history tables. For example, we collect some statistics and send it to a statistics server from time to time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[app]
    -select-&amp;gt;[foo_history]
                        -response-&amp;gt;[app]
                                       -send-&amp;gt;[statistics]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These queries can take some time to get a result from “foo_history” table. In our example, let’s consider that such query can take 5 seconds.&lt;/p&gt;

&lt;p&gt;Now let’s return to our “foo” table. We use table “foo” often in our application, mostly to insert data. Queries over “foo” table should be small and fast. And all go well until we don’t get an alert that our insert queries in “foo” aborted duet timeout (from time to time). Looking on a database analytics, we see that those queries blocked and most of the time sit and waiting until lock would be released. What can goes wrong? We use simple insert statement which could not take too much time. And the load on the application is not so big so that we have problem with competing queries.&lt;/p&gt;

&lt;p&gt;Time to remember about our trigger. Trigger runs in the same transaction as query. Every statement event simple INSERT INTO ... is wrapped in a transaction. We can’t commit a transaction until we finish all triggers. Let’s combine insert, trigger, select and create partition together in one chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[app]
    -1. select (5s)-&amp;gt;[foo_history]
  [app]
      -2. create partition-&amp;gt;[foo_history]
    [app]
        -3. insert-&amp;gt;[foo]
                     -4. after insert-&amp;gt;[foo_trigger]
                                                -5. insert-&amp;gt;[foo_history]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;We run statistic query over “foo_history” table&lt;/li&gt;
&lt;li&gt;In a parallel starts the script which try to create a partition for “foo_history” table. Create partition take exclusive lock and wait util query (1) finished.&lt;/li&gt;
&lt;li&gt;At this time goes request to insert data in table “foo”. We open transaction on insert.&lt;/li&gt;
&lt;li&gt;Insert data and call “foo_trigger”&lt;/li&gt;
&lt;li&gt;“foo_trigger” try to insert data in “foo_history” but because “create partition” took exclusive lock we're getting in line after “create partition” and waiting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;so all request on insert in “foo” would wait until long query finished, and we create a partition even if this partition doesn’t necessary for these inserts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;We can move all read query on read only node (if we have master-follower scheme). Postgres allows adding CONCURRENTLY qualifier, but it still requires SHARE UPDATE EXCLUSIVE lock on &lt;strong&gt;the parent table&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Much better would be to &lt;strong&gt;create a partition table separately and after that attach it to the parent table&lt;/strong&gt;. In this case, it would require SHARE UPDATE EXCLUSIVE lock on the &lt;strong&gt;partitioned table&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE foo_history_p2 (LIKE foo_history INCLUDING ALL);

ALTER TABLE foo_history ATTACH PARTITION foo_history_p2 FOR
  VALUES FROM ('2023-12-01 00:00:00.000') TO ('2023-12-30 00:00:00.000');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>postgres</category>
    </item>
    <item>
      <title>Switch Node.js app to debug mode without restart</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Tue, 04 Apr 2023 15:31:40 +0000</pubDate>
      <link>https://forem.com/maksimrv/switch-nodejs-app-to-debug-mode-without-restart-g8c</link>
      <guid>https://forem.com/maksimrv/switch-nodejs-app-to-debug-mode-without-restart-g8c</guid>
      <description>&lt;p&gt;Bootstrap simple Node.js app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /tmp/echo-app &amp;amp;&amp;amp; \
pushd /tmp/echo-app &amp;amp;&amp;amp; \
mkdir src &amp;amp;&amp;amp; \
npm init -y &amp;amp;&amp;amp; \
npm install express

cat &amp;gt; src/index.js &amp;lt;&amp;lt;EOF
function main() {
  const express = require('express');
  const app = express();

  app.use((req, res) =&amp;gt; {
    res.json({
      method: req.method,
      url: req.url,
      headers: req.headers
    });
  });

  app.listen(3000, () =&amp;gt; {
    console.log('Server is running on port 3000');
  });
}

main();
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node src/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And try to switch it to debug mode &lt;strong&gt;without restarting&lt;/strong&gt;. First, we should get node process ID for our application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps aux | grep node | grep src/index.js | awk '{print $2}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now we can send &lt;strong&gt;SIGUSR1&lt;/strong&gt; to node process to switch node in debug mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kill -USR1 &amp;lt;pid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of kill command, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -e 'process._debugProcess(&amp;lt;pid&amp;gt;)'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can look at output where we have started our app. It should print:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Debugger listening on ws://127.0.0.1:9229/a22762b3-fd9e-4a74-99e5-41cf4a627e24
For help, see: https://nodejs.org/en/docs/inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can attach a debugger to our running app. For example, you can open &lt;code&gt;chrome://inspect/#devices&lt;/code&gt; in Chrome browser and see there as Remote Target your app. You can press inspect to open developer tools and set a breakpoint.&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%2Fgchkv3s1qwxq9qtyxu4g.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%2Fgchkv3s1qwxq9qtyxu4g.png" width="800" height="414"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Developer tools with a breakpoint&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To check that we’ll stop at breakpoint, you can send a request to the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl localhost:3000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fiq7nckn925i1p6mh5x6u.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%2Fiq7nckn925i1p6mh5x6u.png" width="800" height="655"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Developer tools with debugger stopped on the breakpoint&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;stop debug&lt;/strong&gt; , you can just type in debugger console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;process._debugEnd()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>node</category>
    </item>
    <item>
      <title>VS Code: Debug node.js app in Kubernetes</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Sat, 18 Mar 2023 22:47:07 +0000</pubDate>
      <link>https://forem.com/maksimrv/vs-code-debug-nodejs-app-in-kubernetes-251f</link>
      <guid>https://forem.com/maksimrv/vs-code-debug-nodejs-app-in-kubernetes-251f</guid>
      <description>&lt;p&gt;Story about how to debug node.js application on Kubernetes using VS 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%2Fzrfkxlysjthkauclacx5.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%2Fzrfkxlysjthkauclacx5.png" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ll use &lt;a href="https://minikube.sigs.k8s.io" rel="noopener noreferrer"&gt;Minikube&lt;/a&gt; as a local Kubernetes cluster. Minikube allows playing with k8s without fear to break something.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup environment
&lt;/h3&gt;

&lt;p&gt;Let’s create a simple express application. The first step is creating the app folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /tmp/app &amp;amp;&amp;amp; \
pushd /tmp/app &amp;amp;&amp;amp; \
npm init -y &amp;amp;&amp;amp; \
npm install express &amp;amp;&amp;amp; \
mkdir src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create index.js with simple express server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; src/index.js &amp;lt;&amp;lt;EOF
function main() {
  const express = require('express');
  const app = express();

  app.get('/', (_, res) =&amp;gt; {
    res.send('Hello World!!!');
  });

  app.listen(3000, () =&amp;gt; {
    console.log('Example app listening on port 3000!');
  });
}

main();
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add Dockerfile for our simple app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; Dockerfile &amp;lt;&amp;lt;EOF
FROM node:18-slim

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
COPY src ./src

RUN npm ci --only=production

EXPOSE 3000

CMD ["node", "src/index.js"]
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build node-app docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t node-app .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Minikube&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push our image to Minikube docker registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube image load node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add deployment.yaml for Kubernetes cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; deployment.yaml &amp;lt;&amp;lt;EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: node-app
  name: node-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-app
  template:
    metadata:
      labels:
        app: node-app
    spec:
      containers:
      - image: node-app
        name: node-app
        imagePullPolicy: Never
        resources: {
          limits: {
            cpu: 500m,
            memory: 512Mi
          }
        }
        ports:
          - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: node-service
spec:
  type: NodePort
  selector:
    app: node-app
  ports:
  - port: 3000
    targetPort: 3000
    nodePort: 30000
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create test namespace in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create namespace test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use test namespace by default for kubectl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl config set-context --current --namespace=test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload depolyment.yaml :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that our pods are running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start proxy Minikube to allow accessing our Kubernetes app from localhost. The following command will create a proxy, so don’t terminate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube service node-service --url -n test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy URL from previous command output and test that we can send a request to our pod from the localhost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://127.0.0.1:61127
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup VS Code
&lt;/h3&gt;

&lt;p&gt;Open /tmp/app folder in VS Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code -n /tmp/app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools" rel="noopener noreferrer"&gt;Kubernetes extension&lt;/a&gt; for VS Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code --install-extension ms-kubernetes-tools.vscode-kubernetes-tools --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run command in VS Code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes: Focus on Cluster View
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you should see minikube cluster. You can expand Workloads &amp;gt; Pods to see our running pods.&lt;/p&gt;

&lt;p&gt;Now let’s open src/index.js the file and set the breakpoint on line:6 where we send the response res.send. Open command pallet and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Kubernetes: Debug(Attach). 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Select our pod&lt;/li&gt;
&lt;li&gt;Select nodejs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VS Code will start node.js debug session inside our pod container. Now let’s check that we’ll stop at breakpoint by sending a request to our service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://127.0.0.1:61127
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at VS Code, you should see that we have stopped on our breakpoint.&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%2F1tbisja7ku9je32s9ley.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%2F1tbisja7ku9je32s9ley.png" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Stop on breakpoint inside Pod container&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we can debug our deployed application on Kubernetes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Develop local app inside Kubernetes
&lt;/h3&gt;

&lt;p&gt;In previous section, we have learned how to debug deployed application, but we can’t modify it without rebuilding &amp;amp; redeploying the whole app. In this section, we set up a workflow so that we can proxy all Kubernetes requests to our local application, so we can develop our app inside Kubernetes environment.&lt;/p&gt;

&lt;p&gt;Stop debug session from the previous section.&lt;/p&gt;

&lt;p&gt;Install &lt;strong&gt;Bridge to Kubernetes&lt;/strong&gt; extension for VS Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code --install-extension mindaro.mindaro --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open command pallet in VS Code and type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bridge to Kubernetes: Configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Select node-service&lt;/li&gt;
&lt;li&gt;Enter port 3000. This is the port where we start our local app.&lt;/li&gt;
&lt;li&gt;Select Configure Bridge to Kubernetes without a launch configuration&lt;/li&gt;
&lt;li&gt;And No this will redirect all requests to our local machine. But Yes is helpful when you run it on shared Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, now we have finished Bridge configuration. Let’s start our local application. You can start it in terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node src/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or run in debug mode via VS Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Debug: Start Debugging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bridge to Kubernetes: Open Menu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And select Connect to the cluster. This command will modify Kubernetes deployment. And create an additional pod and job. This is required to proxy all request from Kubernetes node-app to local machine. You can see it by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or other Kubernetes introspection command. How does it work, in more details you can &lt;a href="https://learn.microsoft.com/en-us/visualstudio/bridge/overview-bridge-to-kubernetes?view=vs-2019" rel="noopener noreferrer"&gt;read here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For now, let’s change res.send('Hello World!!!'); on res.send('Oh boy!!!') and run the same curl command to send request to our service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://127.0.0.1:61127
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as a result, you will see&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Oh boy!!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so now you can develop and debug your application in live mode on Kubernetes 🎉&lt;/p&gt;

</description>
      <category>node</category>
      <category>vscode</category>
      <category>kubernetes</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Compile Clojure to native binary using GraalVM</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Thu, 31 Mar 2022 18:17:14 +0000</pubDate>
      <link>https://forem.com/maksimrv/compile-clojure-to-native-binary-using-graalvm-1a1k</link>
      <guid>https://forem.com/maksimrv/compile-clojure-to-native-binary-using-graalvm-1a1k</guid>
      <description>&lt;p&gt;We’ll write echo command on Clojure and compile it to native binary by &lt;a href="https://www.graalvm.org" rel="noopener noreferrer"&gt;GraalVM&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  🥇 Setup
&lt;/h4&gt;

&lt;p&gt;The first thing first. Create a project directory echo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /tmp/echo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add basic deps.edn&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:mvn/version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.11.0"&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;Create src/echo/main.clj. This would be our entry point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo.main&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="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&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="nb"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&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;Run clj -M -m echo.main to be sure that all works fine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; echo.main foo bar
foo bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🥈 Build uberjar
&lt;/h4&gt;

&lt;p&gt;Add build.clj to project’s root directory. This file contains logic how to build a Java jar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clojure.tools.build.api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&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="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class-dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"target/classes"&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="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;b/create-basis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"deps.edn"&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="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jar-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"target/echo.jar"&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="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&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="nf"&gt;b/delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"target"&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="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uberjar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&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="nf"&gt;clean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&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="nf"&gt;b/copy-dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:src-dirs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="no"&gt;:target-dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class-dir&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="nf"&gt;b/compile-clj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:basis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basis&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:src-dirs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:class-dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class-dir&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="nf"&gt;b/uber&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:class-dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class-dir&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="no"&gt;:uber-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jar-file&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="no"&gt;:basis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basis&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="no"&gt;:main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;'echo.main&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;Now let’s add &lt;a href="https://clojure.org/guides/tools_build" rel="noopener noreferrer"&gt;tools.build&lt;/a&gt; and :build task to deps.edn&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:mvn/version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.11.0"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:aliases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:build&lt;/span&gt;&lt;span class="w"&gt;  
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt;  
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;io.github.clojure/tools.build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:git/tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"v0.8.1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:git/sha&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"7d40500"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;  
 &lt;/span&gt;&lt;span class="no"&gt;:ns-default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&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;And the last thing is to mark our echo.main as :gen-class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo.main&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:gen-class&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="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&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="nb"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&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;Now we are ready to build uberjar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-T&lt;/span&gt;:build uberjar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a jar in the target folder. You can run it by java&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; target/echo.jar foo bar
foo bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🥉 Build native
&lt;/h4&gt;

&lt;p&gt;To build native script, we should install &lt;a href="https://dev.to/maksimrv/install-graalvm-on-macos-m1-1p8n"&gt;GraalVM&lt;/a&gt; after that we should add com.github.clj-easy/graal-build-time as a dependency to automate declaration of libraries by_ — initialize-at-build-time_&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:mvn/version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.11.0"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;com.github.clj-easy/graal-build-time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:mvn/version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.4"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:aliases&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:build&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;io.github.clojure/tools.build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:git/tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"v0.8.1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:git/sha&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"7d40500"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:ns-default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&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;Rebuild jar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-T&lt;/span&gt;:build uberjar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we are ready to run native-image to build binary&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;native-image &lt;span class="nt"&gt;-jar&lt;/span&gt; target/echo.jar &lt;span class="nt"&gt;--no-fallback&lt;/span&gt; &lt;span class="nt"&gt;--no-server&lt;/span&gt; target/echo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate a native binary from the jar to &lt;em&gt;target/echo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s test our binary&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./target/echo foo bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The end 🎉&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>graalvm</category>
    </item>
    <item>
      <title>Install GraalVM on macOS M1</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Thu, 31 Mar 2022 16:41:49 +0000</pubDate>
      <link>https://forem.com/maksimrv/install-graalvm-on-macos-m1-1p8n</link>
      <guid>https://forem.com/maksimrv/install-graalvm-on-macos-m1-1p8n</guid>
      <description>&lt;p&gt;We can download &lt;a href="https://github.com/graalvm/graalvm-ce-builds/releases" rel="noopener noreferrer"&gt;required version of GraalVM&lt;/a&gt; using curl&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--create-dirs&lt;/span&gt; &lt;span class="nt"&gt;--output-dir&lt;/span&gt; ~/Library/Java/JavaVirtualMachines &lt;span class="nt"&gt;-OL&lt;/span&gt; https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.0.0.2/graalvm-ce-java17-darwin-amd64-22.0.0.2.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will download graalvm-ce-java17-darwin-adm64-22.0.0.2.tar.gz to ~/Library/Java/JavaVirtualMachines. Now we should extract archive’s content by tar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tar &lt;/span&gt;xvzf graalvm-ce-java17-darwin-amd64-22.0.0.2.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can add GRAALVM_HOME environment variables to .bashrc or .zshrc&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;GRAALVM_HOME &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Java/JavaVirtualMachines/graalvm-ce-java17-22.0.0.2/Contents/Home"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;also, we can add GraalVM bin folder to the PATH . This allows us to easily access executable commands from shell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GRAALVM_HOME&lt;/span&gt;&lt;span class="s2"&gt;/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can easily install native-image using gu command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gu &lt;span class="nb"&gt;install &lt;/span&gt;native-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>graalvm</category>
      <category>macos</category>
      <category>applesilicon</category>
    </item>
    <item>
      <title>Setup shadow-cljs react project</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Sun, 13 Mar 2022 16:47:16 +0000</pubDate>
      <link>https://forem.com/maksimrv/setup-shadow-cljs-react-project-29cg</link>
      <guid>https://forem.com/maksimrv/setup-shadow-cljs-react-project-29cg</guid>
      <description>&lt;h4&gt;
  
  
  🚀 Create project
&lt;/h4&gt;

&lt;p&gt;The first step is create a project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-cljs-project my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a project &lt;em&gt;my-project&lt;/em&gt; with minimal required structure and install required dev dependencies for proper work of shadow-cljs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── package-lock.json
├── package.json
├── shadow-cljs.edn
└── src
    ├── main
    └── test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;shadow-cljs.edn is a &lt;a href="https://shadow-cljs.github.io/docs/UsersGuide.html#_basic_workflow" rel="noopener noreferrer"&gt;configuration file&lt;/a&gt; for ClojureScript project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; shadow-cljs configuration
{:source-paths
 ["src/dev"
  "src/main"
  "src/test"]

:dependencies
 []

:builds
 {}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ♺ Compile ClojureScript to JavaScript
&lt;/h4&gt;

&lt;p&gt;Now, let’s create an entry point ClojureScript file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch ./src/main/core.cljs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add minimal boilerplate code to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; ./src/main/core.cljs
(ns core)

(defn main []
  (js/console.log "Hello World!"))

(main)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should specify how to build the project. To do this, we should modify the :builds section in &lt;em&gt;shadow-cljs.edn&lt;/em&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

:builds
 {: **app** {:target : **browser**
        :modules {: **main** {:entries [**core**]}}}}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;:app is a build id&lt;/li&gt;
&lt;li&gt;:browser is target’s type for generated JavaScript files&lt;/li&gt;
&lt;li&gt;:main is a name of generated JavaScript file&lt;/li&gt;
&lt;li&gt;core is a ClojureScript entry namespace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add :output-dir "public/js" to explicitly specify output directory for generated files by default shadow-cljs will use public/js&lt;/p&gt;

&lt;p&gt;Now we can compile our ClojureScript to JavaScript files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx shadow-cljs compile **app**

shadow-cljs - config: /private/tmp/my-project/shadow-cljs.edn
shadow-cljs - connected to server
[:app] Compiling ...
[:app] Build completed. (43 files, 0 compiled, 0 warnings, 0.33s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  👾 Start server
&lt;/h4&gt;

&lt;p&gt;Now we are ready to setup the development server which will serve our static files. For this, we should return back to &lt;em&gt;shadow-cljs.edn&lt;/em&gt; and add information about the dev server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:dev-http {8000 "public"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;8000 is a port which will be used by http server&lt;/li&gt;
&lt;li&gt;public is a folder name for static files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can start it by using watch command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx shadow-cljs **watch** app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beside the start http server watchcommand also automatically recompile JavaScript files when we change ClojureScript one&lt;/p&gt;

&lt;p&gt;You can open &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt; and see that the server is running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Not found. Missing index.html.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but complains on missing index.html. Let’s add index.html to the public folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch ./public/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add some minimal markup with reference to our generated JavaScript file&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;!DOCTYPE html&amp;gt;
&amp;lt;html lang=""&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;my-project&amp;lt;/title&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id="app"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script src=" **js/main.js**" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we open developer tools in the browser we should see “Hello World!” message in the browser’s console. You can open &lt;em&gt;core.cljs&lt;/em&gt; file and change the message. Browser automatically pickup the change via embedded to shadow-cljs live update functionality and display the new message&lt;/p&gt;

&lt;h4&gt;
  
  
  📦 Add React as dependency
&lt;/h4&gt;

&lt;p&gt;shadow-cljs support npm dependencies, so here we can install react via npm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use React in our ClojureScript application. Let’s print React’s version in the browser’s console. To do this, let’s modify core.cljs file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; ./src/main/core.cljs
(ns core **(:require ["react" :as react])**)

(defn main []
  (js/console.log **(.-version react)**))

(main)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can look at the console without restarting the server and see that now it displays React version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Log] shadow-cljs: load JS – "node_modules/react/index.js"
[Log] shadow-cljs: load JS – "core.cljs"
[Log] 17.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the same way, we can install react-dom and render “Hello World!”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(ns core (:require 
           ["react" :as react]
           **["react-dom" :as react-dom]**))

(defn main []
  **(let [app-node (.getElementById js/document "app")]  
 (.render react-dom "Hello World!" app-node))** )

(main)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🎸 Reagent
&lt;/h4&gt;

&lt;p&gt;We can use raw react and react-dom in our ClojureScript but it’s much better and less verbose to use Reagent is a minimalistic ClojureScript interface for React.&lt;/p&gt;

&lt;p&gt;Because Reagent is a ClojureScript module, we can’t install it via npm. To install it, we should define required version in &lt;em&gt;shadow-cljs.edn&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:dependencies
 [**[reagent "1.1.1"]**]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reagent is dependent from React &amp;amp; React DOM packages, so you still should install them via NPM.&lt;/p&gt;

&lt;p&gt;Let’s update core.cljs code and replace React on Reagent&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; ./src/main/core.cljs
(ns core (:require 
          **[reagent.core :as r]  
 [reagent.dom :as rdom]** ))

**(defn app []  
 [:b "Hello World!"])**  

(defn main []
  (let [app-node (.getElementById js/document "app")]
    **(rdom/render [app] app-node)**))

(main)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>reagent</category>
      <category>react</category>
      <category>clojurescript</category>
    </item>
    <item>
      <title>Visual unit tests</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Mon, 27 Sep 2021 19:47:36 +0000</pubDate>
      <link>https://forem.com/maksimrv/visual-unit-tests-14d9</link>
      <guid>https://forem.com/maksimrv/visual-unit-tests-14d9</guid>
      <description>&lt;p&gt;I hope that most of us use unit tests in day to day development because it saves a lot of time for us to make something new instead of repeat the same mistakes again. In this article, I'll talk about our approach to deal with visual tests&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrospective and wishful thinking.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Standard approach
&lt;/h3&gt;

&lt;p&gt;All visual tests* based on the same approach.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You should run the server with your application.&lt;/li&gt;
&lt;li&gt;You should write tests which run by NodeJS&lt;/li&gt;
&lt;li&gt;As a glue between our application and tests, we use Puppeteer or Playwright&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expectation code is clean and straightforward
&lt;/li&gt;
&lt;/ul&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;image&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatchImageSnapshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test code and code under tests are too far from each other
In the test code, we usually call the driver to open some page where located code under test. In the best cases, such pages are somehow automatically generated. This led to notable switch between code under test and test itself that lead to frustration
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Average visual regression test code&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// create a tab/page&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// navigate to URL where located the code which we want to test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Complicated setup and teardown. To run tests, we usually should set up two servers. One for code under test and another for tests itself&lt;/li&gt;
&lt;li&gt;Usually such tests are slow due to complex setup and communication between test and code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these problems and consequences prevent to write visual tests with pleasure. But visual problems haven't gone anywhere&lt;/p&gt;

&lt;h3&gt;
  
  
  What we want or ideal visual test for us
&lt;/h3&gt;

&lt;p&gt;I always dreamed to have something similar to unit test experience. Where you can easily add or remove test. Play with code under tests by tweaking different options and observe the result. Focus on specific test and enjoy fast feedback loop between change and result&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;render&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;UserProfile&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// code under test&lt;/span&gt;
  &lt;span class="c1"&gt;// test code&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Take a screenshot&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatchImageSnapshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Test with reference&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, our test code and what we want to test placed near each other. So by removing test, we're also removing code under test. We can experiment with test and code under test. Because it looks and behave as a regular unit test&lt;/p&gt;

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

&lt;p&gt;For our unit tests, we use Karma because it's flexible, fast and solid tool to test frontend JavaScript in browser even after ~10 years of existing. Also, Karma would be our foundation for visual unit tests. So all approaches and tools which we can use and apply for unit tests are work for visual unit tests too. What we need is provide function to make a screenshot and matcher which compare reference with result.&lt;br&gt;
To make it possible, we take Puppeteer or Playwright as launcher for our tests where we expose &lt;code&gt;screenshot&lt;/code&gt; functionality and possibility to compare screenshot with reference image on the disk for our test code through expose function &lt;a href="https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pageexposefunctionname-puppeteerfunction" rel="noopener noreferrer"&gt;API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We liked matcher functionality provided by &lt;a href="https://github.com/americanexpress/jest-image-snapshot" rel="noopener noreferrer"&gt;jest-image-snapshot&lt;/a&gt;, so we just took this solution and adopted for jasmine and Karma.&lt;/p&gt;

&lt;p&gt;The result is the boom of visual unit tests in our product. Because now write visual unit test as easy as write plain unit test&lt;/p&gt;

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

&lt;p&gt;We love this approach because it already brings benefits of visual tests. And it does not require much effort. We pack it as a &lt;a href="https://www.npmjs.com/package/karma-image-snapshot" rel="noopener noreferrer"&gt;NPM package for karma&lt;/a&gt;, but what we love is the idea of having test code and code under test together, so you can look at our approach and maybe bring a more powerful tool. The repository itself contains tests, so you can open it via Gitpod or GitHub Codespace and play with it without additional setup.&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%2F4qajge95nf6keuqarrv9.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%2F4qajge95nf6keuqarrv9.gif" alt="Video with example of usage" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;- When we're building these tool there no cypress which such functionality but now as I know it provide something similar, and this is cool. Maybe in the future we would migrate to it, but for now we are happy with our current approach &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Font
&lt;/h3&gt;

&lt;p&gt;An innate problem of visual test is a drawing font on different platforms. For us, we decided that in visual tests we want to test only visual part and text/font is more logical part, so we just create a custom font for visual tests where all symbols just black squares which works on all required platforms for us. So the developer can easily write a visual test on macOS and make a reference, and it would work for Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different browsers
&lt;/h3&gt;

&lt;p&gt;Currently, we use only Puppeteer/Chrome to simplify the process of installation, reduce headache with different browsers and improve developer experience to encourage writing visual unit tests. It works for us because it already brings benefits. But solution support use of Playwright(Chromium/Edge, Safari, Firefox) so in the future if all would work fine and robust we are planing to run our tests on different browsers&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>karma</category>
      <category>visualtesting</category>
    </item>
    <item>
      <title>Unit testing JavaScript with Karma. Playwright &amp; Puppeteer</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Sat, 30 Jan 2021 17:12:51 +0000</pubDate>
      <link>https://forem.com/maksimrv/unit-testing-javascript-with-karma-playwright-puppeteer-21kp</link>
      <guid>https://forem.com/maksimrv/unit-testing-javascript-with-karma-playwright-puppeteer-21kp</guid>
      <description>&lt;p&gt;Karma allows run tests in different browsers. In the basic setup, we assume that a developer has the required browser installed on the local machine. Such assumption complicates the test process because it requires manual work from the developer who wants to start writing tests and introduces a difference in a test environment that we could not control. For example, we decided that our unit tests should be run on a specific version of Chrome. Now we should somehow spread this knowledge in our team. This is an inefficient and error-prone approach.&lt;/p&gt;

&lt;p&gt;One of the goals of an experienced engineer to simplify the process of setup and running tests for less experienced teammates. To encourage and spread test culture in the team. &lt;strong&gt;Puppeteer and Playwright allow us to simplify, automate and control the browser setup process&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Puppeteer
&lt;/h3&gt;

&lt;p&gt;Let’s start from Puppeteer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install puppeteer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Puppeteer would install chromium for the target platform automatically&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Downloading Chromium r818858 - 132.4 Mb [====================] 100% 0.0s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s add downloaded Chromium as the default browser for Karma&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;process.env.CHROME_BIN = require('puppeteer').executablePath();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because our default Karma config has &lt;strong&gt;karma-chrome-launcher&lt;/strong&gt; we can reuse it to star Puppeteer’s Chromium simple define CHROME_BIN environment variable in the karma.conf.js&lt;/p&gt;

&lt;p&gt;Let’s run our test and make sure that they pass, and we have not broken anything&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx karma start
30 01 2021 18:02:19.602:INFO [karma-server]: Karma v6.0.3 server started at [http://localhost:9876/](http://localhost:9876/)
30 01 2021 18:02:19.604:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
30 01 2021 18:02:19.609:INFO [launcher]: Starting browser Chrome
30 01 2021 18:02:31.497:INFO [Chrome 88.0.4298.0 (Mac OS 11.0.0)]: Connected on socket -gzowZLOc2OrrmCUAAAB with id 15605462
Chrome 88.0.4298.0 (Mac OS 11.0.0): Executed 2 of 2 SUCCESS (0.011 secs / 0.003 secs)
TOTAL: 2 SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well. Now we can be sure that after run npm install a developer would have full-fledged test environment. We also can run Chrome without UI in headless mode by using ChromeHeadless as a default browser in karma.conf.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;browsers: ['ChromeHeadless'],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you run npx karma start you would not see popped up Chrome window. This may be helpful if you run tests in &lt;strong&gt;watch mode&lt;/strong&gt; to reduce visual noise.&lt;/p&gt;

&lt;p&gt;In most cases, Puppeteer would be enough for unit tests. But what should we do if we want to run tests on Firefox or WebKit based browser like Safari? Here we can use Playwright&lt;/p&gt;

&lt;h3&gt;
  
  
  Playwright
&lt;/h3&gt;

&lt;p&gt;Playwright beside Chrome automatically install Firefox and WebKit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install playwright

Downloading **chromium** v844399 - 98.5 Mb [====================] 100% 0.0s
chromium v844399 downloaded to /Caches/ms-playwright/chromium-844399
Downloading **firefox** v1225 - 73.9 Mb [====================] 100% 0.0s
firefox v1225 downloaded to /Caches/ms-playwright/firefox-1225
Downloading **webkit** v1423 - 51.3 Mb [====================] 100% 0.0s
webkit v1423 downloaded to /Caches/ms-playwright/webkit-1423
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s use Chrome installed by Playwright. What we need to do is just change CHROME_BIN in karma.conf.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;process.env.CHROME_BIN = require('playwright').chromium.executablePath();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a good idea to rerun our tests to be sure that all works fine.&lt;/p&gt;

&lt;p&gt;Setup for &lt;strong&gt;Firefox&lt;/strong&gt; is not so different from Chrome. First we should install official karma-firefox-launcher plugin&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install karma-firefox-launcher
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;update karma.conf.js by setting FIREFOX_BIN and changing browser on Firefox&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;process.env.FIREFOX_BIN = require('playwright').firefox.executablePath();
...
browsers: ['Firefox'],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;run tests&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx karma start
30 01 2021 19:04:40.925:INFO [karma-server]: Karma v6.0.3 server started at [http://localhost:9876/](http://localhost:9876/)
30 01 2021 19:04:40.927:INFO [launcher]: Launching browsers **Firefox** with concurrency unlimited
30 01 2021 19:04:40.934:INFO [launcher]: Starting browser Firefox
30 01 2021 19:04:45.139:INFO [Firefox 85.0 (Mac OS 10.16)]: Connected on socket T1vGhzXoe8dhy_yxAAAB with id 60585180
Firefox 85.0 (Mac OS 10.16): Executed 2 of 2 SUCCESS (0.001 secs / 0.002 secs)
TOTAL: 2 SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SUCCESS! 🎉&lt;/p&gt;

&lt;p&gt;Now we can automatically install Chrome and Firefox for our tests without bothering a developer who want to write tests. Time to go and write some tests.&lt;/p&gt;

</description>
      <category>puppeteer</category>
      <category>playwrights</category>
      <category>javascript</category>
      <category>karma</category>
    </item>
    <item>
      <title>Unit testing JavaScript with Karma in 2021. Starting point</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Sat, 30 Jan 2021 13:43:42 +0000</pubDate>
      <link>https://forem.com/maksimrv/unit-testing-javascript-with-karma-in-2021-starting-point-5dml</link>
      <guid>https://forem.com/maksimrv/unit-testing-javascript-with-karma-in-2021-starting-point-5dml</guid>
      <description>&lt;p&gt;&lt;a href="https://karma-runner.github.io/" rel="noopener noreferrer"&gt;Karma&lt;/a&gt; was born in the era of &lt;a href="https://en.wikipedia.org/wiki/AngularJS" rel="noopener noreferrer"&gt;AngularJS&lt;/a&gt;. This was a significant improvement of existed test tooling on the Web and was one of the reasons for the spread of &lt;a href="https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530" rel="noopener noreferrer"&gt;TDD&lt;/a&gt; in the JavaScript community. Karma still &lt;strong&gt;the best test runner&lt;/strong&gt; for web JavaScript after almost 10 years thanks to the &lt;a href="https://www.youtube.com/watch?v=MVw8N3hTfCI" rel="noopener noreferrer"&gt;architecture and principles it’s based on&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's set up it for a test project and try to understand how it works. The first step is to install it via NPM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install karma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successful installation, we would have Karma binary inside the local node_modules folder. Now let’s create the Karma configuration file for our project using the init command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx karma init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we could select the testing framework from the list of popular frameworks like “&lt;a href="https://jasmine.github.io/" rel="noopener noreferrer"&gt;Jasmine&lt;/a&gt;”, “&lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;Mocha&lt;/a&gt;” etc. In our example, we would use “&lt;a href="https://jasmine.github.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Jasmine&lt;/strong&gt;&lt;/a&gt;” so just press [Enter] to move to the next question.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you want to use Require.js ?
no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://requirejs.org/" rel="noopener noreferrer"&gt;Require.js&lt;/a&gt; was popular 10 years ago for management dependencies when we didn’t have Webpack. Now it’s mostly rudiment so here we select [no]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
&amp;gt; Chrome
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would use Chrome as a default browser for our tests because this is one of the popular browsers nowadays and works on most of operating systems&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
&amp;gt; src/**/*.test.js
&amp;gt; src/**/*.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we should tell Karma where we keep our source and test files. In our example, we would use src/**/*.test.js patter for test files which are widespread now, and src/**/*.js for source files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leaves it empty&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
&amp;gt; yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Karma can be run in two modes “single run” or “watch”. Single run means that when tests are finished karma would stop and to rerun our tests we should do run tests manually again. In the “ &lt;strong&gt;watch&lt;/strong&gt; ” mode Karma would automatically rerun our tests when we change either the source or test files. This pretty handy feature &lt;strong&gt;saves our time&lt;/strong&gt; , so we select [yes] here&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Config file generated at "/&amp;lt;project&amp;gt;/karma.conf.js".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have finished the configuration and Karma says that the result is a karma.conf.js file. But this is not all. Karma also has installed necessary dependencies based on our choices and updated package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+ "karma-chrome-launcher": "^3.1.0",
+ "karma-jasmine": "^4.0.1",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our case these were&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;karma-chrome-launcher the plugin which helps run tests in Chrome&lt;/li&gt;
&lt;li&gt;karma-jasmine an adapter for jasmine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Karma has a plugin architecture. Most of the language and frameworks specific functionality provided by plugins. Karma itself as a runner provides only functionality to run arbitrary JavaScript in a browser via Karma HTTP server. Also, Karma gives you the possibility to process your test and source files before they would be sent to the browser. So roughly say Karma is a mediator between your test/source files, frameworks, browsers, and operating system. Thus, this architecture allows karma to do only one thing but do it well and be open for extension without changing the Karma source itself. I highly encourage you to watch this &lt;a href="https://www.youtube.com/watch?v=MVw8N3hTfCI" rel="noopener noreferrer"&gt;video&lt;/a&gt; and look at the &lt;a href="https://github.com/karma-runner/karma" rel="noopener noreferrer"&gt;Karma source code&lt;/a&gt; itself as an example of a good product that stood the test of time.&lt;/p&gt;

&lt;p&gt;Let’s move back to our test project and finish the Karma setup. Because we decided to use Jasmine as a test framework we should install it too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install jasmine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;karma-jasmine only a Karma adapter for Jasmine itself so this is why we should install Jasmine alongside karma-jasmine.&lt;/p&gt;

&lt;p&gt;Now we are ready to write our first test. Let’s create a file src/foo.test.js and write a test case&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe('My first Karma test', function() {
  it('should be true', function() {
    expect(true).toEqual(true);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before start Karma make sure that you have installed Chrome which we select as our default browser for tests. Now we are ready to run our tests&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx karma start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command would start the Karma server, open the Chrome browser, and run our tests. The result of tests would be printed 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;30 01 2021 14:59:09.329:WARN [karma]: No captured browser, open [http://localhost:9876/](http://localhost:9876/)
30 01 2021 14:59:09.353:INFO [karma-server]: **Karma v6.0.3 server started at** [**http://localhost:9876/**](http://localhost:9876/)
30 01 2021 14:59:09.353:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
30 01 2021 14:59:09.358:INFO [launcher]: Starting browser Chrome
30 01 2021 14:59:10.799:INFO [Chrome 88.0.4324.96 (Mac OS 11.1.0)]: Connected on socket kj6wu3FYg7XPKEKCAAAB with id 15222593
Chrome 88.0.4324.96 (Mac OS 11.1.0): Executed 1 of 1 SUCCESS (0.002 secs / 0.002 secs)
**TOTAL: 1 SUCCESS**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you can notice several interesting points&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Karma starts the server&lt;/li&gt;
&lt;li&gt;Open &lt;a href="http://localhost:9876C" rel="noopener noreferrer"&gt;http://localhost:9876&lt;/a&gt; in Chrome&lt;/li&gt;
&lt;li&gt;Run tests and print the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When tests finished Karma would not stop and wait for changes to rerun tests automatically. Let’s change our test to see how it works&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should be true', function() {
  expect(true).toEqual( **false** );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now look at the result&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;30 01 2021 15:02:37.443:INFO [filelist]: Changed file "/playground/src/foo.test.js".
Chrome 88.0.4324.96 (Mac OS 11.1.0) **My first Karma test should be true FAILED**
        Error: **Expected true to equal false**.
            at &amp;lt;Jasmine&amp;gt;
            at UserContext.&amp;lt;anonymous&amp;gt; ( **src/foo.test.js:3:18** )
            at &amp;lt;Jasmine&amp;gt;
Chrome 88.0.4324.96 (Mac OS 11.1.0): Executed 1 of 1 (1 FAILED) (6.226 secs / 0.001 secs)
**TOTAL: 1 FAILED, 0 SUCCESS**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that Karma automatically rerun the test and told us that now we have 1 failed test. Also, the result contains useful information about the error. The error message contains&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name of a test suite. In our case My first Karma test&lt;/li&gt;
&lt;li&gt;Name of a test case — test should be true&lt;/li&gt;
&lt;li&gt;Expectation/assert error message — Expected true to equal false&lt;/li&gt;
&lt;li&gt;Exception stack trace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because Karma runs tests inside a browser you can use the browser’s developer tools to debug your tests. For this purpose, you can set a breakpoint in a test and open developer tools in Chrome. Also, you can open &lt;a href="http://localhost:9876C" rel="noopener noreferrer"&gt;http://localhost:9876&lt;/a&gt;/debug page where tests would be run in the main window and don’t produce the result in the terminal. If you want to run your tests in another browser you can easily do it without stopping tests and changing configuration by open &lt;a href="http://localhost:9876C" rel="noopener noreferrer"&gt;http://localhost:9876&lt;/a&gt;/ in an interesting browser. It would attach the browser to the Karma server and run tests on it too. This approach also &lt;strong&gt;allows you to run tests on any device and any browser&lt;/strong&gt; just by opening Karma server URL.&lt;/p&gt;

&lt;p&gt;Ok. Let’s fix our test by reverting to the previous change. &lt;strong&gt;To stop tests press [Ctrl-C] in the terminal&lt;/strong&gt; where Karma is running. Now let’s change the Karma configuration file so that test runs without “watch” by default. To do this open karma.conf.js and change singleRun from false to true&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;singleRun: **true** ,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we run tests again by npx karma start you can see Karma stops after tests finished. To run tests in watch mode we should pass --no-single-run parameter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx karma start **--no-single-run**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When karma running in watch mode you can rerun tests without changing source and test files by run command. To do this we should open a &lt;strong&gt;new terminal window&lt;/strong&gt; without terminating karma start process and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx karma run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command mostly useful for the integration of different tools with Karma.&lt;/p&gt;

&lt;p&gt;Now let’s talk about source files. In the example above we have added the test file that contains all logic inside itself. Let’s create the file src/foo.js and write function multiply&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function multiply(x, y) {
  return x * y;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now let’s change add test inside src/foo.test.js so that it would check the result of function multiply&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should multiply 2 on 2', function() {
  expect(multiply(2, 2)).toEqual(4);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don’t stop Karma server you can see that it automatically detect new file and test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Chrome 88.0.4324.96 (Mac OS 11.1.0): Executed 2 of 2 SUCCESS (0.006 secs / 0 secs)
TOTAL: 2 SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have two tests. You can see that function multiply available in the test file this is because &lt;strong&gt;all files are loaded and executed in the same context (on the same page)&lt;/strong&gt;. We had not restricted visibility of our function multiply thus it’s available globally, and we can use it in our test.&lt;/p&gt;

&lt;p&gt;Here I finish the article. This is a &lt;strong&gt;basic setup of Karma and starting point for advanced configuration&lt;/strong&gt;. I recommend starting from the basic setup and when you are sure that it works correctly move towards advanced configuration which usually includes preprocessing step for web projects in our days.&lt;/p&gt;

</description>
      <category>karma</category>
      <category>testing</category>
      <category>jest</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Handling events in React</title>
      <dc:creator>Maksim</dc:creator>
      <pubDate>Sat, 11 Jan 2020 18:20:02 +0000</pubDate>
      <link>https://forem.com/maksimrv/handling-events-in-react-23d9</link>
      <guid>https://forem.com/maksimrv/handling-events-in-react-23d9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Handling events with React elements is very similar to handling events on DOM elements. There are some syntactic differences&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is what &lt;a href="https://reactjs.org/docs/handling-events.html" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt; says. But besides syntactic differences you can face the problem that handling works differently too.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the examples from the official documentation:&lt;/p&gt;

&lt;p&gt;The HTML version&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;button onclick="activateLasers()"&amp;gt;
  Activate Lasers
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the React version&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;button onClick={activateLasers}&amp;gt;
  Activate Lasers
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases if we click on the button, the &lt;code&gt;activateLasers&lt;/code&gt; function would be called. With the difference in &lt;strong&gt;when&lt;/strong&gt; it is going to be called.&lt;/p&gt;

&lt;p&gt;In the HTML version &lt;code&gt;activateLasers&lt;/code&gt; is called on the &lt;strong&gt;button element&lt;/strong&gt; and in the React version &lt;code&gt;activateLasers&lt;/code&gt; is be called on the &lt;a href="https://github.com/facebook/react/blob/e706721490e50d0bd6af2cd933dbf857fd8b61ed/packages/react-dom/src/events/ReactBrowserEventEmitter.js#L179" rel="noopener noreferrer"&gt;&lt;strong&gt;document element&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Why does it matter?&lt;/p&gt;

&lt;p&gt;Usually the document element is the last element in the chain of elements which participate in an event handling[1]. So you can see the situation when the &lt;code&gt;click&lt;/code&gt; handler on an ancestor element would be fired before the &lt;code&gt;click&lt;/code&gt; handler on an descendent element. Usually you can face this problem if you use React with another non React libraries which could listen to DOM events.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I hope this small note would be helpful and will save you a lot of headache down the line if you face this inconsistency between DOM and React event handling.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[1] - Here I’m talking about &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture" rel="noopener noreferrer"&gt;event bubbling phase&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
