<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Siri - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Siri - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 24 Jun 2026 10:06:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/siri/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How I built the SiriWaveJS library: a look at the math and the code ]]>
                </title>
                <description>
                    <![CDATA[ By Flavio De Stefano It was 4 years ago when I had the idea to replicate the Apple® Siri wave-form (introduced with the iPhone 4S) in the browser using pure Javascript. During the last month, I updated this library by doing a lot of refactoring using... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-built-siriwavejs-library-maths-and-code-behind-6971497ae5c1/</link>
                <guid isPermaLink="false">66c34d794f7405e6476b01ed</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Math ]]>
                    </category>
                
                    <category>
                        <![CDATA[ music ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Siri ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 26 Oct 2018 13:50:53 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*DxOICjfEReAFqCeC5V0oNA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Flavio De Stefano</p>
<p>It was 4 years ago when I had the idea to replicate the <strong>Apple® Siri</strong> <strong>wave-form</strong> (introduced with the iPhone 4S) in the browser using pure Javascript.</p>
<p>During the last month, I updated this library by doing a lot of refactoring using ES6 features and reviewed the build process using <strong>RollupJS.</strong> Now I’ve decided to share what I've learned during this process and the math behind this library.</p>
<p>To get an idea what the output will be, visit the <a target="_blank" href="http://kopiro.github.io/siriwave/"><strong>live example</strong></a><strong>;</strong> the whole codebase is <a target="_blank" href="https://github.com/kopiro/siriwave"><strong>here</strong></a>.</p>
<p>Additionally, you can download all plots drawn in this article in GCX (OSX Grapher format): <a target="_blank" href="https://github.com/kopiro/siriwave/raw/master/default.gcx"><strong>default.gcx</strong></a> and <a target="_blank" href="https://github.com/kopiro/siriwave/raw/master/ios9.gcx"><strong>ios9.gcx</strong></a><strong>.</strong></p>
<h3 id="heading-the-classic-wave-style"><strong>The classic wave style</strong></h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/U5DWfdAYQRgGntwYHyJQh2SPSbr2Eals8fD8" alt="Image" width="800" height="400" loading="lazy">
<em>Classic style</em></p>
<p>Initially, this library only had the classic wave-form style that all of you remember using in iOS 7 and iOS 8.</p>
<p>It’s no hard task to replicate this simple wave-form, only a bit of math and basic concepts of the Canvas API.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/HGJeelo1DbenKSl72V423t-q89s3aBWrLet4" alt="Image" width="640" height="308" loading="lazy">
<em>Siri wave-form in iOS 7/8</em></p>
<p>You’re probably thinking that the wave-form is a modification of the <strong>Sine</strong> math equation, and you're right…well, almost right.</p>
<p>Before starting to code, we’ve got to find our linear equation that will be simply applied afterwards. My favourite plot editor is <strong>Grapher;</strong> you can find it in any OSX installation under _Applications &gt; Utilities &gt; Graphe_r.app.</p>
<p>We start by drawing the well known:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-OIGYrieegxfDZ-rlhtkXmrrgBv6VgxZnb3f" alt="Image" width="70" height="18" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/AyYMYn3BxP7KdVZqlLdJ55gcqZHTHB5PFLVi" alt="Image" width="800" height="382" loading="lazy">
<em>Plot for y = sin(x)</em></p>
<p>Perfecto! Now, let’s add some parameters (Amplitude <strong>[A]</strong>, Time coordinate<strong>[t]</strong> and Spatial frequency <strong>[k]</strong>) that will be useful later (Read more here: <a target="_blank" href="https://en.wikipedia.org/wiki/Wave">https://en.wikipedia.org/wiki/Wave</a>).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/tDIRSzaKzb3bBDMJpQ2JfuHxwFPirZliPMV2" alt="Image" width="192" height="19" loading="lazy"></p>
<p>Now we have to “attenuate” this function on plot boundaries, so that for <strong>|x| &gt;</strong>; 2, t<strong>he</strong> y values tends to 0. Let’s draw separately an equati<strong>on g(</strong>x) that has these characteristics.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/EGqbusNiAWDyno0CSwWWpjmklbWccDUeypq1" alt="Image" width="103" height="44" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/L68Rd8wjrZV-9X9al6sme2Wi4kt7Z171E6bb" alt="Image" width="538" height="264" loading="lazy"></p>
<p>This seems to be a good equation to start with. Let’s add some parameters here too to smooth the curve for our purposes:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/FWPk14LdAEnYMvGdv-X65IMf8pMPgJx6pO-5" alt="Image" width="139" height="44" loading="lazy"></p>
<p>Now, by multiplying our <strong>f(x, …)</strong> and <strong>g(x, …)<em>,</em></strong> and by setting precise parameters to the other static values, we obtain something like this.</p>
<ul>
<li><strong>A = 0.9</strong> set the amplitude of the wave to max Y = A</li>
<li><strong>k = 8</strong> set the spatial frequency and we obtain “more peaks” in the range [-2, 2]</li>
<li><strong>t = -π/2</strong> set the phase translation so that <strong>f(0, …) = 1</strong></li>
<li><strong>K = 4</strong> set the factor for the “attenuation equation” so that the final equation is y = 0 when <strong>|x| ≥ 2</strong></li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/mI5c-n9vpwQWrtIK2pWz6R3gz6CCrJ0gRQ3s" alt="Image" width="656" height="385" loading="lazy"></p>
<p>It looks good! ?</p>
<p>Now, if you notice on the original wave we have other sub-waves that will give a lower value for the amplitude. Let’s draw them for <strong>A = {0.8, 0.6, 0.4, 0.2, -0.2, -0.4, -0.6, -0.8}</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/73RU94BxLIkS49r4TWBmA5IVuQwJAyTYPpF6" alt="Image" width="781" height="467" loading="lazy"></p>
<p>In the final canvas composition the sub-waves will be drawn with a decreasing opacity tending to 0.</p>
<h4 id="heading-basic-code-concepts">Basic code concepts</h4>
<p>What do we do now with this equation?</p>
<p>We use the equation to obtain the <strong>Y value</strong> for an <strong>input X</strong>.</p>
<p>Basically, by using a simple <strong>for loop</strong> from <strong>-2 to 2,</strong> (the <em>plot boundaries in this case)</em>, we have to draw <strong>point by point</strong> the equation on the canvas using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath"><strong>beginPath</strong></a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineTo">lineTo</a> API.</p>
<pre><code><span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">'2d'</span>);
</code></pre><pre><code>ctx.beginPath();ctx.strokeStyle = <span class="hljs-string">'white'</span>;
</code></pre><pre><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">-2</span>; i &lt;= <span class="hljs-number">2</span>; i += <span class="hljs-number">0.01</span>) {   <span class="hljs-keyword">const</span> x = _xpos(i);   <span class="hljs-keyword">const</span> y = _ypos(i);   ctx.lineTo(x, y);}
</code></pre><pre><code>ctx.stroke();
</code></pre><p>Probably this pseudo-code will clear up these ideas. We still have to implement our <strong>_xpos</strong> and <strong>_ypos</strong> functions.</p>
<p>But… hey, what is <strong>0.01⁉️</strong> That value represents <strong>how many pixels</strong> you move forward in each iteration before reaching the right plot boundary… but what is the correct value?</p>
<p>If you use a really small value (<strong>&lt;0.</strong>01), you’ll get an insanely precise rendering of the graph but your performance will decrease because you’ll get too many iterations.</p>
<p>Instead, if you use a really big value (<strong>&gt; 0.</strong>1) your graph will lose precision and you’ll notice this instantly.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/3c8OI5O8uiBqD8YUn7bp22xCmxHpCElp8pIh" alt="Image" width="610" height="312" loading="lazy">
<em>Plot drawn with precision = 0.2</em></p>
<p>You can see that the final code is actually similar to the pseudo-code: <a target="_blank" href="https://github.com/kopiro/siriwave/blob/master/src/curve.js#L25">https://github.com/kopiro/siriwave/blob/master/src/curve.js#L25</a></p>
<h4 id="heading-implement-xposi">Implement _xpos(i)</h4>
<p>You may argue that if we’re drawing the plot by incrementing the <strong><em>x</em></strong>, then <strong>_<em>xpos</em></strong> may simply return the input argument.</p>
<p>This is almost correct, but our plot is always drawn from <strong>-B</strong> to <strong>B</strong> <em>(B = Boundary = 2).</em></p>
<p>So, to draw on the canvas via <strong>pixel coordinates</strong>, we must translate <strong>-B to 0,</strong> and <strong>B to 1</strong> (simple transposition of [-B, B] to [0,1]); then multiply [0,1] and the <strong>canvas width (w).</strong></p>
<blockquote>
<p>_xpos(i) = w * [ (i + B) / 2B ]</p>
</blockquote>
<p><a target="_blank" href="https://github.com/kopiro/siriwave/blob/master/src/curve.js#L19">https://github.com/kopiro/siriwave/blob/master/src/curve.js#L19</a></p>
<h4 id="heading-implement-ypos"><strong>Implement _ypos</strong></h4>
<p>To implement <strong>_ypos</strong>, we should simply write our equation obtained before (closely).</p>
<pre><code><span class="hljs-keyword">const</span> K = <span class="hljs-number">4</span>;<span class="hljs-keyword">const</span> FREQ = <span class="hljs-number">6</span>;
</code></pre><pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_attFn</span>(<span class="hljs-params">x</span>) </span>{   <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.pow(K / (K + <span class="hljs-built_in">Math</span>.pow(x, K)), K);}
</code></pre><pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_ypos</span>(<span class="hljs-params">i</span>) </span>{   <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.sin(FREQ * i - phase) *       _attFn(i) *       canvasHeight *      globalAmplitude *       (<span class="hljs-number">1</span> / attenuation);}
</code></pre><p>Let’s clarify some parameters.</p>
<ul>
<li><strong>canvasHeight</strong> is Canvas height expressed in PX</li>
<li><strong>i</strong> is our input value (the <strong>x</strong>)</li>
<li><strong>phase</strong> is the most important parameter, let’s discuss it later</li>
<li><strong>globalAmplitude</strong> is a static parameter that represents the amplitude of the total wave (composed by sub-waves)</li>
<li><strong>attenuation</strong> is a static parameter that changes for each line and represents the amplitude of a wave</li>
</ul>
<p><a target="_blank" href="https://github.com/kopiro/siriwave/blob/master/src/curve.js#L24">https://github.com/kopiro/siriwave/blob/master/src/curve.js#L24</a></p>
<h4 id="heading-phase"><strong>Phase</strong></h4>
<p>Now let’s discuss about the <strong>phase variable:</strong> it is the <strong>first changing variable</strong> over time, because it simulates the wave movement.</p>
<p>What does it mean? It means that <strong>for each <em>animation frame,</em></strong> our base controller should <strong>increment</strong> this value. But to avoid this value throwing a buffer overflow, let’s modulo it with 2π (since <strong>Math.sin</strong> dominio is already modulo 2π).</p>
<pre><code>phase = (phase + (<span class="hljs-built_in">Math</span>.PI / <span class="hljs-number">2</span>) * speed) % (<span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);
</code></pre><p>We multiply <strong>speed</strong> and <strong>Math.PI</strong> so that with <strong>speed = 1</strong> we have the maximum speed (why? because <strong>sin(0) = 0, sin(π/2) = 1, sin(π) = 0, … ?)</strong></p>
<h4 id="heading-finalizing">Finalizing</h4>
<p>Now that we have all code to draw a single line, we define a configuration array to draw all sub-waves, and then cycle over them.</p>
<pre><code><span class="hljs-keyword">return</span> [   { <span class="hljs-attr">attenuation</span>: <span class="hljs-number">-2</span>, <span class="hljs-attr">lineWidth</span>: <span class="hljs-number">1.0</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0.1</span> },   { <span class="hljs-attr">attenuation</span>: <span class="hljs-number">-6</span>, <span class="hljs-attr">lineWidth</span>: <span class="hljs-number">1.0</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0.2</span> },   { <span class="hljs-attr">attenuation</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">lineWidth</span>: <span class="hljs-number">1.0</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0.4</span> },   { <span class="hljs-attr">attenuation</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">lineWidth</span>: <span class="hljs-number">1.0</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0.6</span>},
</code></pre><pre><code>   <span class="hljs-comment">// basic line   { attenuation: 1, lineWidth: 1.5, opacity: 1.0},];</span>
</code></pre><p><a target="_blank" href="https://github.com/kopiro/siriwave/blob/master/src/siriwave.js#L190">https://github.com/kopiro/siriwave/blob/master/src/siriwave.js#L190</a></p>
<h3 id="heading-the-ios-9-style">The iOS 9+ style</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KAVRuTjxVxZvEQEIyG2xru3yzDpLZWvd8zdO" alt="Image" width="1196" height="594" loading="lazy">
<em>GIF of SiriwaveJS iOS9+</em></p>
<p>Now things start to get complicated. The style introduced with iOS 9 is really complex and the reverse engineering to simulate it <strong>it’s not easy at all</strong>! I’m not fully satisfied of the final result, but I’ll continue to improve it until I get the desired result.</p>
<p>As previously done, let’s start to obtain the linear equations of the waves.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/kxsuU2ovEPmN0mqiOwoWM3dHUYmG4wnRAQpc" alt="Image" width="745" height="195" loading="lazy">
<em>Original Siri iOS 9+ wave-form</em></p>
<p>As you can notice:</p>
<ul>
<li>we have three <strong>different specular equations</strong> with different colours (<strong>green, blue, red</strong>)</li>
<li>a single wave seems to be a <strong>sum of sine equations</strong> with <strong>different parameters</strong></li>
<li>all other colours are a <strong>composition</strong> of these three base colours</li>
<li>there is a <strong>straight line</strong> at the plot boundaries</li>
</ul>
<p>By picking again our previous equations, let’s define a more complex equation that <strong>involves translation.</strong> We start by defining again our attenuation equation:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/PFv-Gz5oeue1rG-Wg06zngdoCsTpTPM83k6c" alt="Image" width="199" height="44" loading="lazy"></p>
<p>Now, define <strong>h(x, A, k, t)</strong> function, that is the <strong>sine function</strong> multiplied for <strong>attenuation function,</strong> in its absolute value:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/77pEjutms8rTTvzBaxAIX0dFAyqp6C5pChFp" alt="Image" width="295" height="38" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/gICWeQIDSMxE5jJMSZ2WQv6Kg5zmRQPT54tl" alt="Image" width="522" height="225" loading="lazy"></p>
<p>We now have a powerful tool.</p>
<p>With <strong>h(x)</strong>, we can now create the final wave-form by summing different <strong>h(x)</strong> with different parameters involving different amplitudes, frequency and translations. For example, let’s define the <strong>red curve</strong> by putting random values.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hbal1DKzau5IyTSD4DaTdYc8pJpr3xZqd8Si" alt="Image" width="679" height="18" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/pLT6aOYpEHowx2xYoKy3Iqve6cqC9z4YADZ9" alt="Image" width="800" height="263" loading="lazy"></p>
<p>If we do the same with a <strong>green</strong> and <strong>blue</strong> curve, this is the result:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/QAB6jCDUoq4uzllkLTbhIhKa0XCecjennMZL" alt="Image" width="800" height="268" loading="lazy"></p>
<p>This is not quite perfect, but it could work.</p>
<p>To obtain the specular version, just multiply everything by <strong>-1.</strong></p>
<p>In the coding side, the approach is the same, we have only a more complex equation for <strong>_ypos.</strong></p>
<pre><code><span class="hljs-keyword">const</span> K = <span class="hljs-number">4</span>;<span class="hljs-keyword">const</span> NO_OF_CURVES = <span class="hljs-number">3</span>;
</code></pre><pre><code><span class="hljs-comment">// This parameters should be generated randomlyconst widths = [ 0.4, 0.6, 0.3 ];const offsets = [ 1, 4, -3 ];const amplitudes = [ 0.5, 0.7, 0.2 ];const phases = [ 0, 0, 0 ];</span>
</code></pre><pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_globalAttFn</span>(<span class="hljs-params">x</span>) </span>{   <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.pow(K / (K + <span class="hljs-built_in">Math</span>.pow(x, <span class="hljs-number">2</span>)), K);}
</code></pre><pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_ypos</span>(<span class="hljs-params">i</span>) </span>{   <span class="hljs-keyword">let</span> y = <span class="hljs-number">0</span>;   <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> ci = <span class="hljs-number">0</span>; ci &lt; NO_OF_CURVES; ci++) {      <span class="hljs-keyword">const</span> t = offsets[ci];      <span class="hljs-keyword">const</span> k = <span class="hljs-number">1</span> / widths[ci];      <span class="hljs-keyword">const</span> x = (i * k) - t;            y += <span class="hljs-built_in">Math</span>.abs(         amplitudes[ci] *          <span class="hljs-built_in">Math</span>.sin(x - phases[ci]) *          _globalAttFn(x)      );   }
</code></pre><pre><code>   y = y / NO_OF_CURVES;   <span class="hljs-keyword">return</span> canvasHeightMax * globalAmplitude * y;}
</code></pre><p>There’s nothing complex here. The only thing that changed is that we cycle <strong>NO_OF_CURVES</strong> times over all pseudo-random parameters and we <strong>sum</strong> all <strong>y values.</strong></p>
<p>Before multiplying it for <strong>canvasHeightMax</strong> and <strong>globalAmplitude</strong> that give us the absolute PX coordinate of the canvas, we divide it for NO_OF_CURVES so that <strong>y is always ≤ 1.</strong></p>
<p><a target="_blank" href="https://github.com/kopiro/siriwave/blob/master/src/ios9curve.js#L103">https://github.com/kopiro/siriwave/blob/master/src/ios9curve.js#L103</a></p>
<h4 id="heading-composite-operation"><strong>Composite operation</strong></h4>
<p>One thing that actually matters here is the <strong>globalCompositeOperation</strong> mode to set in the Canvas. If you notice, in the original controller, when there’s a overlap of 2+ colors, they’re actually mixed in a standard way.</p>
<p>The default is set to <strong>source-over</strong>, but the result is poor, even with an opacity set.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/fR8PeyeFbcJq-8Qycopohv6M1hfIK4Zudjal" alt="Image" width="800" height="388" loading="lazy">
<em>composite operation: source-over</em></p>
<p>You can see all examples of vary <strong>globalCompositeOperation</strong> here: <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation">https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation</a></p>
<p>By setting <strong>globalCompositeOperation</strong> to <strong>“ligther”</strong>, you notice that the intersection of the colours is nearest to the original.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/I5HGeo9b8U3bmt1XquQiRsdohkUZeRzIFE3x" alt="Image" width="800" height="370" loading="lazy">
<em>Composite operation: lighter</em></p>
<h3 id="heading-build-with-rollupjs">Build with RollupJS</h3>
<p>Before refactoring everything, I wasn’t satisfied at all with the codebase: old prototype-like classes, a single Javascript file for everything, no uglify/minify and <strong>no build at all.</strong></p>
<p>Using the new ES6 feature like <strong>native classes, spread operators</strong> and <strong>lambda functions</strong>, I was able to clean everything, split files, and decrease lines of unnecessary code.</p>
<p>Furthermore, I used <a target="_blank" href="https://rollupjs.org/">RollupJS</a> to create a transpiled and minified build in various formats.</p>
<p>Since this is a browser-only library, I decided to create two builds: an <strong>UMD (Universal Module Definition)</strong> build that you can use directly by importing the script or by using CDN, and another one as an <strong>ESM module.</strong></p>
<p>The UMD module is built with this configuration:</p>
<pre><code>{   <span class="hljs-attr">input</span>: <span class="hljs-string">'src/siriwave.js'</span>,   <span class="hljs-attr">output</span>: {      <span class="hljs-attr">file</span>: pkg.unpkg,      <span class="hljs-attr">name</span>: pkg.amdName,      <span class="hljs-attr">format</span>: <span class="hljs-string">'umd'</span>    },    <span class="hljs-attr">plugins</span>: [       resolve(),       commonjs(),       babel({ <span class="hljs-attr">exclude</span>: <span class="hljs-string">'node_modules/**'</span> }),    ]}
</code></pre><p>An additional <strong>minified UMD module</strong> is built with this configuration:</p>
<pre><code>{   <span class="hljs-attr">input</span>: <span class="hljs-string">'src/siriwave.js'</span>,   <span class="hljs-attr">output</span>: {      <span class="hljs-attr">file</span>: pkg.unpkg.replace(<span class="hljs-string">'.js'</span>, <span class="hljs-string">'.min.js'</span>),      <span class="hljs-attr">name</span>: pkg.amdName,      <span class="hljs-attr">format</span>: <span class="hljs-string">'umd'</span>    },    <span class="hljs-attr">plugins</span>: [       resolve(),       commonjs(),       babel({ <span class="hljs-attr">exclude</span>: <span class="hljs-string">'node_modules/**'</span> }),       uglify()]}
</code></pre><p>Benefiting of UnPKG service, you can find the final build on this URL served by a CDN: <a target="_blank" href="https://unpkg.com/siriwave/dist/siriwave.min.js">https://unpkg.com/siriwave/dist/siriwave.min.js</a></p>
<p>This is the “old style Javascript way” — you can just import your script and then refer in your code by using <strong>SiriWave</strong> global object.</p>
<p>To provide a more elegant and modern way, I also built an ESM module with this configuration:</p>
<pre><code>{    <span class="hljs-attr">input</span>: ‘src/siriwave.js’,   <span class="hljs-attr">output</span>: {       <span class="hljs-attr">file</span>: pkg.module,       <span class="hljs-attr">format</span>: ‘esm’   },    <span class="hljs-attr">plugins</span>: [       babel({ <span class="hljs-attr">exclude</span>: ‘node_modules<span class="hljs-comment">/**’ })   ]}</span>
</code></pre><p>We clearly don’t want the <strong>resolve</strong> or <strong>commonjs</strong> RollupJS plugins because the developer transplier will resolve dependencies for us.</p>
<p>You can find the final RollupJS configuration here: <a target="_blank" href="https://github.com/kopiro/siriwave/blob/master/rollup.config.js">https://github.com/kopiro/siriwave/blob/master/rollup.config.js</a></p>
<h4 id="heading-watch-and-hot-code-reload"><strong>Watch and Hot code reload</strong></h4>
<p>Using RollupJS, you can also take advantage of <strong>rollup-plugin-livereload</strong> and <strong>rollup-plugin-serve</strong> plugins to provide a better way to work on scripts.</p>
<p>Basically, you just add these plugins when you’re in “developer” mode:</p>
<pre><code><span class="hljs-keyword">import</span> livereload <span class="hljs-keyword">from</span> <span class="hljs-string">'rollup-plugin-livereload'</span>;<span class="hljs-keyword">import</span> serve <span class="hljs-keyword">from</span> <span class="hljs-string">'rollup-plugin-serve'</span>;
</code></pre><pre><code><span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">'production'</span>) { additional_plugins.push(  serve({   <span class="hljs-attr">open</span>: <span class="hljs-literal">true</span>,   <span class="hljs-attr">contentBase</span>: <span class="hljs-string">'.'</span>  }) ); additional_plugins.push(  livereload({   <span class="hljs-attr">watch</span>: <span class="hljs-string">'dist'</span>  }) );}
</code></pre><p>We finish by adding these lines into the <strong>package.json:</strong></p>
<pre><code><span class="hljs-string">"module"</span>: <span class="hljs-string">"dist/siriwave.m.js"</span>,<span class="hljs-string">"jsnext:main"</span>: <span class="hljs-string">"dist/siriwave.m.js"</span>,<span class="hljs-string">"unpkg"</span>: <span class="hljs-string">"dist/siriwave.js"</span>,<span class="hljs-string">"amdName"</span>: <span class="hljs-string">"SiriWave"</span>,<span class="hljs-string">"scripts"</span>: {   <span class="hljs-string">"build"</span>: <span class="hljs-string">"NODE_ENV=production rollup -c"</span>,   <span class="hljs-string">"dev"</span>: <span class="hljs-string">"rollup -c -w"</span>},
</code></pre><p>Let’s clarify some parameters:</p>
<ul>
<li><strong>module / jsnext:main:</strong> path of dist ESM module</li>
<li><strong>unpkg:</strong> path of dist UMD module</li>
<li><strong>amdName:</strong> name of the global object in UMD module</li>
</ul>
<p>Thanks a lot <strong>RollupJS!</strong></p>
<p>Hope that you find this article interesting, see you soon! ?</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
