Skip to main content

Developer handbook

The development branch is next. This is where pull requests must be made and, once approved, it will be automatically released in the test environment (staging).

After being reviewed, tested and approved, the pull requests must be compared and merged with the main branch, which will be released in the production environment.

The fixed branches:

  • next is the development branch (default)
  • main is the production and final version branch

Tangram is built using a collection of packages, all made in the same Git repository, called monorepo.

We use two tools to help us manage installation dependencies and publish packages:

  • Yarn workspaces for handling dependencies across all packages
  • Lerna to publish packages, mark versions, and more

Before installing dependencies, it is necessary to configure .npmrc on the machine or project, including jFrog credentials. For more information, access our wiki.

To install all dependencies in this project, you need to install Yarn and run the following command in the terminal:

yarn install

This will install all the dependencies of each package in the project. In addition, it is possible to connect the packages that we are developing.

yarn setup

This way the packages and dependencies will be linked. Also, it will build each package.

To create all the files in the package, run the following command:

yarn build

To create a new component, run the create-component script, to generate the initial files:

yarn create-component

You should now be ready to start contributing to Tangram!

Documentation

Playground

We use the Ladle playground tool. To start, you can run the following command:

yarn playground start

Docusaurus

To start Docusaurus with public documentation, you can run the following command:

// docs in english
yarn docs start
// docs in portuguese
yarn docs start:br

Common tasks

Some of the tasks you may need to perform:

Common tasks
CommandUsage
yarn buildUses lerna to run the build script in each package
yarn cleanResets the state of the project by removing all node_modules and running the clean script in each package
yarn formatFormat files using Prettier and check if files have been formatted
yarn testRun test on files in each package project
yarn lintRun eslint on files in the project
lerna add <dependency-name> --scope=<package-name>To add some dependency of in a specific package (workspace). Use -D to add in dev mode

Commit conventions

This project follows a structured format for writing commit messages. The main benefit is that we can use these details to automatically generate things like changelogs, for example, as well as clarify what changes they correspond to when we look at our Git history.

We are based on the pattern created by the AngularJS team.

Message format

tip

Portions of this section have been duplicated from the AngularJs commit conventions.

Each commit message consists of a header, a body and a footer. The header has a specific format that includes a type, a scope and a subject:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

The header is required and the header scope is optional. There are some validation rules that we also apply:

  • The header must always be fewer than 72 characters
  • Any line in the commit body must be fewer than 100 characters

Many of these rules are to help integrate git with common tools. We verified this commit format using a tool called commitlint.

Type

Must be one of the following:

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation only changes
  • test: Adding missing tests or correcting existing tests
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • revert: A code change that reverses a previous commit
  • chore: Changes in build process, tools, dependencies (package.json for example)

Subject

The subject contains a succinct description of the change:

  • use the imperative, present tense: "change" not "changed" nor "changes"
  • don't capitalize the first letter
  • no dot (.) at the end

Body

Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.

The footer should contain any information about Breaking Changes. Breaking Changes should start with the word BREAKING CHANGE: with a space or two newlines.

Examples

Feature (feat)
// Adding new functionality to a piece of code is considered a feature.
// This can be seen as extending an existing API
- function MyComponent({ propA }) {
+ function MyComponent({ propA, propB }) {
// ...
}
Bug fix (fix)
// Updating an implementation to correct a fault in the existing code
// is considered a bug fix
function add(a, b) {
- return a - b;
+ return a + b;
}

Packages

These are the project packages:

  • @resultadosdigitais/tangram-components;

    • Located in packages/components
    • Responsible for ReactJS components
  • @resultadosdigitais/tangram-react-icons

    • Located in packages/react-icons
    • Store all SVG icons and build them as React Icons
  • @resultadosdigitais/tangram-design-tokens

    • Located in packages/design-tokens
    • Stores all design tokens
  • @resultadosdigitais/tangram-react-datepicker

    • Located in packages/react-datepicker
    • Stores all DatePicker components

Coding style

ReactJS components

It is important to maintain a standard for writing our components, mainly due to the amount of components we will have, to maintain a standard that allows us to read and modify more easily.

Exporting components

The developed components needs to be exported both at the main entry point and in the entry folder of each component.

1. Main entry point

Export the component at the main entry point located in packages/components/src/index.js:

export { default as Component } from './Component';
export * from './Component';

With that is possible to access the component at the package using it.

import { Component } from '@resultadosdigitais/tangram-components';
2. Entry folder

Export the component folder to make the include only what is needed in packages/components/src/Component/index.js:

export { default } from './Component';
export { default as SubComponent } from './SubComponent';

With that it is possible to access the component folder and avoid to include all components in the bundle.

import Component

Export enumerators

danger

It's just that it's important to map the enums to the components that need them, rather than referencing a default value for all components, as this helps us avoid problems with changing these values. Therefore, even if other components share the same values, it is valid to map these values to your component.

We expose enumerators as a utility to help us with implementation to prevent us from providing a non-existent value. Note that the enumerators are written in plural when we export it, and the prop is written in singular.

const Button = ({ kind }) => {
// ... component code
};

// In the plural
Button.kinds = {
default: KINDS.DEFAULT,
primary: KINDS.PRIMARY,
success: KINDS.SUCCESS
};

Button.propTypes = {
// In the singular
kind: PropTypes.oneOf([
Button.kinds.default,
Button.kinds.primary,
Button.kinds.success
])
};

Example of the enumerators in the implementation with the new definition.

<Button kind={Button.kinds.primary}>Action</Button>

Files and folders

@resultadosdigitais/tangram-components

They are in the packages/components/ folder and we also have an entry point located in /src/index.js that exports all components:

export { default as Button } from './Button';
  • All components belong in /src in their own folder
  • Name files and folders using the singular form, not the plural
  • There are exceptions that need to be dealt with components whose name makes sense in the plural, for example: Tabs
...
Button
- Button.test.js
- Button.js
- constant.js
- index.js
- ...
  • Button.test.js: File with component tests
  • Button.js: Component code with style inside (styled-components)
  • constant.js: Responsible for storing the constants related to the component
  • index.js: Entry point to export the component
  • config.js: Responsible for storing settings and auxiliary functions

The helper folder, located in /src/helper, is responsible for storing all common settings, functions, hooks, etc.

@resultadosdigitais/tangram-react-icons

danger

When adding a new icon remove all fill fill="#000" values within each SVG. This value is automatically added by icon scripts in React.

All icons belong to packages/react-icons/svg in their own folder. Name files using the singular form, not the plural.

- align-center.svg
- align-justify.svg
- ...

All configuration related to build are in packages/react-icons in the following files:

- svgr.config.js
- babel.config.js
- rollup.config.js

@resultadosdigitais/tangram-design-tokens

All tokens belong in packages/design-tokens/src in the following files:

- base.json
- theme.json
- index.js

All configuration related to build are in packages/design-tokens/tasks.

Pull request

Labels

Pull requests must be labeled following FrontHub Lib Flow to indicate what kind of change it is. You can add more than one if needed.

Make sure to include the label version:release in the pull request if a release has to be published.

Make sure all breaking change changes are correctly tagged with version:major.

Issues

If your pull request is solving an issue, you should link the issue to your pull request request.

Deploy

Staging

Open a pull request for the next branch in order to deploy the changes, this way Circle CI will start the deployment to AWS, and when the process is finished the result will be displayed in Tangram staging

If a new version has to be released, a canary release will be made while the PR is still open if the version:release label has been applied. Simply merge the PR with the label if a pre-release needs to be published. Otherwise, simply remove the label before merging.

Production

The production deploy runs whenever a branch is merged into the main branch. Circle CI will start the deployment to AWS and when the process is finished the result will be displayed in Tangram.

To publish a new release just add one of the version labels and the version:release label in the pull request.

Publishes and releases

Final versions

Publishing a new release

  • Open a pull request from the branch origin/next to the origin/main
  • Add the label version:release
  • Await for the reviewers approval
  • Merge the pull request

Next versions

Make shure to test the new release! Is possible to publish a canary version or publish a pre-release when merging a pull request in the feature branch next.

A pull request opent to the next branch and with the version:release label, will publish a canary verion and publish a pre-release when the PR it's merged.

Do not forget to remove the label version:release in case it just needs to release canary for testing and not release a version on merge.

In case you forgot to add a label, we have two suggestions:

  • Find the last pull request, add the missing version:release and run again the CI's pipeline.
  • Open a new pull request with the label version:release, await for the CI to publish a canary and close the pull request.

GitHub, like other services, doesn't allow you to create a pull request without at least one commit more than one base branch. To solve this it is necessary to create an extra commit:

git checkout -b empty-release --track origin/main
git commit --allow-empty -m "Release review"
git push origin empty-release

FAQ

How do I install a dependency?

tip

It's important to keep common dependencies at the root and let Lerna manage them. It provides higher installation performance.

  • To install a common dependency for all packages, you can run yarn add -W <dependency-name>
  • To install a dependency for an only package, you can run lerna add <dependency-name> --scope=<package-name>
    • Example: lerna add -D lodash --scope=@resultadosdigitais/tangram-components

How do I add a new icon to react-icons lib?

tip

The icon needs to be in svg format and, if it has more than one word in its name, they must be separated with a hyphen.

  • After adding the new icon to the react-icons/svg directory, you can run yarn build inside react-icons to create the component
  • When opening the pull request, select the label version:release, to generate a canary, making it possible to test the code in staging, in order to verify if the new icon was properly added to the docs.

Feedback