Introducing Crafty, One bundler to rule them all

Stéphane Goetz
Swissquote Tech Blog
5 min readApr 3, 2018

At Swissquote, our approach is to create small applications that are integrated together at runtime. You could consider this as microservices for frontend.

What does this mean? Application components can be independently updated by different teams.

But… this exposes a major challenge: how do we manage dozens of component webapps and maintain their tooling up to date?

I will try to explain you our approach to reduce this complexity, let me walk you through our process.

TL;DR

Crafty is a configuration tool. Its philosophy is to use the best tool for the job, provide optimal defaults and always provide a way to fine-tune the configuration to your exact needs if you don’t like the defaults.

Check the GitHub repository and Use Cases section to learn more about it

The frontend tooling challenge

Photo by Barn Images on Unsplash

As engineers, we always recommend to “use the right tool for the job” and in recent years in the frontend world, it has become more and more complicated to keep track of what the right tool is.

Let’s take a few use cases where I present one tool for the job.

Compile CSS Files

  • Gulp + PostCSS with a handful of plugins
  • Create a Gulpfile and you’re good to go.

Bundle ES2015+ JavaScript for a Single Page App

  • Take Webpack + babel-loader + babel-preset-env

A TypeScript library shipped as an UMD module and for Node.js

  • Rollup + TypeScript

We see that for three quite common use cases, we’ve used three different bundlers/task runners. Those tools and many others are wonderful and push the web developers community forward but the possibilities are endless.

Configuration and updates

Configuring build tools and keeping them up-to-date is another challenge.

For one part, each tool has its own configuration file : .babelrc , .eslintrc, tsconfig.json, webpack.config.js, .browserslistrcto name just a few. It can also be configured directly in package.jsonor it can receive its configuration when initialized in another file, for example you can configure Babel directly from Webpack’s configuration file.

Even better, the configuration format for a single tool can be different when configured directly or used through another tool.

You’ll also have to make sure that all your plugins are compatible with your tools. Is this plugin compatible with PostCSS 5 or PostCSS 6 ? Is that loader compatible with Webpack 4?

You can either configure your tools once and never update or you’ll have to do the update dance every once in a while to make sure that all your plugins and loaders are still compatible with each other and at the latest version.

The biggest challenge however is to do the same in multiple projects, let’s say you have 50 applications, tons of libraries and you want to keep their configurations up-to-date. What are the options ?

  • Use a boilerplate ? Sounds cool, but a boilerplate is nice when creating the project, not when it has to live for a long time.
  • Have a recurring task in your calendar to take an hour or two to update the dependencies? Doesn’t feel really agile and doesn’t scale to a larger number of projects.
  • A configuration tool. A single dependency to include in your project which provides you with all the tools and configuration needed for your build.

The tale of Swissquote’s configuration tool

We started more than two years ago with a series of gulp tasks bundled together in an npm package (creatively named sq-gulp), first it was only for CSS and JavaScript concatenation, but we soon started to support Babel, TypeScript, Webpack, Image compression, linting and many small utilities.

Soon it became really complicated to maintain and very heavy to install. Some teams refused to use it as it introduced too many additional dependencies for what they actually needed.

That’s the moment we decided to do like many other JavaScript tools did before us: Make it modular.

That’s how Crafty was born.

What is Crafty ?

Swiss army knife — picture by Victorinox

Crafty is a configuration tool. Its philosophy is to use the best tool for the job, provide optimal defaults and always provide a way to fine-tune the configuration to your exact needs if you don’t like the defaults.

Its goal is to help you keep the time you take configuring your builds in check, be it for one or for 60 projects.

Crafty is modular, all main features are in their own plugin, we identify two types of plugins:

  • Runners like Webpack and Gulp, each with their own API to declare new tasks
  • Presets like Babel and PostCSS which provide configuration for your bundles.

A Bundle is the way for you to configure an input, the runner it has to use and where its output has to go.

An example with one Runner, one Preset and one Bundle

With three dependencies npm install @swissquote/crafty @swissquote/crafty-preset-babel @swissquote/crafty-runner-webpack --save and the following configuration :

You get the following features:

  • Compile js/index.js using Webpack into an umd module at dist/app.min.js
  • Compress the compiled code using UglifyJS
  • Sourcemaps are enabled for both development and production builds
  • Use Babel and babel-preset-envto compile all your JavaScript files.
  • Use ESLint to lint all your source files using babel-loader or with the npx crafty jsLint js/**/*.js command
  • Build once using npx crafty run or watch for changes and rebuild automatically using npx crafty watch

Overview of our Presets and Runners

You can create your own Presets and Runners, but to get started easily, we created 7 presets and 3 runners

Three runners

  • Webpack for your webapps needs
  • Rollup for your libraries
  • Gulp for your assets if they aren’t embedded in Webpack

Preset to Compile JavaScript and TypeScript

  • A Babel + ESLint preset.
  • A TypeScript + TSLint preset.

These two presets work with our Webpack, Rollup and Gulp runners you can decide in the configuration which one to use for each bundle.

To compile your styles

  • A PostCSS + Stylelint preset that comes with a selection of plugins, works with Webpack and Gulp.

A preset for your tests

  • Jest, works automatically with the Babel and TypeScript presets.

And various utility presets

  • A preset to compress Images.
  • A preset to compile your assets in Maven, allowing you to set the destination automatically in the right target folder.
  • A React preset, to configure React Hot Module Replacement for Webpack, and test utilities for the Jest preset.

You can use any combination of Presets and Runners in your projects. You can create your own if you want to override the default configuration and share it across multiple projects.

Have a look at our Use Cases section for some usage examples.

You can also check out the GitHub repository if you want to have a look under the hood.

--

--