<?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: Santiago</title>
    <description>The latest articles on DEV Community by Santiago (@woile).</description>
    <link>https://dev.to/woile</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%2F112908%2Fe42d2f40-5e5e-4545-a553-1fec9f19a55d.jpeg</url>
      <title>DEV Community: Santiago</title>
      <link>https://dev.to/woile</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/woile"/>
    <language>en</language>
    <item>
      <title>Secret management for the layman</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Sat, 16 Nov 2024 08:17:47 +0000</pubDate>
      <link>https://dev.to/woile/secret-management-for-the-layman-4d9p</link>
      <guid>https://dev.to/woile/secret-management-for-the-layman-4d9p</guid>
      <description>&lt;p&gt;For a long time, I've been debating myself how to properly handle secrets in a convenient, cheap and reproducible fashion.&lt;/p&gt;

&lt;p&gt;I run a small website: &lt;a href="https://www.reciperium.com" rel="noopener noreferrer"&gt;reciperium.com&lt;/a&gt; (check it out!) and I don't want to depend too much on the cloud.&lt;/p&gt;

&lt;p&gt;Most of the available tools have the following problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hard to setup&lt;/li&gt;
&lt;li&gt;Hard to integrate with your infra&lt;/li&gt;
&lt;li&gt;Hard to communicate / share with teammates (you can give access but they still have to discover the secrets, and build the files)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've developed a straightforward solution using &lt;code&gt;age&lt;/code&gt;, and &lt;code&gt;git&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secrets are stored as &lt;code&gt;.age&lt;/code&gt; files in the &lt;code&gt;git&lt;/code&gt; repo&lt;/li&gt;
&lt;li&gt;Supports multiple users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I call this workflow &lt;strong&gt;"tracked secrets"&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;First thing, prevent your private key from being leaked into git.&lt;/p&gt;

&lt;p&gt;For that we add to our &lt;code&gt;.gitignore&lt;/code&gt; the private keys:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If you use &lt;a href="https://github.com/DeterminateSystems/nix-installer" rel="noopener noreferrer"&gt;nix&lt;/a&gt;, you can set up a development environment with all the dependencies needed. In my case, I use &lt;code&gt;just&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt; for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nix"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"My Application"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github:NixOS/nixpkgs/nixos-unstable"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="err"&gt;å&lt;/span&gt;
  &lt;span class="nv"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;flake-parts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
    &lt;span class="nv"&gt;flake-parts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkFlake&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;inherit&lt;/span&gt; &lt;span class="nv"&gt;inputs&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="nv"&gt;systems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"x86_64-linux"&lt;/span&gt;
        &lt;span class="s2"&gt;"aarch64-darwin"&lt;/span&gt;
        &lt;span class="s2"&gt;"x86_64-darwin"&lt;/span&gt;
      &lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nv"&gt;perSystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="p"&gt;}:&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;devShells&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkShell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"reciperium"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nv"&gt;buildInputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
              &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;age&lt;/span&gt;
              &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;just&lt;/span&gt;
            &lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nv"&gt;shellHook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;''&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;              just --list&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;            ''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="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;You can also configure &lt;a href="https://direnv.net/" rel="noopener noreferrer"&gt;direnv&lt;/a&gt;, to load the nix dependencies, as soon as you &lt;code&gt;cd&lt;/code&gt; into the directory.&lt;br&gt;
This has been a powerful new method in my development toolkit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Interface
&lt;/h2&gt;

&lt;p&gt;The generic commands we are gonna define are the following&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="c"&gt;# Create new key and add it to the recipients&lt;/span&gt;
new-key

&lt;span class="c"&gt;# Decrypt ALL secrets&lt;/span&gt;
decrypt

&lt;span class="c"&gt;# Encrypt ALL secrets&lt;/span&gt;
encrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands can be implemented in a &lt;code&gt;Makefile&lt;/code&gt;, &lt;code&gt;justfile&lt;/code&gt;, bash scripts, or any scripting mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflows
&lt;/h2&gt;

&lt;p&gt;With those 3 commands we can support several different workflows:&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing my host
&lt;/h3&gt;

&lt;p&gt;The commands to be executed for this workflow should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;new-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should create a &lt;code&gt;me.key&lt;/code&gt; and populate &lt;code&gt;recipients.txt&lt;/code&gt; with the public key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If working on an existing repository, then I should create a commit, push the changes to git and ask to a colleague to encrypt the secrets again (after doing a pull)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Encrypting all the secrets
&lt;/h3&gt;

&lt;p&gt;The command to be executed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;encrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command can either encrypt everything necessary or it can be split into multiple commands internally.&lt;br&gt;
It should encrypt with all the recipients present in &lt;code&gt;recipients.txt&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Decrypting all secrets
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;decrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It should decrypt everything in the &lt;strong&gt;right&lt;/strong&gt; place. And the user is ready to work!&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating a secret for a CI
&lt;/h3&gt;

&lt;p&gt;One of the cool benefits of this approach, is that we can integrate it with our CI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;new-key github
encrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should generate a &lt;code&gt;github.key&lt;/code&gt;, and it should populate the &lt;code&gt;recipients.txt&lt;/code&gt;. You can upload the &lt;code&gt;github.key&lt;/code&gt; as a secret and your pipelines are ready to use it!&lt;/p&gt;

&lt;p&gt;The second command encrypts everything again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation example
&lt;/h2&gt;

&lt;p&gt;Let's say we have a repository with our infrastructure. It has 2 folders, one with terraform code. And another with a docker-compose, which gets deployed to the server using docker-swarm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;app
├── infra-tf
│   ├── main.tf
│   └── terraform.tfvars
└── stack
    ├── .env
    └── docker-compose.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secrets of our application are &lt;code&gt;terraform.tfvars&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As I said, I've been using &lt;code&gt;just&lt;/code&gt; for managing the commands, but you can use shell scripts or &lt;code&gt;make&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's take a look at the &lt;code&gt;justfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new private key and store public in recipients.txt
&lt;/span&gt;&lt;span class="nl"&gt;sec__new_key name="me"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"{{name}}.key"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; age-keygen &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"{{name}}.key"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; age-keygen &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="s2"&gt;"{{name}}.key"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; recipients.txt

&lt;span class="c"&gt;# Decrypt ALL secrets
&lt;/span&gt;&lt;span class="nl"&gt;sec__decrypt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    age &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; me.key stack/stack.env.tar.gz.age | &lt;span class="nb"&gt;tar &lt;/span&gt;xvz
    age &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; me.key infra-tf/infra-tf.tar.gz.age | &lt;span class="nb"&gt;tar &lt;/span&gt;xvz

&lt;span class="c"&gt;# Encrypt ALL secrets
&lt;/span&gt;&lt;span class="nl"&gt;sec__encrypt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_sec__encrypt__infra _sec__encrypt__stack&lt;/span&gt;

&lt;span class="c"&gt;# Encrypt terraform.tfvars
&lt;/span&gt;&lt;span class="nl"&gt;_sec__encrypt__infra&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;tar &lt;/span&gt;cvz &lt;span class="se"&gt;\&lt;/span&gt;
        infra-tf/terraform.tfvars | &lt;span class="se"&gt;\&lt;/span&gt;
        age &lt;span class="nt"&gt;-R&lt;/span&gt; recipients.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; infra-tf/infra-tf.tar.gz.age

&lt;span class="c"&gt;# Encrypt the stack environment files
&lt;/span&gt;&lt;span class="nl"&gt;_sec__encrypt__stack&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;tar &lt;/span&gt;cvz &lt;span class="se"&gt;\&lt;/span&gt;
        stack/.env &lt;span class="se"&gt;\&lt;/span&gt;
        age &lt;span class="nt"&gt;-R&lt;/span&gt; recipients.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; stack/stack.env.tar.gz.age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, let's recap. For creating a private key for your current host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just sec__new_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "new key" command is self-service, a user pulls the repo, runs the &lt;code&gt;just sec__new_key&lt;/code&gt;,&lt;br&gt;
and then they push. Another user, with access to the secrets, runs the encrypt again. And finally, the original&lt;br&gt;
user pulls the latest commits, so they can use decrypt locally.&lt;/p&gt;

&lt;p&gt;For encryption, we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just sec__encrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to decrypt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just sec__decrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we want to create a secret for our CI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just sec__encrypt github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also on-board other users, but it involves sending the private key to them, which can be cumbersome, the recommendation is to let people onboard themselves, and they are responsible for their private key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just sec__encrypt lara
just sec__encrypt jon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What to do with the private key?
&lt;/h2&gt;

&lt;p&gt;After running &lt;code&gt;just sec__new_key&lt;/code&gt;, we have a &lt;code&gt;me.key&lt;/code&gt;. You can store a copy in your secret manager.&lt;/p&gt;

&lt;p&gt;I personally use &lt;code&gt;gopass&lt;/code&gt;, but there are more options, e.g: &lt;code&gt;1password&lt;/code&gt;, &lt;code&gt;lastpass&lt;/code&gt; or &lt;code&gt;bitwarden&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential improvements
&lt;/h2&gt;

&lt;p&gt;How can we handle different environments?&lt;/p&gt;

&lt;p&gt;One option is to have a &lt;code&gt;secrets&lt;/code&gt; folder, with the different environments there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;secrets/
├── dev/
├── preview/
└── prod/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we could make just accept different parameters when calling the commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just sec__encrypt prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final comments
&lt;/h2&gt;

&lt;p&gt;Even though, I've seen a lot of people share their nixos configuration publicly, including their encrypted secrets, I still wonder if it's safe, and if so, why is it not used widely?&lt;br&gt;
I want to believe it's safe, and I know that if the secrets get leaked, I'll have to update them all.&lt;br&gt;
The plus side, is that you know where they are, and you can probably write comments on how to retrieve or generate them again, becaues it's just files.&lt;/p&gt;

&lt;p&gt;What do you think of this approach?&lt;/p&gt;

&lt;p&gt;Thanks for reading&lt;/p&gt;

</description>
      <category>secrets</category>
      <category>age</category>
      <category>encryption</category>
      <category>devops</category>
    </item>
    <item>
      <title>Digesting Make and Makefiles</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Sat, 12 Mar 2022 14:40:13 +0000</pubDate>
      <link>https://dev.to/woile/digesting-make-and-makefiles-394m</link>
      <guid>https://dev.to/woile/digesting-make-and-makefiles-394m</guid>
      <description>&lt;p&gt;Make and its makefiles, are a fantastic tool to keep track of the commands needed to build or run an application.&lt;/p&gt;

&lt;p&gt;Just create a &lt;code&gt;Makefile&lt;/code&gt; at the root of your project, start adding commands, and done... right? Not really.&lt;/p&gt;

&lt;p&gt;Let's explore a bit more what I mean, and then try to build a mental model that matches reality a bit better,&lt;br&gt;
closing with some magic you can do with Makefiles.&lt;/p&gt;

&lt;p&gt;Set up a practice field by running in the terminal:&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/practice
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp/practice
&lt;span class="nb"&gt;touch &lt;/span&gt;index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And write a minimal &lt;code&gt;Makefile&lt;/code&gt; with your favourite editor (E.g: &lt;code&gt;vim Makefile&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist
    &lt;span class="nb"&gt;cp &lt;/span&gt;index.html dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then execute in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a folder &lt;code&gt;dist&lt;/code&gt;, and copy &lt;code&gt;index.html&lt;/code&gt; into the folder &lt;code&gt;dist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is good. Particularly for me, it documents the commands used by the project, and helps future me.&lt;/p&gt;

&lt;p&gt;Let's refactor a bit, to show some extra functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist

&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dist&lt;/span&gt;
    &lt;span class="nb"&gt;cp &lt;/span&gt;index.html dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the &lt;code&gt;build: dist&lt;/code&gt;, it means: call &lt;code&gt;dist&lt;/code&gt; command &lt;em&gt;before&lt;/em&gt; running &lt;code&gt;build&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The functionality remains the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We created two commands: &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;dist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;dist&lt;/code&gt; is executed by the &lt;code&gt;build&lt;/code&gt; before running itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is ok, but it's not necessary a correct mental model.&lt;br&gt;
In the Makefile world, commands are not commands... but files.&lt;/p&gt;
&lt;h2&gt;
  
  
  New mental model
&lt;/h2&gt;

&lt;p&gt;In a nutshell, make builds a &lt;a href="https://en.wikipedia.org/wiki/Dependency_graph"&gt;dependency graph&lt;/a&gt; of files and folders.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build&lt;/code&gt; and &lt;code&gt;dist&lt;/code&gt; are actually &lt;strong&gt;target files&lt;/strong&gt; (or folders).&lt;/li&gt;
&lt;li&gt;doing &lt;code&gt;build: dist&lt;/code&gt; means that &lt;code&gt;build&lt;/code&gt; depends on &lt;code&gt;dist&lt;/code&gt; existing first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we had a file called &lt;code&gt;build&lt;/code&gt; , doing &lt;code&gt;make build&lt;/code&gt;, wouldn't execute anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch build
make build
$ make: `build' is up to date.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to actually treat &lt;code&gt;build&lt;/code&gt; as a command, we have to add &lt;code&gt;.PHONY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dist&lt;/span&gt;
    &lt;span class="nb"&gt;cp &lt;/span&gt;index.html dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way Make no longer sees &lt;code&gt;build&lt;/code&gt; as a file, but instead as a recipe, and it will be&lt;br&gt;
executed everytime.&lt;/p&gt;
&lt;h2&gt;
  
  
  Back to targets
&lt;/h2&gt;

&lt;p&gt;Remember what we said about targets and dependency graph? No? Me neither.&lt;br&gt;
Don't worry, I actually didn't say anything.&lt;/p&gt;

&lt;p&gt;If you treat your targets as &lt;strong&gt;files&lt;/strong&gt;, Make can keep track of the files that have&lt;br&gt;
changed, and update only those.&lt;/p&gt;

&lt;p&gt;By knowing this our previous example could be refactored into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist

&lt;span class="nl"&gt;dist/index.html&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dist&lt;/span&gt;
    &lt;span class="nb"&gt;cp &lt;/span&gt;index.html dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we tell Make to create our target file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run multiple times, we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make: `dist/index.html' is up to date.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would expect that by modifying &lt;code&gt;index.html&lt;/code&gt;, and running &lt;code&gt;make dist/index.html&lt;/code&gt;, it would be rebuilt,&lt;br&gt;
but we are getting the same message.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;We need to tell Make that it depends on another file: &lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist

&lt;span class="nl"&gt;dist/index.html&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dist index.html&lt;/span&gt;
    &lt;span class="nb"&gt;cp &lt;/span&gt;index.html dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, if &lt;code&gt;index.html&lt;/code&gt; is modified, &lt;code&gt;make dist/index.html&lt;/code&gt; will run again.&lt;br&gt;
Thus, when dependecies are updated, &lt;strong&gt;target files&lt;/strong&gt; are recreated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a3Kwl2p4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://woile.dev/images/makefile/make-targets-deps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a3Kwl2p4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://woile.dev/images/makefile/make-targets-deps.png" alt="Makefile targets and dependencies" width="880" height="331"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Patterns
&lt;/h2&gt;

&lt;p&gt;Now let's say we have many html files&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;touch &lt;/span&gt;about.html privacy.html docs.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we want to do the same for all the files, without creating many commands in Make.&lt;br&gt;
For this case we use a pattern (&lt;code&gt;%&lt;/code&gt;), and some Make variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$@&lt;/code&gt;: the target file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$&amp;lt;&lt;/code&gt;: the input file
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist

&lt;span class="nl"&gt;dist/%.html&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;%.html dist&lt;/span&gt;
    &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nv"&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 shell"&gt;&lt;code&gt;make dist/about.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And we would be explicitly telling Make which file to create.&lt;/p&gt;

&lt;p&gt;But what if we want to copy all the files at the same time?&lt;/p&gt;

&lt;p&gt;Our current implementation, doesn't know about the available files.&lt;br&gt;
And we are providing the &lt;code&gt;about&lt;/code&gt; to the &lt;code&gt;make dist/about.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have to find a way to "know" all the possible targets.&lt;/p&gt;
&lt;h2&gt;
  
  
  Variables
&lt;/h2&gt;

&lt;p&gt;We are gonna find the source files (&lt;code&gt;*.html&lt;/code&gt; files which are not in the &lt;code&gt;dist&lt;/code&gt; folder), store in a variable,&lt;br&gt;
and then use that information to create the target html files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SRC_HTMLS&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.html'&lt;/span&gt; &lt;span class="nt"&gt;-depth&lt;/span&gt; 1&lt;span class="nf"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;TARGET_HTMLS&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;SRC_HTMLS:./%.html&lt;span class="o"&gt;=&lt;/span&gt;dist/%.html&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(TARGET_HTMLS)&lt;/span&gt;
    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;info Done&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir &lt;/span&gt;dist

&lt;span class="nl"&gt;dist/%.html&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;%.html dist&lt;/span&gt;
    &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nv"&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 shell"&gt;&lt;code&gt;make build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build&lt;/code&gt; has all the &lt;code&gt;TARGET_HTMLS&lt;/code&gt; files as dependency&lt;/li&gt;
&lt;li&gt;Make also sees &lt;code&gt;dist/%.html&lt;/code&gt; and the pattern will fit the criteria for each &lt;code&gt;TARGET_HTMLS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;dist/%.html&lt;/code&gt; we have as dependency  the &lt;code&gt;%.html&lt;/code&gt;, so Make takes the pattern and checks if a &lt;code&gt;%.html&lt;/code&gt; file exist&lt;/li&gt;
&lt;li&gt;If the conditions are met, it runs the &lt;code&gt;cp&lt;/code&gt; command for each file, unless they are already present and not updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can think of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(TARGET_HTMLS)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dist/index.html dist/about.html dist/docs.html dist/privacy.html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables can be reference using &lt;code&gt;$()&lt;/code&gt; or &lt;code&gt;${}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also use &lt;code&gt;$(info Done)&lt;/code&gt; to send information messages to the user.&lt;br&gt;
Make also provides &lt;code&gt;$(warning text…)&lt;/code&gt; for warnings, and&lt;br&gt;
&lt;code&gt;$(error text...)&lt;/code&gt; to exit earlier with an error code different than 0.&lt;br&gt;
See &lt;a href="https://www.gnu.org/software/make/manual/html_node/Make-Control-Functions.html"&gt;Make-Control-Functions&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  One more time
&lt;/h2&gt;

&lt;p&gt;Let's start over by removing the &lt;code&gt;dist&lt;/code&gt; folder, and see what happens&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;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ make build
mkdir dist
cp index.html dist/index.html
cp about.html dist/about.html
cp docs.html dist/docs.html
cp privacy.html dist/privacy.html
Done

❯ make build
Done
make: Nothing to be done for `build'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, files that have not changed, won't be rebuilt by Make.&lt;/p&gt;

&lt;p&gt;Now, try using &lt;code&gt;touch&lt;/code&gt; on the different &lt;code&gt;html&lt;/code&gt; files and running &lt;code&gt;make build&lt;/code&gt; to see what happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  More functionality
&lt;/h2&gt;

&lt;p&gt;Make is a powerful tool, and provides much more functionality, so far with the web stack&lt;br&gt;
I haven't had the need for more complexity.&lt;/p&gt;

&lt;p&gt;I usually wrap docker commands, and make use of different variables, but if the need arises,&lt;br&gt;
make has extra functionality, life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;functions&lt;/li&gt;
&lt;li&gt;if/conditions&lt;/li&gt;
&lt;li&gt;change the shell in which the commands are executed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.delete_on_error&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;Make is usually a good way to keep track of a project's commands, as it's available in Unix systems,&lt;br&gt;
and you can be up and running fast.&lt;br&gt;
But by no means is perfect, it can sometimes be hard to read, or use.&lt;br&gt;
It's not available on Windows. And because it was designed for the C,C++ era, it plays well with files,&lt;br&gt;
but it doesn't mean it fits perfectly the web development paradigm, where you don't "transform" files much&lt;br&gt;
and where &lt;code&gt;docker&lt;/code&gt; is used a lot.&lt;/p&gt;

&lt;p&gt;So depending on your situation, there are some popular alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/casey/just"&gt;just&lt;/a&gt;: modern approach to make written in rust&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://earthly.dev/"&gt;earthly.dev&lt;/a&gt;: repeatable builds based on docker&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bazel.build/"&gt;bazel&lt;/a&gt;: build tool from Google&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/github/scripts-to-rule-them-all"&gt;scripts-to-rule-them-all&lt;/a&gt;: just use scripts, like &lt;a href="https://github.com/encode/starlette/tree/master/scripts"&gt;starlette&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/make/manual/html_node/"&gt;GNU Make Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://makefiletutorial.com/"&gt;Makefiletutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks for reading! 👋&lt;/p&gt;

&lt;p&gt;If you are interested in what I write, follow me on &lt;a href="https://twitter.com/santiwilly"&gt;twitter&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>unix</category>
      <category>gnu</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Layout Team</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Mon, 08 Nov 2021 22:14:16 +0000</pubDate>
      <link>https://dev.to/woile/the-layout-team-5b4m</link>
      <guid>https://dev.to/woile/the-layout-team-5b4m</guid>
      <description>&lt;p&gt;For the last couple of months I've had this idea spinning in my head, which I'm calling:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Layout Team&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Is a work in progress and I'll try to update it when new things come to my mind. The topic can be discussed forever, I will try to formalize the idea while keeping it short.&lt;/p&gt;

&lt;p&gt;I see how the frontend industry is led mostly by hype, and this time I'm not fond of the direction we are going, specifically with micro-frontends. This pattern, spite of its benefits, I don't think it can be implemented properly by most teams, and it's not an idea we should keep suggesting.&lt;/p&gt;

&lt;p&gt;Instead, I'm going to propose an alternative, mostly in the middle. And as you probably guessed... it's "The Layout Team".&lt;/p&gt;

&lt;p&gt;As far as I'm concerned, the ultimate goal of a frontend is to deliver a good user experience, and this includes being fast.&lt;/p&gt;

&lt;p&gt;Micro-frontends, make this target hard to achieve.&lt;br&gt;
If you pull parts from all around it will take longer than pulling from a single place. Of course some teams can accomplish this (out of the question), and they may need it, but most of the time, is not required, but... what do we do then?&lt;/p&gt;

&lt;p&gt;The main issue to me, is that a frontend application has to be &lt;strong&gt;glued together&lt;/strong&gt; at some point, or somewhere. Whether you use a micro-frontend architecture or a monorepo, the final user has to experience one cohesive app, this is &lt;strong&gt;different&lt;/strong&gt; to backends, there's no UI there, mostly machines talk with APIs. Your frontend talks with the API, but the human interacts with the frontend.&lt;/p&gt;

&lt;p&gt;Hence the introduction of &lt;strong&gt;"The Layout Team"&lt;/strong&gt; (I'm giving it a formal name).&lt;/p&gt;

&lt;p&gt;This team could have many different flavours. But ideally, it should be an independent team, holding ownership of the layout of the app.&lt;/p&gt;

&lt;p&gt;Yes, there's nothing fancy here, and the title is self-explanatory.&lt;/p&gt;

&lt;p&gt;The Layout Team maintains the layout, and checks that everyone operates inside the boundaries created by this team.&lt;/p&gt;

&lt;p&gt;Its responsibilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor styles to prevent overlapping components or breaking issues&lt;/li&gt;
&lt;li&gt;Review Pull Requests&lt;/li&gt;
&lt;li&gt;Train other developers, whether through quarterly presentations or one-to-one coaching, but
do it consistently over time. Not fire and forget.&lt;/li&gt;
&lt;li&gt;Maintain &lt;em&gt;some&lt;/em&gt; shared state (logged user or is_authenticated or any other herbs).
But most of the times teams should be able to add and manage their own global state&lt;/li&gt;
&lt;li&gt;Write tools to assist other teams, like linters to prevent CSS or JS&lt;/li&gt;
&lt;li&gt;Identify CSS or JS code that may affect the whole app, and potentially code them
into the linters. Example:

&lt;ul&gt;
&lt;li&gt;Do not use fixed/absolute because... (unless approved to do so)&lt;/li&gt;
&lt;li&gt;Do not use negative margins because we found that no one knows who to...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Write tests for the layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One easy way to do this, is by having a monorepo. The layout for the different pages is defined by "The Layout Team", and the rest of the teams write components, which can be later placed in the places designated by the layout team.&lt;/p&gt;

&lt;p&gt;By doing this, it becomes very easy to produce a small bundle. Because the dependencies are shared. It's then potentially easier, to identify shared code and cache it in a separate bundle across the application.&lt;/p&gt;

&lt;p&gt;One of the "benefits" of micro-frontend is supposed to be the freedom for teams to choose what framework to use, but you end up sending bigger assets to the end user.&lt;br&gt;
This goes against optimizing for the best user experience. So ideally, stick to a single framework, and deliver it once.&lt;/p&gt;

&lt;p&gt;If you are using React in your monorepo, it means everyone will stick to that version. If you have multiple repos, even if everyone uses the same framework, you may end up with different versions, or even the same and still delivering them as part of each apps bundle!&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;The Layout Team&lt;/strong&gt; leverages the use of &lt;code&gt;flex&lt;/code&gt; and &lt;code&gt;grid&lt;/code&gt; heavily.&lt;br&gt;
They shape the app over time. And create &lt;em&gt;slots&lt;/em&gt; for each team.&lt;/p&gt;

&lt;p&gt;Let's see an example:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"box grid grid-cols-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;maintainer=&lt;/span&gt;&lt;span class="s"&gt;"teamA"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ComponentFromTeamA/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;maintainer=&lt;/span&gt;&lt;span class="s"&gt;"teamB"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ComponentFromTeamB/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;maintainer=&lt;/span&gt;&lt;span class="s"&gt;"teamC"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ComponentFromTeamC/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoripego8qczue6wey0l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoripego8qczue6wey0l.png" alt="Image description"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;- Hey! It's almost the same example as a micro-frontend!&lt;/p&gt;

&lt;p&gt;- Well... yes, what did you expect?&lt;/p&gt;

&lt;p&gt;Each team now has a space to place their components, and there's full visibility over who maintains what.&lt;/p&gt;

&lt;p&gt;It is very important, that the people, that are part of this team, understand &lt;code&gt;flex&lt;/code&gt; and &lt;code&gt;grid&lt;/code&gt; very well.&lt;/p&gt;

&lt;p&gt;Useful layout resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" rel="noopener noreferrer"&gt;guide to flexbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://1linelayouts.glitch.me/" rel="noopener noreferrer"&gt;1linelayouts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://csslayout.io/" rel="noopener noreferrer"&gt;csslayout&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would very much like your feedback.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What has been your experience with micro-frontends?&lt;/li&gt;
&lt;li&gt;Do you think "the layout team" would work?&lt;/li&gt;
&lt;li&gt;What do you think of this proposal?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Changelog generation released for commitizen</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Mon, 04 May 2020 18:44:40 +0000</pubDate>
      <link>https://dev.to/woile/changelog-generation-released-for-commitizen-1b5k</link>
      <guid>https://dev.to/woile/changelog-generation-released-for-commitizen-1b5k</guid>
      <description>&lt;p&gt;After a lot of work, time and effort, we were able to release &lt;a href="https://github.com/commitizen-tools/commitizen"&gt;commitizen v1.19&lt;/a&gt; which includes &lt;strong&gt;automatic changelog generation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; commitizen
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this release the cycle is complete, commitizen now supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;custom commit rules&lt;/li&gt;
&lt;li&gt;automatic version bump based on the rules&lt;/li&gt;
&lt;li&gt;automatic changelog generation&lt;/li&gt;
&lt;li&gt;git hook to check that the commit is valid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default the system is using &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;conventional commits&lt;/a&gt; but you can come up with your own rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;For starters the configuration is straightforward, first, start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;cz init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It will prompt the user for information about the repo and based on that it will generate the &lt;code&gt;toml&lt;/code&gt; configuration file.&lt;/p&gt;

&lt;p&gt;Once that is done, after you've done some commits complying with the rules, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;cz bump &lt;span class="nt"&gt;--changelog&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;You can execute that command in your CI and then push the changes.&lt;/p&gt;

&lt;p&gt;For more in-depth explanations, check the &lt;a href="https://commitizen-tools.github.io/commitizen/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this tool helps you automate your systems and relief you of some repetitive tasks.&lt;/p&gt;

&lt;p&gt;Check &lt;a href="https://github.com/commitizen-tools/commitizen"&gt;commmitizen's github&lt;/a&gt; for some github actions, the repo is auto publishing docs, releases to pypi, testing, etc. &lt;/p&gt;

</description>
      <category>python</category>
      <category>semver</category>
      <category>changelog</category>
      <category>conventionalcommits</category>
    </item>
    <item>
      <title>Simplest React Hook component for PWA install button</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Tue, 24 Dec 2019 12:50:49 +0000</pubDate>
      <link>https://dev.to/woile/simplest-react-hook-component-for-pwa-install-button-2die</link>
      <guid>https://dev.to/woile/simplest-react-hook-component-for-pwa-install-button-2die</guid>
      <description>&lt;p&gt;This is the simplest snippet I could come up with to add a button which will prompt the user for the install pop up of your PWA.&lt;br&gt;
It doesn't use any redux, nor nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InstallPWA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;supportsPWA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSupportsPWA&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;promptInstall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPromptInstall&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&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;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;we are being triggered :D&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setSupportsPWA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setPromptInstall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeinstallprompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transitionend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&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;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;promptInstall&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="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;promptInstall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;supportsPWA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
      &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setup_button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Install app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Install app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Install&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;InstallPWA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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



&lt;p&gt;Any feedback is welcome.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>react</category>
      <category>hooks</category>
    </item>
    <item>
      <title>React folder structure</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Sun, 15 Dec 2019 11:03:14 +0000</pubDate>
      <link>https://dev.to/woile/react-folder-structure-lcl</link>
      <guid>https://dev.to/woile/react-folder-structure-lcl</guid>
      <description>&lt;p&gt;Hello people, I wanted to share my current folder structure for my React projects, after some time this is it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── package.json
├── jsconfig.json
├── public/
└── src/
    ├── assets/
    ├── components/
    └── pages/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;components&lt;/code&gt;: Any component that don't belong to the pages should live here.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages&lt;/code&gt;: Components living in this folder should map to a url. This is useful because if you want to move to Next.JS, there's not much needed to be done. This folder can have sub folders, if you are using &lt;code&gt;reach-router&lt;/code&gt;, it fits perfectly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;assets&lt;/code&gt;: This folder is &lt;strong&gt;optional&lt;/strong&gt;, it may include things as images, or any other static file that you'd like to put there, depending on the size of the app, the static content can also live next to each component, so it's not that needed.&lt;/p&gt;

&lt;p&gt;And the &lt;code&gt;jsconfig.json&lt;/code&gt; can have this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pages"&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="s2"&gt;"./src/pages/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cards"&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="s2"&gt;"./src/cards/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"components"&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="s2"&gt;"./src/components/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&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="s2"&gt;"node_modules"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib"&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;So my question is, what do you think? Would you change it to something different?&lt;/p&gt;

&lt;p&gt;Cheers&lt;/p&gt;

</description>
      <category>react</category>
      <category>boilerplate</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Question: how to create sass/css packages</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Fri, 15 Nov 2019 09:03:45 +0000</pubDate>
      <link>https://dev.to/woile/question-how-to-create-sass-css-packages-2h2e</link>
      <guid>https://dev.to/woile/question-how-to-create-sass-css-packages-2h2e</guid>
      <description>&lt;p&gt;Hello people! I'd like to create a sass packages and I'd like to hear which tools do you use to manage, publish, etc.&lt;/p&gt;

&lt;p&gt;I've realized that for the creation of JS packages, there's ton of documentation, but I haven't found much info on sass, css.&lt;/p&gt;

&lt;p&gt;I don't really want to maintain webpack scripts, so I'm looking for some already pre-cooked libraries or skeletons.&lt;/p&gt;

&lt;p&gt;Some questions I can think of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which tools do you use to create bundles? (webpack, parcel?, etc)&lt;/li&gt;
&lt;li&gt;How do you publish? is there something to keep in mind?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>sass</category>
      <category>packages</category>
      <category>npm</category>
      <category>css</category>
    </item>
    <item>
      <title>Libraries for functional webcomponents?</title>
      <dc:creator>Santiago</dc:creator>
      <pubDate>Tue, 29 Oct 2019 08:52:08 +0000</pubDate>
      <link>https://dev.to/woile/libraries-for-functional-webcomponents-3bak</link>
      <guid>https://dev.to/woile/libraries-for-functional-webcomponents-3bak</guid>
      <description>&lt;p&gt;Hello people, I would like to open a discussion over functional webcomponents, do you know any? I really like the idea of React Hooks, and I enjoy them a lot. The documentation of webcomponents uses mostly classes. For external reasons I have to use webcomponents, I was wondering if people know of any good functional webcomponent package. &lt;br&gt;
So far I've found &lt;a href="https://github.com/hybridsjs/hybrids"&gt;hybrids&lt;/a&gt; but I have no references about it.&lt;/p&gt;

&lt;p&gt;Some questions I'm thinking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What do you think of webcomponents? &lt;/li&gt;
&lt;li&gt;Would you like functional webcomponents?&lt;/li&gt;
&lt;li&gt;Do you know any functional wc package?&lt;/li&gt;
&lt;li&gt;Have you used any of them?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Regards and happy coding!&lt;/p&gt;

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