🍥
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github
.storybook
buffer-account
packages
.babelrc
.dockerignore
.editorconfig
.gitignore
.travis.yml
Dockerfile
Dockerfile.development
Jenkinsfile
Jenkinsfile.json
README.md
lerna.json
package.json
pre-build.sh
yarn.lock

README.md

Buffer Account

🍥

Table of contents

What Is Buffer Account?

Buffer Account is a tool that is being developed to manage preferences and settings across Buffer's new suite of products.

Buffer Account is being actively developed right now! This code is open source for any and all to see and learn from — see our copyright below for more details.

If you have any questions feel free to create an issue or Tweet us @bufferdevs. We'd love to chat!

⚠️ Important Note: While you can pull this code down freely, it won't work correctly without some key components (including our API) which are not open source.

Quick Start

To get started on local development and testing:

  1. Get your buffer-dev environment setuphttps://github.com/bufferapp/buffer-dev

  2. Install the latest version of yarnInstalling Yarn

  3. Install Packages and Bootstrap

    $ cd ~/buffer-dev/buffer-account  # Or wherever yours is located
    $ yarn
    $ yarn run bootstrap
  4. Start up the account docker containers

    $ cd ../buffer-dev
    $ ./dev up session-service login account-dev

    Account relies on the session service, so it's important to include it in our up command. The order is important, since this relates to the way docker-compose starts up containers.

  5. You should now be able to visit https://account.local.buffer.com — party time! 🎉 🙌

The Account Server

When you run the ./dev up command from the quick start it spins up a number of containers on which Account depends. It also spins up the account container itself, which is an Express server with two purposes:

  1. Serve index.html for all requests to https://account.local.buffer.com
  2. Bundles frontend using webpack and serves incremental build updates to the client
  3. Provide an /rpc endpoint/proxy for making API calls in the front-end

Lerna and Yarn Workspaces

Buffer Account is a monorepo. That means it's composed of several separate parts, or packages. (You can take a look at these packages in the /packages directory) These are essentially the same as packages on npm. We use two very awesome tools to make this magic possible. 🎩. (And if you're confused by this at all, skimming their README files should help!)

  1. Lernahttps://lernajs.io/
  2. Yarn Workspaceshttps://yarnpkg.com/en/docs/workspaces

Lerna is the core of what makes it all work, while Yarn Workspaces is an addition used in place of Lerna's package mgmt. logic. You can read more about how we use Yarn Workspaces with Lerna here. The reason for using Yarn Workspaces is for better speed, and support of our workflows.

Publishing Packages

Since our app is made from a bunch of npm packages, we can publish them to the npm repository when we've made changes. All packages are namespaced under the @bufferapp organization.

ℹ️  When should you publish?
In general, you should publish to npm when you've made significant changes to any local package, like fixing a bug, or finishing a feature. Publishing your changes is usually not a requirement for deploys to production (or staging servers) to work correctly.* This is because the process that bundles and deploys Account does not fetch packages from npm if they are present in the repository (i.e., anything commited in /packages). (* The exception to this rule is any changes to the @bufferapp/session-manager package that are consumed by the server package — since at this point the build process will grab the code from npm. See this JIRA issue for more context.)

Login Login to your NPM user who has access to the @bufferapp npm organization. If you're not part of the organization, ask someone on the team for help.

npm login

Make Package Changes Make changes in a branch and get them reviewed in a PR, as usual.

Bring Changes Into Master Merge or rebase the reviewed PR into master.

Pull Master Sanity check to make sure you've got the latest changes.

git pull

Publish

yarn run publish

After running this command you'll be prompted with a menu like this;

lerna info Comparing with tag v0.5.27
? Select a new version (currently 0.5.27) (Use arrow keys)
❯ Patch (0.5.28)
  Minor (0.6.0)
  Major (1.0.0)
  Prepatch (0.5.28-0)
  Preminor (0.6.0-0)
  Premajor (1.0.0-0)
  Prerelease
  Custom

In most cases you'll choose Patch. If you're unsure, this is a great question to ask the team in Slack. You can read more about versioning with SemVer here.

The publish command picks up all changed packages and updates their package.json versions automatically . It also ensures that dependant local packages have the updated version. Finally, it also pushes the version tag to Git.

For more info on the publish command see https://github.com/lerna/lerna#publish.

Common Issues with Publishing

vundefined

If you run git tags you'll see vundefined listed as a tag. This happened when trying to do a publish on a branch that had git hashes changed due to a rebase. This also blocks publishing complaining about a git hash missing. To fix this one just delete the vundefined and undoing the related version update commits. This is a great one to ask for help!

Package Scripts

We have a few helpful commands defined in this project's package.json.

Command Description
yarn run bootstrap This runs yarn (to install) on each package and links local packages together!
yarn run clean Deletes all node_modules from all packages. Use this first if you see any odd dependency errors and then follow with a yarn run bootstrap.
yarn run test Runs yarn test on all packages.
yarn run test-update Runs yarn run test-update on all packages to update all snapshot tests.
yarn run init Runs yarn on the top level package and then runs yarn run bootstrap to setup all packages. Generally you won't need to run this more than once to set things up.
yarn run lint Runs linting on all packages.
yarn run start Starts up the Account Express server, as explained above, and is run automatically when you start Account with ./dev up. (So in most cases you won't be running this command.)
yarn run publish This publishes the changed packages to npm.
yarn run build Builds the frontend with webpack.
yarn run updated Runs lerna updated which indicates which packages have changed.

Adding New Dependencies

Adding packages to a lerna projects is slightly different than adding to a standard node package. Common devDependencies can be added to the top level package.json file. For more details on that: https://github.com/lerna/lerna#common-devdependencies

Adding A Common Dependencies

This is the most likely scenario you'll face.

in the root directory (buffer-account/) run the follwing commands:

$ yarn add -DE some-cool-package
$ yarn run bootstrap

Now some-cool-package is available to all packages.

Creating A Dependency To Another Local Package

To create a dependency to the login package from the example package:

In the example package add the following entry in the packages/example/package.json file under the dependencies key:

{
  //...other stuff...
  dependencies:{
    //...other dependencies...
    "@bufferapp/login": "0.0.1", // this version must be exact otherwise it fetches from npm!
  }
}
⚠️  Important
The version number must be exact to link local packages, otherwise it will (try to) fetch the package from npm.

Add A Dependency That Runs A Binary

An example of this would be eslint or jest. These should be added to the individual package:

cd packages/example/
yarn add -DE jest

How Packages Communicate

At a high level each package communicates using the Observer Pattern through the Redux store. This means that each package receives all events and decides whether to modify their own state or ignore the event. An event (or action) flows from the originator to all other packages (including itself):

Package-A ---action--->Redux Store--->Package-B
  ^                             |
  |-----------------------------|---->Package-C

If you need to listen to another packages events, import the actionTypes into the package you're building:

// handle app initialized
export default (state, action) => {
  switch (action.type) {
    case 'APP_INIT':
      return {
        ...state,
        initialized: true,
      };
    default:
      return state;
  }
};

Copyright

© 2018 Buffer Inc.

This project is open source as a way to transparently share our work with the community for the purpose of creating opportunities for learning. Buffer retains all rights to the code in this repository and no one may reproduce, distribute, or create derivative works from this.