You want to help us enable Skyscanner to create beautiful, coherent products at scale? That's awesome! ❤️
By contributing your code, you agree to license your contribution under the terms of the APLv2.
All files are released with the Apache 2.0 licence.
If you are adding a new file it should have a header comment containing licence information:
Show/hide licence header
Backpack - Skyscanner's Design System
Copyright 2018 Skyscanner Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Conventions and squad decisions are kept in the decisions folder. We recommend familiarising yourself with these.
Backpack is developed using Node, using the following versions:
LTS/Carbon
(Node ^8.12.0)^6.4.1
(npm)
This is enforced using a pre-install hook that calls out to ensure-node-env.
If you use nvm or nave to manage your Node environment, Backpack has built-in support for these. Just run nvm use
or nave auto
to install the correct Node version.
To install npm, use npm install --global npm@^6.4.1
.
Skip this section if you don't intend to develop React Native components.
iOS
Install XCode from the App Store. Once installed, open it and accept the licence agreement. You're free to close it after that.
We use Cocoapods to install some iOS-specific dependencies. Cocoapods uses Ruby, so you'll need to install that too. rbenv and rvm are both good ways to get Ruby. The version of Ruby you'll need is specified in native/ios/.ruby-version
.
Once you have Ruby, install Bundler with gem install bundler
.
Android
Get Homebrew if you don't already have it.
Install Watchman with brew install watchman
, then install Java 8 with brew tap caskroom/versions && brew cask install java8
.
Get Android Studio with brew cask install android-studio
. Once installed, open it and a setup wizard will guide you through installing lots of extra things like the Android SDK (choose Standard installation). You may be asked for your password during this. You're free to close Android Studio once this is done.
Add an environment variable pointing to the SDK location to your ~/.bash_profile
(or similarly used file):
echo "export ANDROID_HOME=\"$HOME/Library/Android/sdk\"" >> ~/.bash_profile
echo "export ANDROID_SDK_ROOT=\"$HOME/Library/Android/sdk\"" >> ~/.bash_profile
source ~/.bash_profile
Accept the SDK licences:
$ANDROID_SDK_ROOT/tools/bin/sdkmanager --licenses
Download Android system images for the minimum and targeted API levels. Note that you may get a warning about a .cfg
file not being present. You're safe to ignore this.
$ANDROID_SDK_ROOT/tools/bin/sdkmanager "system-images;android-27;google_apis;x86"
$ANDROID_SDK_ROOT/tools/bin/sdkmanager "system-images;android-21;google_apis;x86"
Create Android Virtual Devices (AVDs):
$ANDROID_SDK_ROOT/tools/bin/avdmanager create avd --name "bpk-avd" --package "system-images;android-27;google_apis;x86" --device "pixel" && cp native/android/bpk-avd.ini ~/.android/avd/bpk-avd.avd/config.ini
$ANDROID_SDK_ROOT/tools/bin/avdmanager create avd --name "bpk-avd-min" --package "system-images;android-21;google_apis;x86" --device "Nexus 5"
Backpack also supports native Android and iOS. This is separate from React Native, using the Android SDK and UIKit.
They can be found at backpack-android and backpack-ios.
Backpack uses a combination of ESLint and Prettier to enforce coding styles. ESLint runs as a pre-commit hook, so it isn't possible to commit code that causes ESLint to fail.
We recommend that you install a plugin to your editor to run ESLint automatically, which will then show you any errors inline. You can even enable an option to fix ESLint errors automatically upon saving.
Run npm install
to install dependencies from npm.
A note on dependencies
Backpack is a multi-package repository, also known as a monorepo. This means that instead of having one code repository for each npm package, we manage them all inside this single repository.
We use Lerna to achieve this. Lerna links packages together inside this repo by 'bootstrapping'.
When you run npm install
, Lerna is bootstrapped automatically as a post-install hook. However, if you change dependencies within a package, you will need to run Lerna manually with npm run bootstrap
.
Skip this section if you don't intend to develop React Native components.
iOS
From inside native/ios
, run bundler install
followed by bundle exec pod install
.
Android
To ensure that maps powered by Google work set the google_maps_api_key
in native/android/local.properties
and make sure you are using the backpack.keystore.
For members of Backpack we have a keystore tied to our Google Maps API key in LastPass. Retrieve this key and place it in native/android/backpack.keystore
. For contributors who are not members of Backpack nothing needs to be done, but Google Maps will not work. If you need Google Maps to work you'll need to supply your own Google Maps Api Key and possible keystore.
Backpack's code depends on some things that must be built first, such as icon fonts, SVGs and tokens.
Use npm run build
to do this.
We use Storybook for our development environment. The instructions for running it are different, depending on whether you're running the web or React Native storybook.
Run npm start
to start the storybook server, then go to http://localhost:9001 in a web browser to view it.
- Run
npm run native
to start the storybook server. - Open another terminal tab/window.
- Run
npm run ios
to run the Backpack app on an iPhone simulator. - Run
npm run android
to run the Backpack app on an Android emulator. - Go to http://localhost:7007 in a web browser.
At this point, you should have a functioning development environment running on your local machine.
If you want to add a new component, we will need the following:
- Design (Sketch file)
- Associated tokens
- Sass mixin(s)
- React component
- Stories
- Tests
- Documentation (Including main
README.md
)
Sketch is the preferred format for non-technical folks. We’d appreciate if you could provide an exact match of your component in Sketch format together with folders for each state e.g. disabled, expanded etc.
Any visual CSS parameters of the component, such as color, margins, paddings etc. should not live as magic numbers in the component code, but as tokens in the bpk-tokens
package.
Tokens are defined in the src/base
directory (with the exception of product-specific tokens, which are in other subdirectories). Tokens come in two layers: In aliases.json
, all base tokens are defined with concrete values, such as colors, numbers and sizes. The other files then map those aliases to tokens for specific elements.
You should probably not touch
aliases.json
, as our color palette or grid rarely changes.
All Sass mixins are defined in the bpk-mixins
package. The package also exposes the Sass variables from the bpk-tokens
package.
If you add a new file of mixins, for example for a new atom, make sure you add the file to the imports in _index.scss
.
Use npm run create-component
to create a new skeleton React component. Once this is created, use existing components for code style inspiration.
We use CSS Modules along with BEM to prevent collisions and accidental overwrites in CSS.
Our documentation consists of two parts: Sassdoc, which is automatically generated from the bpk-mixin
sources, and the main documentation.
As mentioned, the Sassdoc are automatically generated from source and comments. If you want to double check, you can generate them using npm run sassdoc
and start a static server to browse the docs, but usually this is not necessary.
Take a look at some of the mixin source files to see how to annotate your Sass to generate proper Sassdoc.
When adding documentation for a new component:
- Add the new dependency in
packages/bpk-docs/package.json
and runnpm run bootstrap
to install it. - Add routes for your new component in
packages/bpk-docs/src/constants/Routes.js
andpackages/bpk-docs/src/constants/redirect-routes.js
. - Add new link in
packages/bpk-docs/src/layouts/links.js
.
For help writing documentation, see Skyscanner's copywriting guide and Backpack's guide for writing docs.
Create a pull request to Backpack
For anything non-trivial, we strongly recommend speaking to somebody from Backpack squad before starting work on a PR. This lets us pass on any advice or knowledge we already have about the work you're proposing. It might even be something we're already working on. After this, follow the steps below.
- Fork the repository.
- Create a new branch.
- Make your changes.
- Commit and push your new branch.
- Submit a pull request.
- Notify someone in Backpack squad or drop a note in #backpack.
Bear in mind that small, incremental pull requests are likely to be reviewed faster.
Run tests
npm test
will run all tests for both web and React Native. It will pick up any files that end in -test.js
, so you don't need to do anything to make Jest pick them up. You can also use npm run test:native
to only run React Native tests.
You can also run the tests in 'watch mode', which means the process will continually run and run tests every time files change. Use npm run jest:watch
to do this, or npm run jest:native:watch
to only run them for React Native.
Run the documentation site
The Backpack documentation is a standalone client-side app. Each package has its own page, which you can find and edit in the bpk-docs
package under src/pages
.
The “page” modules themselves contain introductory blurbs and examples for the respective component. They also import the component’s README, which you should have created as part of your component.
You can run the docs app locally using:
npm run build
npm run docs
And loading http://localhost:8080.
The web Map component page requires an environment variable named GOOGLE_MAPS_API_KEY
. During builds, this is set by Travis.
Run linters manually
npm run lint
to lint both JS and SCSS.npm run lint:js
to lint JS.npm run lint:js:fix
to lint and try to automatically fix any errors.npm run lint:scss
to lint SCSS.
Run Android emulators manually
The setup process detailed in Prerequisites created two Android emulators. One with API version 27 and another with 21.
To run these manually, from inside the /native
folder, run npm run android:emulator
or npm run android:emulator:min
to run API versions 27 and 21 respectively.
Publish packages (Backpack squad members only)
- Update the unreleased changelog with every package that has changed, separating out breaking changes (major), additions (minor) and fixes (patch) changes (you should see examples of this in previous entries of the changelog).
- Some useful commands for determining "what's changed?":
npm run lerna updated
npm run lerna diff <package-name>
- Some useful commands for determining "what's changed?":
- Make sure you are an owner of the npm packages (speak to a member of the Backpack squad).
- Do not run
npm publish
. Instead, runnpm run publish
(this will runlerna publish
). - You’ll be asked to specify a new version for every package that has changed. Options are patch, minor or major. These should directly align to the entries you put in the unreleased changelog in step 1.
- You’ll be asked at the end to confirm. Note you can still exit without making these changes.
- Move entries from unreleased.md to the changelog. Update the package versions for the new changes, and group them under a title with today’s date and a brief summary of what has changed.
- Commit and push to master.
Be aware that if bpk-tokens
has changed, all packages in the repository will be updated as they all depend on bpk-tokens
. Changing an existing token is almost always worth a "major" release, whereas adding a new token is usually a "minor" release.
When a component is released for the first time on npm, remember to add the component to the Skyscanner organisation through the npm UI.
backpack-android
and backpack-ios
folders are git submodules used solely for documentation. They shouldn't be directly used for anything else.
The documentation build will ensure the local submodules are up to date before using it so there is no need to do any git command directly. That being said, from time to time it's good to update the submodules to point to a newer commit so fewer changes will be pulled before each doc build.
To do the above run npm run submodules:update
and then git push origin master
.
If you have any questions at all, don't hesitate to get in touch. We love to talk all things Backpack and we look forward to seeing your contribution!