Meandering Soul

This day is done, I'm going home.
eFranes Penguin Avatar

Creating efrane.com Or how to inline styles with Jigsaw and TailwindCSS

25
Jul 2020

Recently, I finally got around to designing something of a portfolio website for me. There really is never time to do these, is there? You can head over to GitHub to view the source if you want, no need to keep it private. 

The general setup is a Jigsaw-based static site using TailwindCSS as style framework. The whole site does not have a single line of JavaScript in production which – surprise! – massively simplifies the setup! (Also, like, loading times are amazeballs.)

Decisions

Before deciding on the frameworks to use, I set up some constraints for the design and more so for the technical foundation of the site:

  • Graceful degradation on older browsers
  • Very good accessibility
  • Responsive-ish layout
  • Fast
  • Low-barrier content modification

Along came also some quirky demands like wanting to use flexbox for layout and having Twig or Blade as a Template Engine as I am most comfortable thinking template logic in those. I also wanted to write as little as possible server or generation code as this site will – for the foreseeable future – not have any dynamic content. Nevertheless, some kind of content editing that can be easier than always writing everything in HTML was added as a nice-to-have.

In my toolbox, these requirements form a straight path towards static site generators. Among these, since I am well-versed in Laravel, Jigsaw is the obvious choice for me. One never knows if there’s any modifications to be made and it always helps to know ones way around the underlying architecture.

Choosing TailwindCSS as a style framework was a no-brainer. It is a wonderfully simple solution and I find myself clicking with the utility-only approach.

Getting it done

Jigsaw provides several events to modify and extend the build process. Since my goal was to add content to the resulting HTML files after all other build steps, I opted for adding a handler on the afterBuild event:

1
2
3
4
// in Jigsaw's bootstrap.php

/** @var $events \TightenCo\Jigsaw\Events\EventBus */
$events->afterBuild(InlineStyles::class);

The Inline Styles event handler is of course where the magic happens. First, all built html files need to be gathered, Symfony’s Finder component is great at that:

1
2
3
4
$htmlFilesFinder = Finder::create()
            ->in($jigsaw->getDestinationPath())
            ->name('*.html')
            ->files();

Then, we can fetch the compiled CSS and inject it into a style tag in the head using SimpleXML:

1
2
3
4
5
6
7
8
9
$htmlFile = simplexml_load_file($htmlFilePath);

        $cssPath = $jigsaw->getDestinationPath() . (string)$htmlFile->head->style['data-src'];

        $cssContents = file_get_contents($cssPath);

        $htmlFile->head->style = $cssContents;

        file_put_contents($htmlFilePath, $htmlFile->asXML());

The full code is available on GitHub: http://github.com/eFrane/efrane.com.

  • Published on July 25, 2020
  • 419 words

A mermaid.js Plugin for Vuepress

16
Oct 2019

Since the last time I wrote about integrating Mermaid with Vuepress the latter matured to version 1.0. With that came a much more refined plugin interface - or maybe that existed before and I just didn’t notice it in the docs. In the meantime, I have been implementing that previous approach in a growing number of documentation sites and figured that having this as a plugin to a) reduce the hassle of getting it to work to basically zero and b) stop copying a bunch of code around would be a good idea.

So, without further ado I present vuepress-plugin-mermaidjs. When you do the search on npm, you will unfortunately find another package named very similar (vuepress-plugin-mermaid). One might ask now, “eFrane, why didn’t you just contribute to that one instead, wouldn’t that have been the healthier choice for the ecosystem?” Yes, it would have. Alas, the GitHub Repository for that plugin is empty and it doesn’t have a readme and wasn’t updated in over a year. All in all, that feels like an abandoned package to me. So that’s why I decided to publish my take as a package. 

NPM Package: https://www.npmjs.com/package/vuepress-plugin-mermaidjs
GitHub Repo:https://github.com/eFrane/vuepress-plugin-mermaidjs

  • Published on October 16, 2019
  • 194 words

Symfony Console Additions v0.6.0

21
Sep 2019

I released [efrane/console-additions](https://packagist.org/packages/efrane/console-additions) v0.6.0 today. More than a year after the last bigger release this probably could have been a v1.0. However, I still feel like there’s some fundamentals I do with Symfony’s Console component in my everyday work which I would like to extract into a reusable form in this library.

So, what’s changed?

For one, this development episode was focused on reorganising the code. There’s still very few files in the repository but that doesn’t mean that there wasn’t room for optimisation. The result of this is, that the tests folder now resemble the folder structure of the src folder, thus making it easier to find the corresponding test file.

The bigger change is a partial rewrite of command batches. Before, the Batch class internally managed every possible action as a combination of strings and weird arrays. This type-conglomerate lead to a quite a few ugly places in the code which felt like they might break at a moment’s notice. Since this version, Batch internally relies on Action classes which know how to handle themselves. This also means, that Batch just became that much more powerful since all Batch wants to know about them is how to represent them as a string and a way to start their execution:

1
2
3
4
5
interface Action
{
    public function execute(OutputInterface $output): int;
    public function __toString(): string;
}

Usable actions are now:

  • StringCommandAction - This handles executing console commands given a full command signature
  • InstanceCommandAction - No need to do string parsing of a signature? Pass a command instance to this one!
  • MessageAction - This is your basic echo action. Especially when PHP-izing former shell scripts, this can come in quite handy
  • ProcessAction - Pass a configured Process from the Symfony Process component to this one
  • ShellAction - Just want to execute a shell command and don’t feel like configuring the process yourself? This one is there for your convenience!

All of the built-in actions have convenience methods on Batch, e.g. $batch->addProcess() or $batch->addMessage().

Along with these internal updates came the jump to PHP 7.0 or newer as a language dependency and Symfony Components 3.4 or newer are required to work with this library now. The latter also means that string parsing for commands in $batch->addShell() has been deprecated and will be removed in the next release. I highly encourage any user of this library to switch to the array-Syntax.

  • Published on September 21, 2019
  • 403 words

Adding mermaid.js support to Vuepress

22
May 2019

I recently set up Vuepress for the first time to create a documentation for a new library I am working on (more on that in a future post). Since that library will do a few things that might appear sort of magical it seems like a good idea to add a few explanatory graphs to the documentation.

Now, what tool combines markdown-friendliness with creating graphs? Yep, you guessed it: Mermaid.js.

There are numerous ways of making Vuepress do things it can’t by default:

  • You can overwrite the whole theme
  • You can add Markdown-It plugins for additional markdown processing
  • You can add global components

The long story here would be to elaborate on why overwriting the theme is not an option and the plugin route didn’t pan out. But let’s not bore ourselves with that story. So yeah, I created a new global component in .vuepress/components/Mermaid.vue and worked away. However, it’s unfortunately not exactly that simple. Since Vuepress is a SPA or rather even an PWA, rendering works a little bit different. Which in short means that it’s very easy to get something to show up on first load of a component but there’s a little work involved in having things work after navigation. The technical background to this can be referenced in the vue-router Documentation.

What I ended up with is rendering the mermaid graphs to SVG and then rendering the SVG in the component’s render() Function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import mermaid from 'mermaid/src/mermaidAPI'

let graphIdCounter = 0

export default {
  name: 'Mermaid',
  data() {
    return {
      svg: undefined,
      graph: this.$slots.default[0].text
    }
  },
  render(h) {
    return h('div', { domProps: { innerHTML: this.svg }})
  },
  mounted() {
    mermaid.initialize({ startOnLoad: true })

    let renderDiv = document.createElement('div')
    document.body.appendChild(renderDiv)

    mermaid.render(
      'mermaid' + ++graphIdCounter,
      this.graph,
      (svg) => {
        this.svg = svg
        document.body.removeChild(renderDiv)
      },
      renderDiv
    )
  }
}

Alas, this was not quite the end of it. I would have hoped that I’d be off to the races with yarn add mermaid. That’s not even close. Here’s the full list of dependencies you’ll have to add:

  • mermaid
  • sass-loader
  • node-sass

After this, adding mermaid graphs anywhere in the documentation markdown is as easy as

1
2
3
4
5
<mermaid>
graph TD
mermaid-->isAwesome
isAwesome-->mermaid
</mermaid>

Which then renders to:

Update (2019-10-16): I published an npm package that provides the <mermaid>-Component.

  • Published on May 22, 2019
  • 387 words

Get the number of days in a month with moment.js

09
Dec 2015
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var date = moment();
var currentMonth = date.month();

var daysInMonth = 31;         // Every month has 31 days
if (currentMonth % 2 == 1) {  // except every other month
    if (currentMonth == 1) {  // and then there is februrary
        if (date.isLeapYear()) { 
            daysInMonth = 29; // which has 29 if it's a leap year
        } else {
            daysInMonth = 28; // and 28 if it isn't.
        }
    } else {
        daysInMonth = 30;
    }
}
  • Published on December 09, 2015
  • 79 words

Using Git Hooks for code style fixes

16
Oct 2015

Pretty much every modern language has an established Coding Style Guide. For PHP, this is PSR-2. As with other style guides of this sort, there is a tool for automatically applying the appropriate fixes to one’s code

I only recently finally switched to using PSR-2 and to make sure I wouldn’t accidentally miss running the style fixer, I added this little snipped to my .git/hooks/pre-commit-Hook:

1
2
3
4
5
6
modified_php=$(git ls-files --modified | grep "\.php$")

for f in $modified
do
    php-cs-fixer fix --level psr2 $f
done
  • Published on October 16, 2015
  • 84 words

Redirecting in Laravel Form Requests

08
May 2015

While Form Request Validation in Laravel 5 usually does exactly what it’s supposed to do, I recently had to append a location hash to the redirect URL. Turns out that’s as simple as overwriting the FormRequest’s getRedirectUrl()-method:

1
2
3
4
5
protected function getRedirectUrl()
{
  $url = $this->redirector->getUrlGenerator();
  return $url->previous().'#hash';
}
  • Published on May 08, 2015
  • 49 words