<?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: Mikhail 🐺</title>
    <description>The latest articles on DEV Community by Mikhail 🐺 (@_mikhailbot).</description>
    <link>https://dev.to/_mikhailbot</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%2F92268%2Fffff8b7f-1627-488f-a31c-3fc544466116.jpg</url>
      <title>DEV Community: Mikhail 🐺</title>
      <link>https://dev.to/_mikhailbot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_mikhailbot"/>
    <language>en</language>
    <item>
      <title>Adding Browser Sync to Laravel and Docker with Vessel</title>
      <dc:creator>Mikhail 🐺</dc:creator>
      <pubDate>Wed, 15 Jul 2020 19:02:29 +0000</pubDate>
      <link>https://dev.to/_mikhailbot/adding-browser-sync-to-laravel-and-docker-with-vessel-5flj</link>
      <guid>https://dev.to/_mikhailbot/adding-browser-sync-to-laravel-and-docker-with-vessel-5flj</guid>
      <description>&lt;p&gt;I recently stumbled upon &lt;a href="https://vessel.shippingdocker.com/"&gt;Vessel&lt;/a&gt; by &lt;a href="https://serversforhackers.com/"&gt;Chris Fidao&lt;/a&gt; which is a great way to leverage Docker in your development environment. I'm a big fan of Docker and use it extensively for home lab work, but haven't fully explored it for development yet.&lt;/p&gt;

&lt;p&gt;Getting it going with some Laravel projects I had on hand was super smooth and will probably be my new choice for development going forward. However, I was still hoping to fix an issue I've been having developing on &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-index"&gt;WSL 2&lt;/a&gt;--getting Browser Sync to work. It's one of the biggest annoyances when working in Window's WSL 2 versus on macOS.&lt;/p&gt;

&lt;p&gt;After some playing around with the config files Vessel generates, I've gotten Browser Sync to work with it--which also means it works in WSL 2 thanks to Docker!&lt;/p&gt;

&lt;p&gt;First this assumes you have a relatively new Laravel project (version 6 or 7) and have &lt;a href="https://github.com/shipping-docker/vessel#install"&gt;set up Vessel&lt;/a&gt; without any major customizations.&lt;/p&gt;

&lt;p&gt;First lets update our &lt;code&gt;.env&lt;/code&gt; to reduce any port conflicts, changing the APP port and MYSQL port as appropriate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env&lt;/span&gt;
&lt;span class="nv"&gt;APP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8080
&lt;span class="nv"&gt;MYSQL_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;33060
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;./vessel start&lt;/code&gt; should get your containers up and running with your defined ports--great! Next we're going to ensure you've Browser Sync included in your dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./vessel npm i browser-sync browser-sync-webpack-plugin &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Update your &lt;code&gt;webpack.mix.js&lt;/code&gt; to leverage the new package. Here you can choose whether just to watch for files going through the webpack pipeline (CSS and JS) or also include any changes to your Blade templates or even user content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// webpack.mix.js&lt;/span&gt;
&lt;span class="nx"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/js&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;sass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/sass/app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/css&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;browserSync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app:80&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The magic line is &lt;code&gt;app:80&lt;/code&gt;--this should be equal to the container Vessel created for you. It should be called &lt;code&gt;app&lt;/code&gt;. To confirm run &lt;code&gt;./vessel ps&lt;/code&gt; and look for one that has &lt;code&gt;app&lt;/code&gt; in the title. If you run into issues, it may also be called &lt;code&gt;yourappname_app_1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The port by default is &lt;code&gt;80&lt;/code&gt; but change this if you've changed your &lt;code&gt;docker_compose.yml&lt;/code&gt; file to something else. This should be the internal container port, not the port you used to view your site (in this case &lt;code&gt;8080&lt;/code&gt; as defined earlier).&lt;/p&gt;

&lt;p&gt;Finally, we're going to tell Docker to expose the Browser Sync ports, as well as a default command to ensure the container doesn't immediately exit and opens the ports for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run watch&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;3000:3000"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3001:3001"&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, let's stop and start our containers, and if all went well we should see our Browser Sync connected app at &lt;code&gt;localhost:3000&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./vessel stop &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./vessel start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you don't initially see your app, you can run the below command to see any log output from the node process--sometimes it takes a bit to get everything built initially.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./vessel logs node

&lt;span class="c"&gt;# If you wanna follow the logs live&lt;/span&gt;
&lt;span class="c"&gt;# ./vessel logs -f node&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;This post originally appear on my personal &lt;a href="https://delport.ca/"&gt;site&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wsl</category>
      <category>docker</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Vue CLI 3, TailwindCSS, and PurgeCSS</title>
      <dc:creator>Mikhail 🐺</dc:creator>
      <pubDate>Wed, 26 Sep 2018 15:14:26 +0000</pubDate>
      <link>https://dev.to/_mikhailbot/vue-cli-3-tailwindcss-and-purgecss-1d1k</link>
      <guid>https://dev.to/_mikhailbot/vue-cli-3-tailwindcss-and-purgecss-1d1k</guid>
      <description>&lt;p&gt;The new &lt;a href="https://cli.vuejs.org/"&gt;Vue CLI&lt;/a&gt; just came out and I was itching to give it a go. Our wedding website needed a fresh coat of paint so decided to move it from Nuxt to just a plain Vue app. It's two pages so there was really no need to bring Nuxt in.&lt;/p&gt;

&lt;p&gt;The new Vue CLI is awesome and got things up and running in no time. Add in my new favourite CSS framework, &lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt;, and things were soaring along. Until I decided the decrease my bundle size.&lt;/p&gt;

&lt;p&gt;Because of how TailwindCSS works, by default the entire framework gets included. You can add some configuration options to add or removes colours, responsive states, and such. However, an even easier way to handle things is with &lt;a href="https://github.com/FullHuman/purgecss"&gt;PurgeCSS&lt;/a&gt;. It'll go over through your HTML (Vue in my case) files and see what CSS selectors you use, and remove all the others from your CSS. This should cause your TailwindCSS output to be tiny, just the classes you use!&lt;/p&gt;

&lt;p&gt;A new project with Vue CLI 3 uses &lt;a href="https://github.com/michael-ciniawsky/postcss-load-config"&gt;postcss-load-config&lt;/a&gt; to handle PostCSS plugins. However, the default way of using your &lt;code&gt;package.json&lt;/code&gt; to configure plugins doesn't appear to work with the PostCSS PurgeCSS &lt;a href="https://github.com/FullHuman/postcss-purgecss"&gt;plugin&lt;/a&gt;. Thankfully, postcss-load-config allows you to use numerous different type of configuration files. Switching to a JavaScript one (&lt;code&gt;.postcssrc.js&lt;/code&gt;) gave me the below config that allows you to use TailwindCSS in your Vue files, but also removes unused CSS from the generated bundle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&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;purgecss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fullhuman/postcss-purgecss&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;autoprefixer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;autoprefixer&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;postcssImport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-import&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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;postcssImport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;tailwindcss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./tailwind.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;purgecss&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;content&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="s1"&gt;./src/**/*.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;extractors&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;extractor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;TailwindExtractor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&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="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-z0-9-:&lt;/span&gt;&lt;span class="se"&gt;\/]&lt;/span&gt;&lt;span class="sr"&gt;+/g&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="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;extensions&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="s1"&gt;vue&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="nx"&gt;autoprefixer&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;This took me far too long to figure out, but the benefits are profound! Before adding PurgeCSS my CSS bundle was 50.12 kb Gzipped, after PurgeCSS it was only 2.33 kb--over a 20 times reduction in size!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The custom extrator is required for Tailwind's responsive classes which get stripped out by default!&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;Originally posted on my &lt;a href="https://delport.ca/2018/vue-tailwindcss-purgecss"&gt;site&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>tailwindcss</category>
      <category>postcss</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
