Webpack Academy

Sean Larkin, core team member of Webpack, will be leaving his current job at Mutual of Omaha for a new position at Microsoft. Because on his team he was the one most familiar with the webpack setup of the project, he looked for a way to transfer his knowledge. He landed on creating a video course on webpack that’s free for everyone.

I decided to create Webpack Academy, a training and educational platform for those wanting to learn more about webpack. This was a perfect way to not only allow me to give back to my team — by giving them free access to all of the content — but to also benefit the community by sharing it with everyone.

https://webpack.academy/

How to analyze tweet sentiments with PHP Machine Learning

In a post on Sitepoint Allan MacGregor gives a good practical example on how to work with PHP-ML, a machine learning library for PHP.

As of late, it seems everyone and their proverbial grandma is talking about Machine Learning. Your social media feeds are inundated with posts about ML, Python, TensorFlow, Spark, Scala, Go and so on; and if you are anything like me, you might be wondering, what about PHP?

Yes, what about Machine Learning and PHP? Fortunately, someone was crazy enough not only to ask that question, but to also develop a generic machine learning library that we can use in our next project. In this post we are going take a look at PHP-ML – a machine learning library for PHP – and we’ll write a sentiment analysis class that we can later reuse for our own chat or tweet bot.

https://www.sitepoint.com/how-to-analyze-tweet-sentiments-with-php-machine-learning/

Achieving Geo-search with Laravel Scout and Algolia

On Scotch.io a new post by Julien Bourdeau was published that shows how you can easily import and search geographic data with Laravel Scout and Algolia.

Laravel Scout makes it very easy to setup an external search engine to create consumer-grade search quickly. The package comes with Algolia as a default search engine. I’d like to demonstrate how to make use of the geo-location search feature with Scout.

In this tutorial, you’ll learn how to prepare your data for Algolia and Laravel Scout to retrieve items based on location.

https://scotch.io/tutorials/achieving-geo-search-with-laravel-scout-and-algolia

Optimize images in Laravel apps

A while ago we released image-optimizer. In short this package can make all kinds of images smaller by stripping out metadata and applying a little bit of compression. Read this blogpost to learn more about it. Although it’s pretty easy to work with the package, we felt that we could deliver a more seamless experience in Laravel apps. That’s why we created our newly released laravel-image-optimizer package.

The package uses a bunch of binaries to optimize images. To learn which ones and how to install them, head over to the optimization tools section in the readme of the underlying image-optimizer package. That readme also contains info on what these tools will do to your images.

Once the laravel-image-optimizer package is installed it’s laughably easy to optimize images.

If you like facades this is how you’d go about it:

use ImageOptimizer;

// the image will be replaced with an optimized version which should be smaller
ImageOptimizer::optimize($pathToImage);

// if you use a second parameter the package will not modify the original
ImageOptimizer::optimize($pathToImage, $pathToOptimizedImage);

You don’t like facades you say? No problem! Just resolve a configured instance of Spatie\ImageOptimizer\OptimizerChain out of the container:

app(Spatie\ImageOptimizer\OptimizerChain::class)->optimize($pathToImage);

The package also contains a middleware to automatically optimize all images in a request.

Route::middleware('optimizeImages')->group(function () {
    // all images will be optimized automatically
    Route::post('upload-images', [email protected]);
});

If you want to customize the chain of tools and the options being passed to them, you can do so by publishing and modifying the config file. This is the default contents:

use Spatie\ImageOptimizer\Optimizers\Svgo;
use Spatie\ImageOptimizer\Optimizers\Optipng;
use Spatie\ImageOptimizer\Optimizers\Gifsicle;
use Spatie\ImageOptimizer\Optimizers\Pngquant;
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;

return [
    /*
     * When calling `optimize` the package will automatically determine which optimizers
     * should run for the given image.
     */
    'optimizers' => [

        Jpegoptim::class => [
            '--strip-all',  // this strips out all text information such as comments and EXIF data
            '--all-progressive',  // this will make sure the resulting image is a progressive one
        ],

        Pngquant::class => [
            '--force', // required parameter for this package
        ],

        Optipng::class => [
            '-i0', // this will result in a non-interlaced, progressive scanned image
            '-o2',  // this set the optimization level to two (multiple IDAT compression trials)
            '-quiet', // required parameter for this package
        ],

        Svgo::class => [
            '--disable=cleanupIDs', // disabling because it is know to cause troubles
        ],

        Gifsicle::class => [
            '-b', // required parameter for this package
            '-O3', // this produces the slowest but best results
        ],
    ],

    /*
     * The maximum time in seconds each optimizer is allowed to run separately.
     */
    'timeout' => 60,

    /*
     * If set to `true` all output of the optimizer binaries will be appended to the default log.
     * You can also set this to a class that implements `Psr\Log\LoggerInterface`.
     */
    'log_optimizer_activity' => false,
];

To learn more about laravel-image-optimzer head over to the readme on GitHub. And be sure to check out the other Laravel package we’ve previously made.

Good Product Team / Bad Product Team

Marty Cagan, who held jobs at eBay, AOL, Netscape and HP, describes the most important differences between good and bad product teams.

What I’ve learned is that there is a profound difference between how the very best product companies create technology products, and the rest. And I don’t mean minor differences. Everything from how the leaders behave, to the level of empowerment of teams, to how the organization thinks about funding, staffing and producing products, down to how product, design and engineering collaborate to discover effective solutions for their customers.

http://svpg.com/good-product-team-bad-product-team/

Typehint all the things

David Négrier, CTO of the CodingMachine, wrote a nice article on why he likes and how his team uses typehints.

As a developer consuming this function, I know how to use it. And if I’m using it wrong, I’ll know right away because PHP will crash with a nice error message when the function is called rather than with a cryptic error some time later.

https://www.thecodingmachine.com/type-hint-all-the-things/

Personally I like typehints too, because the potential readability improvement the article touches upon.

Note: (I only include this paragraph because it’s mentioned in the intro of the article, don’t want to stir up a discussion) the fuzz about that “Visual Debt” video was overblown. Even though I didn’t agree with all of it, it was nice to hear Jeffrey’s way of thinking.

Easily optimize images using PHP (and some binaries)

Our recently released image-optimizer package can shave off some kilobyes of PNGs, JPGs, SVGs and GIFs by running them through a chain of various image optimization tools. In this blog post I’ll tell you all about it.

First, here’s a quick example on how you can use it:

use Spatie\ImageOptimizer\OptimizerChainFactory;

$optimizerChain = OptimizerChainFactory::create();

$optimizerChain->optimize($pathToImage);

The image at $pathToImage will be overwritten by an optimized version which should be smaller. Here are a few images that were optimized by this package.

Why we built this

On nearly every website we make, images are displayed. In fact, in most cases images make up the bulk of the size of the entire page. So to provide a fast page load it’s best to make those images as small as they can be. The less bytes the browser needs to download the faster the page will be.

Now, to make images as small as they can be (without sacrificing a lot of detail) there are a lot of tools available. These tools, such as jpegtran, pngquant, and gifsicle, work more or less by applying a little bit of compression, removing metadata and reducing the number of colors. In most cases these tools can make your images considerably smaller without you noticing, unless you have a trained eye for that.

These tools are free to use and can be easily installed on any system. So far so good. What makes them a bit bothersome to use from PHP code is that you need to create a process to run them. You must make sure that you pass the right kind of image to the right optimizer. You also have to decide which optimization parameters you’re going to use for each tool. None of this is rocket science, but I bet that the vast majority of small to medium sites don’t bother writing this code or researching these optimizations.

Our package aims to do all of this out of the box. It can find out which optimizers it should run, it can execute the binary and by default uses a set of optimizers with a sane configuration.

How to optimize images

Optimizing an image is very easy using our package.

use Spatie\ImageOptimizer\OptimizerChainFactory;

$optimizerChain = OptimizerChainFactory::create();

$optimizerChain->optimize($pathToImage);

The image at $pathToImage will be overwritten by an optimized version which should be smaller.

The package will use these optimizers if they are present on your system:

The readme of the package includes instructions on how to install these on Ubuntu and MacOS.

Which tools will do what?

Like already mentioned, the package will automatically pick the right tool for the right image.

JPGs

JPGs will be made smaller by running them through JpegOptim. These options are used:
--strip-all: this strips out all text information such as comments and EXIF data
--all-progressive: this will make sure the resulting image is a progressive one, meaning it can be downloading using multiple passes of progressively higher details.

PNGs

PNGs will be made smaller by running them through two tools. The first one is Pngquant 2, a lossy PNG comprossor. We set no extra options, their defaults are used. After that we run the image throug a second one: Optipng. These options are used:
-i0: this will result in a non-interlaced, progressive scanned image
-o2: this set the optimization level to two (multiple IDAT compression trials)

Customizing the optimization

If you want to customize the chain of optimizers you can do so by adding Optimizers manually to a OptimizerChain.

Here’s an example where we only want optipng and jpegoptim to be used:

use Spatie\ImageOptimizer\OptimizerChain;
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
use Spatie\ImageOptimizer\Optimizers\Pngquant;

$optimizerChain = (new OptimizerChain)
   ->addOptimizer(new Jpegoptim([
       '--strip-all',
       '--all-progressive',
   ]))

   ->addOptimizer(new Pngquant([
       '--force',
   ]))

If you want to use another tool than the package supports out of the box, you can easily write your own optimizer. An optimizer is any class that implements the Spatie\ImageOptimizer\Optimizers\Optimizer interface. If you want to view an example implementation take a look at the existing optimizers that ship with the package.

Integration in other packages

Our image-optimizer is not the first package we wrote the revolves around handling images. There also our image package which makes modifying images very easy. And we have laravel-medialibrary which can associate all kinds of files (including images) with Eloquent models. And lastly we have Browsershot, which can turn any webpage into an image. Let’s take a look on how image-optimizer has been integrated in all of those.

Image

Using the image package you can manipulate an image like this:

Image::load('example.jpg')
    ->sepia()
    ->blur(50)
    ->save();

This creates a sepia version that is blurred. The package has many other available manipulations. Here’s how you can create an optimized version.

Image::load('example.jpg')
    ->sepia()
    ->blur(50)
    ->optimize()
    ->save();

Yea, just add the optimize method in the chain and you’re done. Easy right?

laravel-medialibrary

In laravel-medialibrary this is just as easy. Using that package you can define conversion profiles on your models. Whenever you associate a file with that model a derived file using that conversion profile is being generated. This is handy for creating thumbnails and such.

Here’s a quick example of such a conversion profile.

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia\Interfaces\HasMediaConversions;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;

class NewsItem extends Model implements HasMediaConversions
{
    use HasMediaTrait;

    public function registerMediaConversions()
    {
        $this->addMediaConversion('thumb')
              ->width(368)
              ->height(232)
              ->sharpen(10);
    }
}

Let’s add an image to the medialibrary:

$media = NewsItem::first()->addMedia($pathToImage)->toMediaCollection();

Besides storing the original item, the medialibrary will also create a derived image.

$media->getPath();  // the path to the where the original image is stored
$media->getPath('thumb') // the path to the converted image with dimensions 368x232

$media->getUrl();  // the url to the where the original image is stored
$media->getUrl('thumb') // the url to the converted image with dimensions 368x232

That’s a crash course into using medialibrary. But wait, we didn’t create an optimized version of that thumbnail. Let’s do that now. Under the hood all conversions are done by the aforementioned image package. So you can just use optimize function in your conversion profile.

    public function registerMediaConversions()
    {
        $this->addMediaConversion('thumb')
              ->width(368)
              ->height(232)
              ->sharpen(10)
              ->optimize();
    }

Boom done.

In the next major version of medialibrary we’ll automatically call optimize behind the screens for all image conversions. So you’ll get optimized conversion by default. We’ll add a nonOptimized method if you want to opt out of that. We haven’t introduced that behaviour in the current version because it’s breaking change.

Browsershot

Browsershot is a package that leverages headless Chrome to turn any webpage into an image. Here’s how to use it:

Browsershot::url('https://example.com')->save($pathToImage);

And here’s how to save an optimized version:

Browsershot::url('https://example.com')->optimize()->save($pathToImage);

In closing

I should mention that our optimize package is based upon another one by Piotr Śliwa. All the basic principles on how the package should work are inspired by Piotr’s work. The reason why we rewrote it is because his was not that easy to extend and did not use modern stuff such as Symfony’s Process component or PSR-3 compatible logging.

In this post I’ve mainly mentioned tools you can install locally, but there actually are a lot of SaaS solutions as well such as TinyPNG, Kraken.io, imgix.com and many many others. In this first release of our image-optimizer package I’ve mainly concentrated on supporting local optimizers. With remote optimizers you have to deal with slowness of the network and API keys and such. But I do recognize the value of those remote services. That’s why you’ll probably see some remote optimizers being referenced or included in package in the future. Here’s an issue on the repo where the first thoughts on that were being exchanged.

The package contains a few more features not covered by this blogpost. So check out image-optimizer on GitHub. I hope our tool can make your images smaller and your pages faster. If you haven’t already done so, check out our previous work in the open source space. Please send us a postcard if any of our stuff makes in into your production environment.

HTTP Tools Roundup

Curl is not your only tool when creating or testing out APIs. On her blog Lorna Jane Mitchell made a nice list of alternatives.

At a conference a few days ago, I put up a slide with a few of my favourite tools on it. I got some brilliant additional recommendations in return from twitter so I thought I’d collect them all in one place in case anyone is interested – all these tools are excellent for anyone working APIs (so that’s everyone!).

https://lornajane.net/posts/2017/http-tools-roundup

A list of podcasts

On his blog Left On The Web, Stefan Koopmanschap lists the podcasts he’s listening to. His selection contains both tech and non-tech podcasts.

I had sitting in travel not being able to do anything. Listening to music can help, but can end up also being frustrating. While I was working at Schiphol last year I got pointed to podcasts. Since then I’ve been really getting into listening to podcasts on my daily commute and it’s been making the trip a lot more fun… and useful.

Here is a random collection of podcasts that I’ve been listening to in the past year and a half, on many different subjects. My main problem right now is that it’s so many that I’m way behind on the episodes of most of these. Ah well, it’s still quite good content.

https://leftontheweb.com/blog/2017/07/01/a-list-of-podcasts/

Here are a few of my favourite podcasts:

North Meets South
In this relatively young podcast Jacob Bennett and Michael Dyrynda talk about the things that make them tick.

Twenty Percent Time
Daniel Coulbourne & Caleb Porzio weekly discuss a programming topic. They try to keep it to twenty minutes, but that doesn’t always work out that way 🙂

The Laravel News podcast
Besides North Meets South, Jacob and Michael also run another podcast focused on all things happening in the Laravel ecosystem.

Full Stack Radio
Adam Wathan & David Hemphill talk about how they are creating their products: Crondog & KiteTail

Voices Of The Elephant
In this podcast Cal Evans interviews people active in PHP community. It’s been a while since there was a new episode, but it’s still worthwhile to listen to.

The Changelog
Adam Stacoviak & Jered Santo weekly have a conversion with somebody from the open source community.

A programmer’s cognitive load

Brent Roose wrote down his thoughts around how things like fonts, spacing, docblock, … can influence the cognitive load of a programmer.

As a professional programmer, I’m reading and writing code on a daily basis. I’m working on new projects, doing code reviews, working with legacy code, learning documentation etc. Based on my own experience and that of colleagues, being a programmer often involves a lot more reading than actually writing code. Whether it’s your own code or that of others, when you open a file, you have to take it all in. You need to wrap your head around what’s going on, before you’re able to write your code. Doing this day by day, it’s important to find ways to make this process easy. To try and reduce this cognitive load as much as possible. Streamlining the way you take in code, will allow you to not only work faster and better; but also improve your mental state and mood.

https://www.stitcher.io/blog/a-programmers-cognitive-load

Visual debt is real.

Easily convert webpages to images using PHP

Browsershot is a package that can easily convert any webpage into a image. Under the hood the conversion is made possible new headless options in Chrome 59. In this post I’d like to show you how you can use Browsershot v2.

Here’s a quick example of how it can be used:

Browsershot::url('https://example.com')->save($pathToImage);

History

About three years ago I started working on my first package, called Browsershot. It can convert any webpage to an image. Under the hood PhantomJS was used to perform the transformation. Since it got released it did it’s job pretty well, but unfortunately PhantomJS recently has been abandoned.

A few weeks ago Chrome 59 got released. In that version some pretty cool features were introduced. One of them is the ability to take screenshots of a webpage. A recent version of Chrome probably is better in rendering a correct page then and abandoned version of PhantomJS. That’s why I decided to make a new major release of Browsershot. In this post I’d like to show you how you can use Browsershot v2.

Installing Chrome 59

In order to make use of Browsershot you must make sure that Chrome 59 or higher is installed on your system. On a Forge provisioned Ubuntu 16.04 server you can install the latest stable version of Chrome like this:

sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get -f install
sudo apt-get install google-chrome-stable

Browsershot has been tested on MacOS and Ubuntu 16.04. If you use another OS your mileage may vary.

Using Browsershot

Here’s the easiest way to create an image of a webpage:

Browsershot::url('https://example.com')->save($pathToImage);

Browsershot will make an education guess where Google Chrome is located. If on your system Chrome can not be found you can manually hint it’s location:

Browsershot::url('https://example.com')
   ->setChromePath($pathToChrome)
   ->save($pathToImage);

By default the screenshot will be a png and it’s size will match the resolution you use for your desktop. Want another size of screenshot? No problem!

Browsershot::url('https://example.com')
    ->windowSize(640, 480)
    ->save($pathToImage);

You can also set the size of the output image independently of the size of window. Here’s how to resize a screenshot take with a resolution of 1920×1080 and scale that down to something that fits inside 200×200.

Browsershot::url('https://example.com')
    ->windowSize(1920, 1080)
    ->fit(Manipulations::FIT_CONTAIN, 200, 200)
    ->save($pathToImage);

In fact, you can use all the methods spatie/image provides. Here’s an example where a greyscale image is created:

Browsershot::url('https://example.com')
    ->windowSize(640, 480)
    ->greyscale()
    ->save($pathToImage);

If, for some reason, you want to set the user agent Google Chrome should use when taking the screenshot you can do so:

Browsershot::url('https://example.com')
    ->userAgent('My Special Snowflake Browser 1.0')
    ->save($pathToImage);

In closing

The screenshot capabilities of Chrome are already quite good, but there’s a lot of room for improvement still. Right now there’s no way to specify where Chrome should save the screenshot (a problem that the package solves for you behind the scenes). In the DevTools there’s an option to take a screenshot of the whole length of the page. Unfortunately this isn’t possible with the current command line options.

I’m pretty sure the headless and screenshotting options will improve in future versions of Chrome. I intend to update Browsershot as soon as new features become available in Chrome.

Want to get started using Browsershot? Then head over to GitHub. Also take a look at the other packages our team has previously made.

Exposing Multiple Vue Components as a Plugin

In a new post on his blog Sebastian De Deyne, JavaScript (and all-round) wizard at Spatie, describes a technique to expose Vue components as a plugin.

We recently published a tabs package. Initially, users needed to register two components in order to create a tabular interface: Tabs, which acts as a container, and Tab, which defines a single tab and its contents in the interface.

Since developers are most likely going to use both components together, and there’s a fair chance that they’d want to register them globally like in the example, it made sense to provide some sort of auto-install option.

https://sebastiandedeyne.com/posts/2017/exposing-multiple-vue-components-as-a-plugin

Insights into Laravel package design

On the Bugsnag blog, Graham Campbell, wrote a guest post on the basics of creating a Laravel package. If you’ve ever wanted to create a package, this is a good starting point.

Laravel is a massively influential PHP framework, and its simple but powerful design means that it’s easy to utilize packages in your application. In this blog post we will look at the basics of creating and installing Laravel packages.

https://blog.bugsnag.com/designing-laravel-packages/