@sumup/foundry

A toolkit for JavaScript + TypeScript applications by SumUp.

Usage no npm install needed!

<script type="module">
  import sumupFoundry from 'https://cdn.skypack.dev/@sumup/foundry';
</script>

README

Foundry

NPM version Code coverage License Contributor Covenant

A toolkit that makes it a breeze to set up and maintain JavaScript + TypeScript applications. Foundry has presets for ๐Ÿ” linting, ๐Ÿš€ releasing, ๐Ÿค– continuous integration (CI), and ๐Ÿ–‡๏ธ templates and currently supports React, Emotion, Jest, Cypress, Node and Testing Library.

Table of contents

Getting Started

Installation

Foundry needs to be installed as a dev-dependency via the Yarn or npm package managers. The npm CLI ships with Node. You can read how to install the Yarn CLI in their documentation. Foundry requires Node v12+.

Depending on your preference, run one of the following.

# With Yarn
$ yarn add --dev @sumup/foundry

# With npm
$ npm install --save-dev @sumup/foundry

Initialization

Foundry exposes customizable configuration presets for the CLI tools it supports. To make use of these presets, you need to initialize a configuration file for each tool you would like to use. This is done with the init command.

# With Yarn
$ yarn run foundry init

# With npm
$ npx foundry init

Foundry will launch an interactive prompt to ask you questions about your project, such as in which language it is written, which frameworks it uses, or whether you are planning to open source it. Once you have answered all questions, Foundry will write the config files (don't worry, it asks before overwriting existing files) and will add scripts to your package.json file to conveniently run the tools.

Alternatively, you can pass your answers to the init command directly as flags. This is useful for environments such as CI where interactive prompts cannot be used. Here is an overview of all available options (you can view this help menu by running npx foundry init --help):

--presets, -p       A preset configures a group of tools that solve a common
                    problem  [array] [options: "lint", "release", "templates", "ci"]
--language, -l      The programming language in which the project is written
                                               [options: "TypeScript", "JavaScript"]
--environments, -e  The environment(s) in which the code runs
                                                [array] [options: "Node", "Browser"]
--frameworks, -f    The framework(s) that the project uses
                                       [array] [options: "React", "Emotion", "Jest"]
--ci                The CI platform the project uses     [options: "github-actions"]
--openSource, -o    Whether the project is open-source                     [boolean]
--publish           Whether to publish to NPM                              [boolean]
--configDir, -c     The directory to write the configs to    [string] [default: "."]
--help              Show this help menu                                    [boolean]

Configuration

All config files that are generated by Foundry follow the same format. They import a configuration function, optionally call it with an options object and/or overrides, and export the result. Here's an example:

module.exports = require('@sumup/foundry/<tool>')(options, overrides);

// Example for .eslintrc.js:
module.exports = require('@sumup/foundry/eslint')(
  {
    language: 'TypeScript',
    frameworks: ['React', 'Emotion'],
  },
  {
    rules: {
      'emotion/jsx-import': 'error',
    },
  },
);

The options for each tool are documented below.

The overrides are merged with Foundry's default configuration after the options have been applied. The overrides follow each tool's configuration schema, please refer to their official documentation.

Presets

A preset includes the configurations and scripts that are needed for a certain task.

๐Ÿ” Lint

Check code for syntax errors and format it automatically. The preset adds the following scripts to your package.json:

  • lint: check files for problematic patterns and report them
  • lint:fix: same as lint, but also try to fix the issues
  • lint:ci: same as lint, but also save the report to a file

The preset includes the following tools:

Eslint

ESLint identifies and fixes problematic patterns in your JavaScript code so you can spot mistakes early.

Eslint's configuration options:

Name Type Options Default
language string 'TypeScript', 'JavaScript' 'TypeScript'
environments array 'Browser', 'Node' []
frameworks array 'React', 'Emotion', 'Jest', 'Cypress', 'Testing Library' []
openSource boolean true, false false

Prettier

Prettier is our code formatter of choice. It makes all our code look the same after every save.

Prettier currently has no configuration options.

lint-staged

lint-staged is a tool for running linters on files staged for your next commit in git. Together with Husky (see below) it prevents bad code from being committed.

lint-staged's configuration options:

Name Type Options Default
language string 'TypeScript', 'JavaScript' 'TypeScript'

Husky

Husky makes setting up git hooks very easy. Whenever someone installs your project, Husky will automatically set up git hooks as part of its postinstall script.

Husky currently has no configuration options.

๐Ÿš€ Release

Automatically generate release notes and (optionally) publish to NPM. The preset adds the following script to your package.json:

  • release: release and publish a new version

The preset includes the following tools:

semantic-release

semantic-release automates the whole package release workflow including determining the next version number, generating the release notes, and publishing the package.

semantic-releases's configuration options:

Name Type Options Default
publish boolean true, false false

๐Ÿค– Continuous Integration (CI)

Validate the code on every push using the ๐Ÿ” linting preset (if configured). The supported CI providers are:

  • GitHub Actions builds, tests, and deploys your code right from GitHub.

๐Ÿ–‡๏ธ Templates

Generate boilerplate code e.g. for React components. The preset adds the following script to your package.json:

  • create:component: generate the files for a React component

The preset includes the following tool:

Plop

Plop generates common files from templates. This is very helpful when creating similar files repeatedly and reduces the boilerplate you have to write as a developer.

Plop's configuration options:

Name Type Options Default
language string 'TypeScript', 'JavaScript' 'TypeScript'
templateDir string A path relative to the location of plopfile.js '.'

Custom templates

โญ This is an advanced use case.

Plop uses Handlebar templates to generate the files. If you'd like to override a built-in template, you can specify a custom template directory (see config options above). Plop will first check if a custom template exists, otherwise, it will fall back to the default template.

To see which variables are available for use in a Handlebars template, have a look at the default templates.

Running a tool

Foundry manages all supported tools for you and exposes them via the run command. As an example: to run ESLint through Foundry, execute:

# With Yarn
$ yarn foundry run eslint src

# With npm
$ npx foundry run eslint src

Here, src is the folder you want ESLint to check. Note that you can use any of the command-line flags and arguments supported by ESLint and other tools. Foundry forwards them so they get handled by the tool. For example, to have ESLint fix your linting errors, run npx foundry run eslint --fix src.

Why?

TLDR

Creating and maintaining a JavaScript project can be very tedious. There are tools, configurations, dependency management, and boilerplate. With Foundry, you can fix all of that with a single dependency. It lints, creates files, and keeps the tools up to date. And the best part? You can still get down and dirty with your configurations. But only if you want.

The problem

Setting up and maintaining a complex JavaScript project can be very tedious. There are many different dependencies to install (linters, testing frameworks, bundlers) and configurations to set up. Once you have a running project, you end up writing a lot of boilerplate code when creating commonly used files. For example, a React component might come with a spec file (test), a Storybook file (isolated component development), and a service for handling business logic.

It gets much, much worse when you have several (many?) projects. What happens when there is a breaking change in a tooling dependency? What if a team decides you need to add a new linting rule? Nobody wants to go through every project and update those files all the time. And who knows, if they are even the same? Syncing configurations is terrible. Or think about that new engineer you are onboarding. How are they supposed to know how you structure your project, how your components are supposed to look, which files they need to create?

You might think you could solve these issues with a boilerplate repository and some snippets or templates. But you cannot. At least the maintenance problem will not go away.

The solution

Toolkits are a way to mitigate these kinds of problems. They encapsulate as much as possible of the toolchain into a single dependency and expose it through a CLI. Doing so gets you the following, probably more!

  • You don't need to set up any tooling when creating a new project. Bootstrap it and start coding. :rocket:
  • When you need to update a tooling dependency or change a configuration, do it in the toolkit and update the toolkit dependency in your projects — preferably in an automated fashion. That's it. :sparkles:
  • Make the way you write JavaScript more consistent. All your projects will work exactly the same. :straight_ruler:
  • Easy onboarding. New colleagues will be able to get productive much more quickly. ๐Ÿ™‡โ€โ™‚๏ธ
  • The number of direct dependencies becomes much smaller and your package.json shorter. :spider_web:

But what makes Foundry different?

We were inspired by many toolkit projects, such as create-react-app and kcd-scripts. These projects are opinionated, and so is Foundry. But Foundry is different, in our opinion, because:

  • It encapsulates tools and their configuration, but also lets you get down and dirty with the configs in your project.
  • It merely proxies the tools you use on a CLI level instead of talking to them through their Node.js APIs. We literally execute the binaries and forward any options you provided.

So please, go ahead and try it.

Code of Conduct (CoC)

We want to foster an inclusive and friendly community around our Open Source efforts. Like all SumUp Open Source projects, this project follows the Contributor Covenant Code of Conduct. Please, read it and follow it.

If you feel another member of the community violated our CoC or you are experiencing problems participating in our community because of another individual's behavior, please get in touch with our maintainers. We will enforce the CoC.

Maintainers

About SumUp

SumUp logo

It is our mission to make easy and fast card payments a reality across the entire world. You can pay with SumUp in more than 30 countries already. Our engineers work in Berlin, Cologne, Sofia, and Sฤo Paulo. They write code in JavaScript, Swift, Ruby, Go, Java, Erlang, Elixir, and more. Want to come work with us? Head to our careers page to find out more.