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:
Command | Usage |
---|---|
yarn build | Uses lerna to run the build script in each package |
yarn clean | Resets the state of the project by removing all node_modules and running the clean script in each package |
yarn format | Format files using Prettier and check if files have been formatted |
yarn test | Run test on files in each package project |
yarn lint | Run 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
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.
Footer
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
// 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 }) {
// ...
}
// 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
- Located in
@resultadosdigitais/tangram-react-icons
- Located in
packages/react-icons
- Store all SVG icons and build them as React Icons
- Located in
@resultadosdigitais/tangram-design-tokens
- Located in
packages/design-tokens
- Stores all design tokens
- Located in
@resultadosdigitais/tangram-react-datepicker
- Located in
packages/react-datepicker
- Stores all DatePicker components
- Located in
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
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 testsButton.js
: Component code with style inside (styled-components)constant.js
: Responsible for storing the constants related to the componentindex.js
: Entry point to export the componentconfig.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
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 theorigin/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 acanary
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?
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
- Example:
How do I add a new icon to react-icons lib?
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 runyarn build
insidereact-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.