<?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: Roman Potashow</title>
    <description>The latest articles on DEV Community by Roman Potashow (@justgook).</description>
    <link>https://dev.to/justgook</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%2F187711%2F49dce561-e161-4afd-89eb-f80309deb9c7.png</url>
      <title>DEV Community: Roman Potashow</title>
      <link>https://dev.to/justgook</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/justgook"/>
    <language>en</language>
    <item>
      <title>Good enough for production</title>
      <dc:creator>Roman Potashow</dc:creator>
      <pubDate>Fri, 25 Oct 2019 08:30:27 +0000</pubDate>
      <link>https://dev.to/justgook/good-enough-for-production-49ja</link>
      <guid>https://dev.to/justgook/good-enough-for-production-49ja</guid>
      <description>&lt;p&gt;Im frontend developer for more that 10y, and to be in shape I do some small projects just for personal satisfaction, or to learn some new technics and tools. &lt;/p&gt;

&lt;p&gt;Most of my work is just some opens source (as I believe in it) - any project that I do for my self gives me experience, that is biggest profit that I can get, and happy when someone can learn something out of that.&lt;/p&gt;

&lt;p&gt;For those "Pet projects" exists good place where share code - &lt;a href="http://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, but maybe not all of you knows that GitHub also allows you publish your work as &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;static web pages&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitHub Pages is a static site hosting service that takes HTML, CSS, and JavaScript files straight from a repository on GitHub, optionally runs the files through a build process, and publishes a website.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words everything that is pushed to branch &lt;code&gt;gh-pages&lt;/code&gt; - is served as static page under &lt;code&gt;http(s)://&amp;lt;user&amp;gt;.github.io/&amp;lt;repository&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For some time all my pet projects is written in &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; and &lt;code&gt;elm&lt;/code&gt; ecosystem is just single elm compiler that allow you do all job (compile elm to js, run local server, download packages, publish packages, run code optimisations, and even more).&lt;/p&gt;

&lt;p&gt;Problem came - when you need to publish it - as just copy development code to public folder (&lt;code&gt;gh-pages&lt;/code&gt; brunch) is not acceptable for me. &lt;strong&gt;Production code should be not same as development&lt;/strong&gt; - it should not contain any debug information, it bundle size should be optimised for download not for rebuild time. Same goes for HTML (for development you not really care how it looks as long as it works), for production HTML should be valid, have social media meta tags (twitter, facebook), css should live in separate files.&lt;/p&gt;

&lt;p&gt;Other part that I'm (as most developers) lazy, and everything that can be automated - &lt;strong&gt;must&lt;/strong&gt; be automated. And deployment automation can be done via CI (continues integration) &lt;/p&gt;

&lt;p&gt;I using &lt;a href="https://travis-ci.org" rel="noopener noreferrer"&gt;Travis&lt;/a&gt; - main benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;easy configurable &lt;/li&gt;
&lt;li&gt;free for open source projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://travis-ci.org" rel="noopener noreferrer"&gt;Travis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lisperator.net/uglifyjs/" rel="noopener noreferrer"&gt;uglify-js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://terser.org/" rel="noopener noreferrer"&gt;terser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/facebook/jscodeshift" rel="noopener noreferrer"&gt;jscodeshift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prepack.io/" rel="noopener noreferrer"&gt;Prepack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/posthtml/posthtml" rel="noopener noreferrer"&gt;PostHTML&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  GitHub Pages
&lt;/h1&gt;

&lt;p&gt;Kind of explained before - but there is few hacks that you can learn and implement.&lt;/p&gt;

&lt;h4&gt;
  
  
  404.html
&lt;/h4&gt;

&lt;p&gt;create file &lt;code&gt;404.html&lt;/code&gt; in &lt;code&gt;gh-pages&lt;/code&gt; root that redirects all request to &lt;code&gt;index.html&lt;/code&gt; (2019 - we all about &lt;a href="https://en.wikipedia.org/wiki/Single-page_application" rel="noopener noreferrer"&gt;SPA&lt;/a&gt;)&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="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&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;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"refresh"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"0;URL='http(s)://&amp;lt;user&amp;gt;.github.io/&amp;lt;repository&amp;gt;'"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  index.html
&lt;/h4&gt;

&lt;p&gt;Add script that will update history from redirect if there was such:&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&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&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="nx"&gt;redirect&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceState&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Javascript bundle
&lt;/h1&gt;

&lt;p&gt;Elm part have great explanation in official guide, section &lt;a href="https://guide.elm-lang.org/optimization/asset_size.html" rel="noopener noreferrer"&gt;Asset Size&lt;br&gt;
&lt;/a&gt;, but if you use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" rel="noopener noreferrer"&gt;custom elements&lt;/a&gt;, that is main way to interact with some low-level api from js, or external libs (google maps, code editors,..) you need cannot use only uglify-js, as it not supports ES6 classes that is needed for custom elements - so there come in place &lt;a href="https://terser.org/" rel="noopener noreferrer"&gt;terser&lt;/a&gt; - that is not so great for elm, but can do stuff for custom elements.&lt;/p&gt;
&lt;h4&gt;
  
  
  Elm
&lt;/h4&gt;

&lt;p&gt;elm can do all by it self (as mention before):&lt;br&gt;
&lt;code&gt;elm make src/Main.elm --optimize --output=./gh-pages/bundle.js&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  JsCodeShift
&lt;/h4&gt;

&lt;p&gt;here it is - that file take all take care of glsl string optimisations (if you use WebGL) inline &lt;code&gt;An&lt;/code&gt; and &lt;code&gt;Fn&lt;/code&gt; functions in result javascript - in other words - &lt;em&gt;elm js voodoo&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jscodeshift &lt;span class="nt"&gt;-t&lt;/span&gt; transform.js ./gh-pages/bundle.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/justgook/6c37a9f6e78987da7eb3c5847ffbabd7" rel="noopener noreferrer"&gt;transform.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Uglify-js
&lt;/h4&gt;

&lt;p&gt;if you not use custom elements just copy it from elm &lt;a href="https://guide.elm-lang.org/optimization/asset_size.html#instructions" rel="noopener noreferrer"&gt;guide&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uglifyjs ./gh-pages/bundle.js &lt;span class="nt"&gt;--compress&lt;/span&gt; &lt;span class="s1"&gt;'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe'&lt;/span&gt; | uglifyjs &lt;span class="nt"&gt;--mangle&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./gh-pages/bundle.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or split that in 2 commands, where first one will be done with &lt;code&gt;uglify-js&lt;/code&gt; (and second with &lt;code&gt;terser&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;uglifyjs ./gh-pages/bundle.js &lt;span class="nt"&gt;--compress&lt;/span&gt; &lt;span class="s2"&gt;"pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./gh-pages/bundle.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Prepack
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Prepack is a tool that optimizes JavaScript source code: Computations that can be done at compile-time instead of run-time get eliminated. Prepack replaces the global code of a JavaScript bundle with equivalent code that is a simple sequence of assignments. This gets rid of most intermediate computations and object allocations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Prepack will increase bundle size (most of time) - but application will run faster - as lot of math and code is inlined (where it can), and with pure functional language as Elm - it can done &lt;strong&gt;lot&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prepack ./gh-pages/bundle.js &lt;span class="nt"&gt;--inlineExpressions&lt;/span&gt; &lt;span class="nt"&gt;--out&lt;/span&gt; ./gh-pages/bundle.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Terser
&lt;/h4&gt;

&lt;p&gt;totally same as uglify js - but here you merging together ES6 custom elements with your resulted &lt;code&gt;bundle.js&lt;/code&gt; of elm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terser ./gh-pages/bundle.js ./gh-pages/script.js &lt;span class="nt"&gt;--compress&lt;/span&gt; &lt;span class="s1"&gt;'keep_fargs=false,unsafe_comps,unsafe'&lt;/span&gt; &lt;span class="nt"&gt;--mangle&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./gh-pages/bundle.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Result pipeline looks like for &lt;code&gt;bundle.js&lt;/code&gt;:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;elm make src/Main.elm &lt;span class="nt"&gt;--optimize&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./gh-pages/bundle.js
jscodeshift &lt;span class="nt"&gt;-t&lt;/span&gt; transform.js ./gh-pages/bundle.js
uglifyjs ./gh-pages/bundle.js &lt;span class="nt"&gt;--compress&lt;/span&gt; &lt;span class="s2"&gt;"pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./gh-pages/bundle.js
prepack ./gh-pages/bundle.js &lt;span class="nt"&gt;--inlineExpressions&lt;/span&gt; &lt;span class="nt"&gt;--out&lt;/span&gt; ./gh-pages/bundle.js
terser ./gh-pages/bundle.js ./gh-pages/script.js &lt;span class="nt"&gt;--compress&lt;/span&gt; &lt;span class="s1"&gt;'keep_fargs=false,unsafe_comps,unsafe'&lt;/span&gt; &lt;span class="nt"&gt;--mangle&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./gh-pages/bundle.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have production ready &lt;code&gt;bundle.js&lt;/code&gt; that is optimised for production, and we done as much as can in build time (that we should not do for development as they take lot of time).&lt;/p&gt;

&lt;h1&gt;
  
  
  PostHTML
&lt;/h1&gt;

&lt;p&gt;For your project you would like attract people (or at share it) in Facebook, Twitter and others. To make your project looks nice. You can try your links in validators (&lt;a href="https://cards-dev.twitter.com/validator" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="https://developers.facebook.com/tools/debug/sharing/" rel="noopener noreferrer"&gt;facebook&lt;/a&gt;) to see how they will be represented. Main idea is that bots (grabbers) go to link, and try find some information to present your application (link) as nice post/card.&lt;/p&gt;

&lt;p&gt;But as developer (at least that is true for me) - you would like have your HTML code download fast.&lt;/p&gt;

&lt;h4&gt;
  
  
  PostHTML &amp;amp; Plugins
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;posthtml-cli&lt;/code&gt; - &lt;a href="https://github.com/posthtml/posthtml" rel="noopener noreferrer"&gt;PostHTML&lt;/a&gt; сommand line interface&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;htmlnano&lt;/code&gt; - Modular HTML minifier, built on top of the &lt;a href="https://github.com/posthtml/posthtml" rel="noopener noreferrer"&gt;PostHTML&lt;/a&gt;. Inspired by &lt;a href="http://cssnano.co/" rel="noopener noreferrer"&gt;cssnano&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;posthtml-content&lt;/code&gt; - Flexible content transform for posthtml&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;posthtml-favicons&lt;/code&gt; - This module is using &lt;a href="https://github.com/evilebottnawi/favicons" rel="noopener noreferrer"&gt;favicons&lt;/a&gt; to generate all of favicons based on a single image&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;posthtml-head-elements&lt;/code&gt; - This plugin is intended to work with PostHTML. It will allow you to keep HTML head elements - title, script, link, base and meta - in a separate JSON file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;posthtml-style-to-file&lt;/code&gt; - Save DOM styles to CSS file&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each application needs it own favicon, and they must be converted to lot of devices (iPhone, Android, and different sizes for different sizes of screen, icons, pixelRatios)&lt;/p&gt;

&lt;p&gt;Each application needs its own &lt;a href="https://developers.facebook.com/" rel="noopener noreferrer"&gt;Facebook App Id&lt;/a&gt;, special meta tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;posthtml ./gh-pages/index.html &lt;span class="nt"&gt;-o&lt;/span&gt; ./gh-pages/index.html &lt;span class="nt"&gt;-c&lt;/span&gt; posthtml.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/justgook/d3e17098a7894fc654f6d10e3dde0be6" rel="noopener noreferrer"&gt;posthtml.config.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Screenshots
&lt;/h4&gt;

&lt;p&gt;To create nice social media meta-tags you need some image of your application. You can just create your images by your self - but im too lazy for that - and just screenshot is good enough for that (and if I not like that idea, I always can create some custom url for taking screenshot).&lt;br&gt;
There is nice tool that can be used to make screenshot in CI - that will update image each build - &lt;a href="https://www.npmjs.com/package/node-server-screenshot" rel="noopener noreferrer"&gt;&lt;code&gt;node-server-screenshot&lt;/code&gt;&lt;/a&gt;&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;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&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;takeScreenShot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-server-screenshot&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/index.html`&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/gh-pages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;F_OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&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;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;server started&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;savePreview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`gh-pages/&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;APP_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png`&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;preview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;takeScreenShot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;savePreview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;show&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;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;675&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;waitAfterSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body &amp;gt; *&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;waitMilliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&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="o"&gt;=&amp;gt;&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Screenshot: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;savePreview&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&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;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&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;h1&gt;
  
  
  Deploy
&lt;/h1&gt;

&lt;p&gt;Deployment of all that to gh-pages is really easy task after all that, as &lt;a href="https://travis-ci.org" rel="noopener noreferrer"&gt;Travis&lt;/a&gt; have &lt;a href="https://docs.travis-ci.com/user/deployment/pages/" rel="noopener noreferrer"&gt;provider&lt;/a&gt; that do all magic for you. (will not go in to details how to do that - all info is in &lt;a href="https://docs.travis-ci.com/user/deployment/pages/" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&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;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pages&lt;/span&gt;
  &lt;span class="na"&gt;skip-cleanup&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;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$GITHUB_TOKEN&lt;/span&gt;
  &lt;span class="na"&gt;keep-history&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;local-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh-pages&lt;/span&gt;
  &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;Lets make our projects look like production application even if that is just "pet experiment project". It is not so hard, and after few projects published like that, you will not be able just push something to public domain until it looks like it is professional app (even if not).&lt;br&gt;
With correct tool and few minutes in preparation - you can automate all that process, and not think about it any more.&lt;/p&gt;

&lt;p&gt;Here is examples:&lt;br&gt;
&lt;a href="https://github.com/justgook/web-tiled" rel="noopener noreferrer"&gt;web-tiled&lt;/a&gt; - current work in progress where I done all that in few hours &lt;br&gt;
&lt;a href="https://github.com/justgook/platformer" rel="noopener noreferrer"&gt;platformer&lt;/a&gt; - extended version with binary encoding of game level - that I'll explain some day.&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%2F9cmq452kdhetzodwqd93.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%2F9cmq452kdhetzodwqd93.png" alt="Twitter Cards"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elm</category>
      <category>github</category>
      <category>html</category>
    </item>
  </channel>
</rss>
