<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Camille Hodoul</title>
    <description>The latest articles on DEV Community by Camille Hodoul (@camillehdl).</description>
    <link>https://dev.to/camillehdl</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%2F183437%2Fd9a82d8e-d11c-4a70-adff-823827996b34.png</url>
      <title>DEV Community: Camille Hodoul</title>
      <link>https://dev.to/camillehdl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/camillehdl"/>
    <language>en</language>
    <item>
      <title>Illustrate your comments</title>
      <dc:creator>Camille Hodoul</dc:creator>
      <pubDate>Fri, 07 Jul 2023 12:56:48 +0000</pubDate>
      <link>https://dev.to/camillehdl/illustrate-your-comments-jjn</link>
      <guid>https://dev.to/camillehdl/illustrate-your-comments-jjn</guid>
      <description>&lt;p&gt;I remember the day structural sharing in data structures "clicked" for me. It was illustrated by a drawing of boxes and arrows.&lt;/p&gt;

&lt;p&gt;An image is a powerful way to communicate relationships between objects, distance, size, time, all of which are relevant in a program.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HzmcNGUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hluhee1va5b2x9wskkha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HzmcNGUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hluhee1va5b2x9wskkha.png" alt="Unflattening, Nick Sousanis" title="In “Unflattening”, Nick Sousanis illustrates how shape, distance, repetition, separation, negative space and other visual tools can communicate relationships." width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comments in code are communication tools: they explain an abstraction, an implementation, or give context to complex technical problems. They are the documentation closest to the code, where we need it most.  &lt;/p&gt;

&lt;p&gt;We should use images in comments more often.   &lt;/p&gt;

&lt;p&gt;We should not, however, lose the convenience of plain text: it can be checked in version control, shows up in diffs and works out-of-the-box in any text editor.&lt;br&gt;&lt;br&gt;
Nor should we entirely remove sentences, because phrases can be searched for in a search engine and can be read by accessibility tools or people who don't like visual communication.&lt;/p&gt;

&lt;p&gt;Text-based diagrams are, to me, a good compromise. Look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
            No data duplication

┌───────────┐                 ┌───────────┐
│ Version A │                 │ Version B │
└───────────┘                 └───────────┘
      │                             │
      ├─────────────┬───────────────┘
      │             │
┌─────▼────┐  ┌─────▼────┐
│ Data A 1 │  │ Data A 2 │
└──────────┘  └──────────┘
              ──────────────
           With data duplication

┌───────────┐                 ┌───────────┐
│ Version A │                 │ Version B │
└───────────┘                 └───────────┘
      │                             │
      ├─────────────┐               ├─────────────┐
      │             │               │             │
┌─────▼────┐  ┌─────▼────┐    ┌─────▼────┐  ┌─────▼────┐
│ Data A 1 │  │ Data A 2 │    │ Data B 1 │  │ Data B 2 │
└──────────┘  └──────────┘    └──────────┘  └──────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I generated this diagram with &lt;a href="https://monodraw.helftone.com"&gt;monodraw&lt;/a&gt; a paid (but not expensive) macos app, which can export text-based drawings with options to easily paste into common comment formats.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8u364jIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otaaomm70ya8gdevds7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8u364jIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otaaomm70ya8gdevds7j.png" alt="Monodraw text export menu" title="A list of common comment formats in the monodraw export menu." width="392" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Communicating ideas with pictures seems to be obvious everywhere, from art to education and marketing. Why not use it in comments?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Meaning is thus conveyed not only by what's depicted, but through structure:&lt;br&gt;
the size, shape, placement, and relationship of components - what they're next to, and what they're not, matters.&lt;br&gt;
&lt;cite&gt;&lt;u&gt;Unflattening&lt;/u&gt;, Nick Sousanis&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://camillehdl.dev/illustrate-your-comments/"&gt;Original article on my blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>programming</category>
    </item>
    <item>
      <title>Update to the latest version of many npm dependencies at once</title>
      <dc:creator>Camille Hodoul</dc:creator>
      <pubDate>Mon, 17 May 2021 08:49:22 +0000</pubDate>
      <link>https://dev.to/camillehdl/update-to-the-latest-version-of-many-npm-dependencies-at-once-2gmp</link>
      <guid>https://dev.to/camillehdl/update-to-the-latest-version-of-many-npm-dependencies-at-once-2gmp</guid>
      <description>&lt;p&gt;I couldn't find a &lt;code&gt;npm&lt;/code&gt; command to update a subset of my dependencies to their latest version based on a name pattern, so here's a one-liner to do it with pipes and &lt;code&gt;awk&lt;/code&gt; (to be modified for your needs).  &lt;/p&gt;

&lt;p&gt;In this example, I want to update all the dependencies containing the string "babel".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm outdated |awk &lt;span class="s1"&gt;'BEGIN{OFS="@"} $1 ~ /babel/ { print $1, "latest" }'&lt;/span&gt;| xargs npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Explanation of each command
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;npm outdated&lt;/code&gt; lists your outdated dependencies.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;awk&lt;/code&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BEGIN{OFS="@"}&lt;/code&gt; sets &lt;code&gt;@&lt;/code&gt; as the output field separator (will be used by &lt;code&gt;print&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$1 ~ /babel/&lt;/code&gt; will match the lines containing "babel" in their first column&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ print $1, "latest" }&lt;/code&gt; will output each selected lines concatenated with "latest" (using "@" as the &lt;code&gt;OFS&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;xargs npm install&lt;/code&gt; will give the output of &lt;code&gt;awk&lt;/code&gt; as input arguments to &lt;code&gt;npm install&lt;/code&gt;, like so : &lt;code&gt;npm install dependency1@latest dependency2@latest ...&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tweak it
&lt;/h1&gt;

&lt;p&gt;The beauty of the command line: you could tweak this for different dependency managers, such as Composer for PHP.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>awk</category>
      <category>npm</category>
      <category>shell</category>
    </item>
    <item>
      <title>Ship modern JavaScript with Rollup</title>
      <dc:creator>Camille Hodoul</dc:creator>
      <pubDate>Sat, 23 Jan 2021 11:22:15 +0000</pubDate>
      <link>https://dev.to/camillehdl/ship-modern-javascript-with-rollup-2e8a</link>
      <guid>https://dev.to/camillehdl/ship-modern-javascript-with-rollup-2e8a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This &lt;a href="https://camillehdl.dev/ship-modern-javascript-rollup/"&gt;post&lt;/a&gt; is a few months old, but it still gets a few hits on my blog everyday so maybe it can help people.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using ES2017 (and newer) syntax in our codebase is one thing, sending it to our users is another.  &lt;/p&gt;

&lt;p&gt;Chances are, if we have to support IE11 and/or use &lt;code&gt;@babel/preset-env&lt;/code&gt; and/or ship a single bundle (even with code-splitting), we're probably sending ES5 to everybody, even if their browser is perfectly capable of understanding &lt;a href="https://caniuse.com/#feat=es6-class"&gt;classes&lt;/a&gt; or &lt;a href="https://caniuse.com/#feat=mdn-javascript_operators_await"&gt;async/await&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;This is suboptimal, because &lt;strong&gt;we're sending more code than needed&lt;/strong&gt; and, long term, &lt;strong&gt;we'll miss out on some "free" performance gains&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can read more about the peformance of ES6 features compared to their ES5 transpiled versions on the &lt;a href="http://incaseofstairs.com/six-speed/"&gt;Six Speed project&lt;/a&gt;. The status quo isn't set in stone, as browser vendors regularly improve the performance of new syntax (see &lt;a href="https://v8.dev/blog/high-performance-es2015"&gt;this&lt;/a&gt; and &lt;a href="https://v8.dev/blog/spread-elements"&gt;this&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Moreover, even if all our &lt;code&gt;preset-env&lt;/code&gt; targets are up-to-date, Babel &lt;a href="https://podcast.babeljs.io/preset-env/"&gt;may still be transpiling some syntax because of edge-cases&lt;/a&gt;. Besides, our dependencies are probably transpiled to ES5 anyway.&lt;/p&gt;

&lt;p&gt;A better thing to do would be to &lt;strong&gt;ship transpiled ES5 to legacy browsers&lt;/strong&gt; and &lt;strong&gt;as much ES2017 as possible to modern browsers&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;The steps we need to take to achieve this are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create 2 distinct bundles

&lt;ol&gt;
&lt;li&gt;use &lt;code&gt;preset-modules&lt;/code&gt; instead of &lt;code&gt;preset-env&lt;/code&gt; for our modern build,&lt;/li&gt;
&lt;li&gt;configure terser to output ES2017&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;load each bundle in the correct browsers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can see a working example &lt;a href="https://github.com/camille-hdl/rollup-react-example"&gt;in this repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bundling
&lt;/h2&gt;

&lt;p&gt;If you're using Rollup, you can already output ES modules or a fallback out-of-the-box.&lt;br&gt;&lt;br&gt;
To create each build with a different config however, we have to add a bit of configuration.  &lt;/p&gt;

&lt;p&gt;One way to do this could be to use an environment variable &lt;code&gt;ROLLUP_BUILD_TYPE&lt;/code&gt;, in npm scripts.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rollup and Terser configuration
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// package.json&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/** ... **/&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm-run-all --parallel &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;build:*&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build:legacy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env ROLLUP_BUILD_TYPE=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;legacy&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; rollup -c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build:modern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env ROLLUP_BUILD_TYPE=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;modern&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; rollup -c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;devDependencies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm-run-all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rollup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="cm"&gt;/** ... **/&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// rollup.config.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ROLLUP_BUILD_TYPE&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ROLLUP_BUILD_TYPE&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/index.jsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;buildType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/public/js/system/`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/public/js/esm/`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;esm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="cm"&gt;/** ... **/&lt;/span&gt;
            &lt;span class="nx"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="cm"&gt;/**
                * Uncomment to ignore node_modules. This will accelerate yur build,
                * but prevent you from using modern syntax in your dependencies
                */&lt;/span&gt;
                &lt;span class="c1"&gt;// exclude: "node_modules/**"&lt;/span&gt;
            &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="nx"&gt;terser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;collapse_vars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;ecma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;buildType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;legacy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2017&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;safari10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="cm"&gt;/** ... **/&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice how &lt;strong&gt;we didn't exclude node_modules/&lt;/strong&gt; from Babel. This will let us optimally transpile our dependencies if they export modern syntax. More on that later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/terser/terser"&gt;Terser&lt;/a&gt; is a minifier which needs to be told which version of the language we are using. &lt;/p&gt;
&lt;h3&gt;
  
  
  Babel configuration
&lt;/h3&gt;

&lt;p&gt;Babel 7 can be configured with a function instead of a static object. We can take advantage of this feature in order to write conditional and annotated code.&lt;/p&gt;

&lt;p&gt;Remember that our goal is to transpile as little as possible. In this example, I include a preset for react as well as plugins for &lt;a href="https://tc39.es/ecma262/2020/"&gt;ES2020 features&lt;/a&gt;, that will still be used for a while even in modern browsers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in babel.config.cjs&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ROLLUP_BUILD_TYPE&lt;/span&gt;
    &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ROLLUP_BUILD_TYPE&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Will be used for the legacy build
     */&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presetEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;browsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;0.25%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not op_mini all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Will be used for the modern build
     */&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presetModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-modules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;loose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alwaysUsedPresets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alwaysUsedPlugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-syntax-dynamic-import&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-proposal-optional-chaining&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-proposal-nullish-coalescing-operator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Only loaded in the legacy build
     */&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;legacyPlugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/plugin-proposal-object-rest-spread&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productionConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nx"&gt;modern&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="cm"&gt;/**
                   * Modern build
                   */&lt;/span&gt;
                  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="nx"&gt;presetModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPresets&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPlugins&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="cm"&gt;/**
                   * Legacy build
                   */&lt;/span&gt;
                  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="nx"&gt;presetEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPresets&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPlugins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;legacyPlugins&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;developmentConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nx"&gt;modern&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="cm"&gt;/**
                   * Modern build
                   */&lt;/span&gt;
                  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="nx"&gt;presetModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPresets&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPlugins&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="cm"&gt;/**
                   * Legacy build
                   */&lt;/span&gt;
                  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="nx"&gt;presetEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPresets&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPlugins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;legacyPlugins&lt;/span&gt;
                      &lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;productionConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;developmentConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="cm"&gt;/**
                 * Chances are tests will run in node
                **/&lt;/span&gt;
                &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPresets&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;alwaysUsedPlugins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;legacyPlugins&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We didn't use the .mjs alternative because it only works when babel is loaded asynchonously.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;preset-modules&lt;/code&gt; will transpile less code than &lt;code&gt;preset-env&lt;/code&gt;. Read &lt;a href="https://github.com/babel/preset-modules"&gt;the documentation&lt;/a&gt; to understand why.&lt;/p&gt;

&lt;p&gt;Now that we have our bundles, we need a way to load them in their targets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The module/nomodule pattern
&lt;/h2&gt;

&lt;p&gt;This technique (from &lt;a href="https://philipwalton.com/articles/deploying-es2015-code-in-production-today/"&gt;2017&lt;/a&gt;) utilizes &lt;code&gt;&amp;lt;script type="module"&amp;gt;&lt;/code&gt; support as a breakpoint between legacy browsers (mostly IE nowadays) and "evergreen" browsers (Chrome, Firefox, Safari, Edge, ...).&lt;br&gt;&lt;br&gt;
This gives us a way to send a modern bundle to modern browsers, and a legacy bundle to old browsers.  &lt;/p&gt;

&lt;p&gt;For a long time, things weren't as simple as &lt;a href="https://dev.to/dynamic-import-esm-fallback"&gt;some browsers did support modules, but didn't support &lt;code&gt;import()&lt;/code&gt;&lt;/a&gt;. This has now been delt wih though, and &lt;code&gt;&amp;lt;script type="module"&amp;gt;&lt;/code&gt; can be safely used.&lt;/p&gt;

&lt;p&gt;The pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/js/esm/main.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/** ... **/&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;nomodule&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/legacy/main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The future
&lt;/h2&gt;

&lt;p&gt;While this post is about ES2017, the techniques explained here can be updated later to use newer versions of the language, as long as browser support keeps up.&lt;br&gt;&lt;br&gt;
One important limitation to note is that most third-party libraries still &lt;a href="https://podcast.babeljs.io/dependencies/"&gt;don't export untranspiled code&lt;/a&gt;. Unfortunately, this means the majority of the code you ship will still be ES5 for now.&lt;br&gt;&lt;br&gt;
However, if you stop excluding node_modules/ from your Babel config, and more people do the same, things might improve soon enough.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>rollup</category>
      <category>es2017</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Pre-commit, pre-push or pre-merge ?</title>
      <dc:creator>Camille Hodoul</dc:creator>
      <pubDate>Mon, 23 Nov 2020 07:03:19 +0000</pubDate>
      <link>https://dev.to/camillehdl/pre-commit-pre-push-or-pre-merge-8i9</link>
      <guid>https://dev.to/camillehdl/pre-commit-pre-push-or-pre-merge-8i9</guid>
      <description>&lt;p&gt;On my codebases, I may want to run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a linter,&lt;/li&gt;
&lt;li&gt;static analysis,&lt;/li&gt;
&lt;li&gt;tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While I can run them manually, I find it easier for everyone involved if it happens on its own.&lt;/p&gt;

&lt;p&gt;It's about &lt;strong&gt;getting feedback as soon as possible without breaking the flow of work&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When and where should they run?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;on save: runs every time I save a file on disk,&lt;/li&gt;
&lt;li&gt;pre-commit: runs before I commit my changes,&lt;/li&gt;
&lt;li&gt;pre-push: runs before I push mu changes to a remote,&lt;/li&gt;
&lt;li&gt;pre-merge: runs on CI when I do a merge request (or "pull-request").&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;th&gt;How often&lt;/th&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;on save&lt;/td&gt;
&lt;td&gt;very early&lt;/td&gt;
&lt;td&gt;very often&lt;/td&gt;
&lt;td&gt;locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pre-commit&lt;/td&gt;
&lt;td&gt;early&lt;/td&gt;
&lt;td&gt;often&lt;/td&gt;
&lt;td&gt;locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pre-push&lt;/td&gt;
&lt;td&gt;late&lt;/td&gt;
&lt;td&gt;sometimes&lt;/td&gt;
&lt;td&gt;locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pre-merge&lt;/td&gt;
&lt;td&gt;later&lt;/td&gt;
&lt;td&gt;rarely&lt;/td&gt;
&lt;td&gt;CI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My advice is that the correct answer for a given task will depend on the "lost" time &lt;a href="https://en.wikipedia.org/wiki/Time_perception"&gt;perceived&lt;/a&gt; by the developer. Perceived lost time ~= runtime + time to correct the code, if the task is blocking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The slower the task, the later and less often it should run.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If something &lt;em&gt;feels&lt;/em&gt; slow, it will get in the way and people (me included) &lt;em&gt;will&lt;/em&gt; work around it.&lt;br&gt;&lt;br&gt;
If I have to wait a long time before knowing if my tests pass or not, I probably will switch to another task and waste time.&lt;br&gt;&lt;br&gt;
If the task itself can correct the code instead of rejecting the commit (e.g. linters), make it so.&lt;/p&gt;

&lt;p&gt;Here is my rule of thumb, to be adapted to your needs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Earliest it can run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;less than 100 milliseconds&lt;/td&gt;
&lt;td&gt;on save&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;less than 3 seconds&lt;/td&gt;
&lt;td&gt;pre-commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;less than 10 seconds&lt;/td&gt;
&lt;td&gt;pre-push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;above 10 seconds&lt;/td&gt;
&lt;td&gt;pre-merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;above 5 minutes&lt;/td&gt;
&lt;td&gt;split into sub-tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Fine-tuning
&lt;/h2&gt;

&lt;p&gt;To state the obvious: every team, every codebase, every workflow is different. What works for one won't necessarily work for others.&lt;/p&gt;

&lt;p&gt;The tools we use give us even more options to choose when to run what, according to our preferences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IDE Integrations,&lt;/li&gt;
&lt;li&gt;manual or conditional tasks on CI,&lt;/li&gt;
&lt;li&gt;third party tools integrating with our version control system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, I choose to run linters on pre-commit, not on save, even if it's fast, because I find it distracting to have code jumping around on the screen.&lt;/p&gt;

&lt;p&gt;I run unit tests pre-merge but trigger end-to-end tests manually because they are very slow, and would delay feedback too much.&lt;/p&gt;

&lt;p&gt;Experiment and gather feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  External links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pre-commit.com"&gt;pre-commit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks"&gt;Documentation on git hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.atlassian.com/bitbucket-cloud/docs/get-started-with-bitbucket-pipelines/"&gt;bitbucket pipelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tooling</category>
      <category>testing</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Bitbucket Pipeline for PHP, MySQL &amp; Elasticsearch</title>
      <dc:creator>Camille Hodoul</dc:creator>
      <pubDate>Sun, 21 Jul 2019 10:58:19 +0000</pubDate>
      <link>https://dev.to/camillehdl/bitbucket-pipeline-for-php-mysql-elasticsearch-6n1</link>
      <guid>https://dev.to/camillehdl/bitbucket-pipeline-for-php-mysql-elasticsearch-6n1</guid>
      <description>&lt;p&gt;If your application has dependencies that are not covered by Bitbucket Pipelines &lt;a href="https://confluence.atlassian.com/bitbucket/use-services-and-databases-in-bitbucket-pipelines-874786688.html" rel="noopener noreferrer"&gt;built-in services&lt;/a&gt;, or these dependencies are more complex that simply checking that a container is running, &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt; can be a helpful tool.  &lt;/p&gt;

&lt;p&gt;In my case, I want to setup CI on a Symfony + MySQL + Elasticsearch (which is not available as a pipeline service) application. I just want to run phpunit tests, so I don't need an HTTP server. The dependencies are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MySQL has no dependencies,&lt;/li&gt;
&lt;li&gt;Elasticsearch has no dependencies,&lt;/li&gt;
&lt;li&gt;PHP depends on MySQL and Elasticsearch for bootstraping and running tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These look pretty straightforward and can be expressed in docker-compose. However as always, the devil is in the details: not only should the Elasticsearch container be up, the service should be &lt;strong&gt;ready&lt;/strong&gt; for the tests to run correctly.&lt;/p&gt;

&lt;p&gt;Pipelines use docker containers to run our application and let us use whatever image we need. We will use this to our advantage and use &lt;a href="https://github.com/tiangolo/docker-with-compose" rel="noopener noreferrer"&gt;an image&lt;/a&gt; with docker-compose available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Folder structure
&lt;/h2&gt;

&lt;p&gt;We will create a &lt;code&gt;ci/&lt;/code&gt; folder which will contain the files we will use in our CI environment.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feft9lwhfqqrlx87i3qlp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feft9lwhfqqrlx87i3qlp.png" alt="Folder structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;.env.ci&lt;/em&gt; contains environment variables if you use DotEnv&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;phpunit.xml&lt;/em&gt; contains configuration for phpunit&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;php-ini-overrides.ini&lt;/em&gt; is self-explanatory&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;docker-compose.yml&lt;/em&gt; describes the containers we need&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;setup-and-test.sh&lt;/em&gt; will bootstrap our application and run tests against it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  docker-compose.yml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.1"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:5.7&lt;/span&gt;
      &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-db-server&lt;/span&gt;
      &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/application&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../:/application&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=root&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_DATABASE=my-db&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8002:3306"&lt;/span&gt;

    &lt;span class="na"&gt;elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/elasticsearch/elasticsearch:6.8.1&lt;/span&gt;
      &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elasticsearch&lt;/span&gt;
      &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/application&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;xpack.security.enabled=false&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transport.host=localhost"&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bootstrap.system_call_filter=false"&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../:/application&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9200:9200"&lt;/span&gt;
      &lt;span class="na"&gt;tty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="na"&gt;php-fpm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chodoul1egal2/php72-mysql&lt;/span&gt;
      &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/application&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../:/application&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini&lt;/span&gt;
      &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;elasticsearch&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;A few things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://hub.docker.com/r/chodoul1egal2/php72-mysql" rel="noopener noreferrer"&gt;docker image I use for php-fpm&lt;/a&gt; is a custom one which includes the modules I need for my application (notably php-mysql). &lt;a href="https://phpdocker.io/" rel="noopener noreferrer"&gt;You might need a different one&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;No volumes are needed as nothing needs to be persisted in a CI context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  setup-and-test.sh
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Make sure CI stops as soon as something wrong happens&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt;

&lt;span class="c"&gt;# Inspiration for this script:&lt;/span&gt;
&lt;span class="c"&gt;# https://github.com/elastic/elasticsearch-py/issues/778#issuecomment-384389668&lt;/span&gt;

&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://elasticsearch:9200"&lt;/span&gt;


&lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;--output&lt;/span&gt; /dev/null &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--head&lt;/span&gt; &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;
    &lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Wait for ES to be available&lt;/span&gt;
&lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;--write-out&lt;/span&gt; %&lt;span class="o"&gt;{&lt;/span&gt;http_code&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; /dev/null &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Elasticsearch is unavailable - sleeping"&lt;/span&gt;
    &lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done&lt;/span&gt;


&lt;span class="c"&gt;# Wait for ES to be ready&lt;/span&gt;
&lt;span class="nv"&gt;health&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;/_cat/health?h=status"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;health&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$health&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'s/^[[:space:]]+|[[:space:]]+$//g'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$health&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'green'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;health&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;/_cat/health?h=status"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;health&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$health&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'s/^[[:space:]]+|[[:space:]]+$//g'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Elasticsearch is unavailable - sleeping"&lt;/span&gt;
    &lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ES is up"&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
composer &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-interaction&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"bootstrapping"&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# YOUR BOOTSTRAPPING LOGIC HERE&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;

&lt;span class="c"&gt;# php bin/console ...&lt;/span&gt;
&lt;span class="c"&gt;# php bin/console fos:elastica:populate&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"done"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"tests"&lt;/span&gt;
vendor/bin/simple-phpunit &lt;span class="nt"&gt;--stop-on-failure&lt;/span&gt; 
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"over"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pipelines configuration
&lt;/h2&gt;

&lt;p&gt;Finally, the bitbucket-pipelines.yml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tiangolo/docker-with-compose&lt;/span&gt;

&lt;span class="na"&gt;definitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2048&lt;/span&gt;

&lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2x&lt;/span&gt;
        &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
        &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cp ci/.env.ci ./.env&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cp ci/phpunit.ci ./phpunit.xml&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose -f ci/docker-compose.yml up -d &amp;amp;&amp;amp; sleep &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose -f ci/docker-compose.yml exec -T php-fpm ci/setup-and-test.sh&lt;/span&gt; 
        &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;sleep 5&lt;/code&gt; is an ugly hack to avoid timing problems related to the &lt;code&gt;- d&lt;/code&gt; flag on &lt;code&gt;docker-compose&lt;/code&gt;. Removing &lt;code&gt;-d&lt;/code&gt; implies having a lot of noise in your pipeline logs. If you have a better solution, please share!&lt;/li&gt;
&lt;li&gt;Elasticsearch will use a lot memory, so we use &lt;code&gt;size: 2x&lt;/code&gt; and give the &lt;code&gt;docker&lt;/code&gt; service enough memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have ideas to improve this, I would love to hear about it!&lt;/p&gt;




&lt;p&gt;This was originally posted &lt;a href="https://camillehdl.dev/bitbucket-php-elasticsearch-mysql-docker/" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ci</category>
      <category>elasticsearch</category>
      <category>bitbucket</category>
      <category>docker</category>
    </item>
    <item>
      <title>UTF-8 csv fix for Excel</title>
      <dc:creator>Camille Hodoul</dc:creator>
      <pubDate>Tue, 16 Jul 2019 20:36:48 +0000</pubDate>
      <link>https://dev.to/camillehdl/utf-8-csv-fix-for-excel-3m2h</link>
      <guid>https://dev.to/camillehdl/utf-8-csv-fix-for-excel-3m2h</guid>
      <description>&lt;p&gt;Using &lt;em&gt;utf-8&lt;/em&gt; for your CSV files sounds obvious and works well in most software processing them.&lt;br&gt;&lt;br&gt;
Most software except Micrososft's Excel, which, considering its number of users, can sadden your day.&lt;/p&gt;

&lt;p&gt;Excel seems to assume &lt;em&gt;windows-1252&lt;/em&gt; &lt;strong&gt;unless a &lt;a href="https://en.wikipedia.org/wiki/Byte_order_mark"&gt;Byte order mark&lt;/a&gt; is provided&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To fix this without asking your users to navigate a maze of hidden menus, you can add a BOM to a string before saving it to a file or triggering a download.&lt;/p&gt;

&lt;p&gt;In JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;csvString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a,b,c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1,2,3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;csvString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;ufeff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;csvString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or in PHP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$csvString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"a,b,c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"1,2,3"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$csvString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xEF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xBB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xBF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$csvString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at the hex dump, you can check for the presence of this byte sequence at the very beginning: &lt;code&gt;EF BB BF&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>unicode</category>
      <category>excel</category>
      <category>php</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
