Debugging your Webpack build time with Speed Measure Plugin

If your Webpack build is slow, you can use the Speed Measure Plugin for Webpack to figure out where time is being spent.
Note that at time of writing, Webpack 5 seems unsupported. It works on Webpack 4, though.

Wire it into your application as described in the library's documentation:

  1. Hook into your environment file, e.g. config/webpack/development.js and instead of exporting your Webpack config,...

Webpacker: Loading code on demand

Sometimes you want to load code on demand. For instance, when a a large library is only used on a single screen, this library should only be loaded for that screen. It should not blow up the bundle size for all screens.

You can load code on demand by using import() as a function (with parentheses) instead of using it as a keyword import (without parentheses). The import() function returns a promise with the exported variables:

let exports = await import('large-library')

console.log("A named export is ", exports.exportedName)
c...

When does Webpacker compile?

Webpack builds can take a long time, so we only want to compile when needed.

This card shows what will cause Webpacker (the Rails/Webpack integration) to compile your assets.

When you run a dev server

While development it is recommended to boot a webpack dev server using bin/webpack-dev-server.

The dev server compiles once when booted. When you access your page on localhost before the initial compilation, the page may load without assets.

The ...

Converting ES6 to ES5 on the command line

I use the TypeScript compiler for this, since its output is more minimal than Babel's.

The following will transpile all src/*.js files into a file build.js:

npm install typescript
npx tsc src/*.js --target ES5 --allowJs --outFile build.js

The output will only transpile ES6 syntax. It will not include any polyfills for missing APIs.

Capybara: Preventing server errors from failing your test

When your Rails application server raises error, Capybara will fail your test when it clears the session after the last step. The effect is a test that passes all steps, but fails anyway.

Capybara's behavior will help you to detect and fix errors in your application code. However, sometimes your application will explode with an error outside your control. Two examples:

  • A JavaScript library references a source map in its build, but forgets to package the source map
  • CarrierWave cleans up an upload or cache file after the record was delet...

Capybara: Pretending to interact with the document

Browsers blocks abusable JavaScript API calls until the user has interacted with the document. Examples would be opening new tab or start playing video or audio.

E.g. if you attempt to call video.play() in a test, the call will reject with a message like this:

NotAllowedError: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD

Workaround

To pretend document interaction in a test you can create an element, click on it, and remove the element again. This unblocks the entire JavaSc...

makandra/capybara-lockstep

capybara-lockstep can help you with flaky end-to-end tests:

This Ruby gem synchronizes Capybara commands with client-side JavaScript and AJAX requests. This greatly improves the stability of a full-stack integration test suite, even if that suite has timing issues.

Ruby: Generating and parsing JSON, or: understanding JSON::ParserError "unexpected token"

json is part of the standard library of Ruby and deals with JSON, obviously. As you know, JSON is the string format that represents simple data structures. Ruby data structures that resemble Javascript objects can be serialized to JSON with #to_json. These can be restored from a JSON string with JSON.parse().

So what could go wrong here?

JSON.parse("a".to_json)

It will raise JSON::ParserError (784: unexpected token at '"a"'). But why?

Generating JSON vs serializing objects

J...

Regular Expressions: Quantifier modes

When you repeat a subpattern with a *, + or {...} operator, you may choose between greedy, lazy and possessive modes.

Switching modes may affect the result and performance of your regular expressions. In the worst case, an ill-suited mode may make your regular expression so slow that it can DoS your application (Examples are the ActiveRecord's PostgreSQL CVE-2021-22880 or the [Cloudflare outage 2019](https://makandracards.com/makandra/77515-regular-expressions-excessive-backtracking...

Some tips for upgrading Bootstrap from 3 to 4

Recently I made an upgrade from Bootstrap 3 to Bootstrap 4 in a bigger project. Here are some tips how to plan and perform such an upgrade. The effort will scale with the size of the project and its structure. If your stylesheets already follow strict rules, it may take less time to adapt them to the new version.

Preparation

There are several gems and libraries that works well with bootstrap or provide at least stylesheets/plugins to easily integrate the bootstrap theme. But very often they only work with specific version or are no long...

WYSIWYG with Action Text

Rails 6 includes a WYSIWYG editor, Action Text. It works out of the box quite well, but chances are that you want to add some custom functionality. This card contains some tips how to achieve this.

Setup

Basically, follow the guide in the Rails documentation. The automated script may not work with the way webpacker is configured in your project, but it should be easy to fix.

If you don't want the default c...

Git: Parsing large diffs as a human

I just finished migrating a project from the Asset Pipeline to Webpacker, this is what my diff to master looks like:

5.825 files changed, 44.805 insertions(+), 529.948 deletions(-)
warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 5134 and retry the command.

There is no way me or my peer reviewer is able to parse 500k+ lines of code. Fortunately, git has ...

How to build a fully custom TinyMCE 5 dialog

TinyMCE is a WYSIWYG editor which is quite customizable.


  1. Add a custom button to the tinyMCE toolbar and tell tinyMCE to open a dialog with the route to your dialog's view.
tinymce.init({
  // ...
  toolbar: 'myCustomButton',
  setup: function(editor) {
      editor.ui.registry.addButton('myCustom Button', {
        ...

A few recent CSS properties

  • Feature Queries (Edge 12+): Similar to @media queries, @supports blocks can be scoped to browsers that support a given declaration. There is CSS.supports() to do the equivalent in Javascript.

  • backdrop-filter (Edge 17+, but not FF): Applying filters to what is visible through an element.

  • [touch-action](https://d...

Configuring Webpacker deployments with Capistrano

When deploying a Rails application that is using Webpacker and Capistrano, there are a few configuration tweaks that optimize the experience.

Using capistrano-rails

capistrano-rails is a Gem that adds Rails specifics to Capistrano, i.e. support for Bundler, assets, and migrations. While it is designed for Asset Pipeline (Sprockets) assets, it can easily be configured for Webpacker. This brings these features to the Webpacker world:

  • Automatic removal of expired assets
  • Manifest backups

Passive event listeners may speed up your scroll and touch events

Scroll and touch event listeners tend to be computationally expensive as they are triggered very often. Every time the event is fired, the browser needs to wait for the event to be processed before continuing - the event could prevent the default behavior. Luckily there is a concept called passive event listeners which is supported by all modern browsers.

Below are the key parts quoted from WICG's explainer on passive event listeners. See [this demo video](https://www.youtube.com/watch?v=NPM6172...

Service Worker series by GoMakeThings

Learn how to create offline applications with service workers.

  1. The amazing power of service workers
  2. Writing your first service worker with vanilla JS
  3. Saving recently viewed pages offline with service workers and vanilla JS
  4. Offline first with service workers and vanilla JS
  5. Improving web font performance with service workers
  6. How to set an expiration date for items in a service worker cache
  7. How to update a service worker
  8. How to trigger a service worker function from the front end with vanilla JS
  9. How to immediately ...

Chrome Lighthouse

Chrome has a built-in utility to check performance and accessibility (and more) of your web app: Lighthouse.

Open the Developer Tools and go to the lighthouse tab:

Image

Then you'll see some suggestions on how to improve your site.
This is cool, because you can even use it with non-public pages or your development environment (but be aware that some settings we're using for development, like not minifying JS and CSS files, might ruin your stats)...

Webpacker: Disable source maps

You can do this per environment, e.g. in config/webpack/test.js:

const environment = require('./environment')
const config = environment.toWebpackConfig()
config.devtool = 'none'
module.exports = config

How to migrate CoffeeScript files from Sprockets to Webpack(er)

If you migrate a Rails application from Sprockets to Webpack(er), you can either transpile your CoffeeScript files to JavaScript or integrate a CoffeeScript compiler to your new process. This checklist can be used to achieve the latter.

  1. If you need to continue exposing your CoffeeScript classes to the global namespace, define them on window directly:
-class @User
+class window.User
  1. Replace Sprocket's require statement with Webpacker's...

Vortrag: Content Security Policy: Eine Einführung

Grundidee

CSP hat zum Ziel einen Browser-seitigen Mechanismus zu schaffen um einige Angriffe auf Webseiten zu verhindern, hauptsächlich XSS-Angriffe.

Einschub: Was ist XSS?

XSS = Cross Site Scripting. Passiert wenn ein User ungefiltertes HTML in die Webseite einfügen kann.

<div class="comment">
  Danke für den interessanten Beitrag! <script>alert('you have been hacked')</script>
</div>

Rails löst das Problem weitgehend, aber

  • Programmierfehler weiter möglich
  • manchmal Sicherheitslücken in Gems oder Rails

Lösungsid...

Automatically validating dependency licenses with License Finder

"Open-source software (OSS) is great. Anyone can use virtually any open-source code in their projects."

Well, it depends. Licenses can make things difficult, especially when you are developing closed-source software. Since some OSS licenses even require the employing application to be open-sourced as well (looking at you, GPL), you cannot use such software in a closed-source project.

To be sure on this, we have developed a project-level integration of Pivotal's excellent [license_finder](https:/...

Shorthand function properties in ES6

Here is an ES5 object literal with two string properties and a function property:

let user = { 
  firstName: 'Max',
  lastName: 'Muster',
  fullName: function() { return this.firstName + ' ' + this.lastName }
}

user.fullName() // => 'Max Muster'

In ES6 we can define a function property using the following shorthand syntax:

let user = { 
  firstName: 'Max',
  lastName: 'Muster',
  fullName() { return this.firstName + ' ' + this.lastName }
}

user.fullName() // => 'Max Muster'

We can also define a gette...

The HTML5 video element

# Basic HTML example
<video poster="preview_image.png" controls>
  <source src="or_here.webm" type="video/webm" />
  <source src="alternative_if_browser_cant_pay_first_source.mp4" type="video/mp4" />
  <track src="optional_subtitles.vtt" kind="subtitles" srclang="de" label="Deutsch" default>
</video>

# Javascript API (notable methods and properties)
video = document.querySelector('video')
video.play()
video.pause()
video.load() // Reset to the beginning and select the best available source
video.currentSrc // The selected source
video.c...