loading...
Cover image for Simplify Expo releases with Standard Version

Simplify Expo releases with Standard Version

bycedric profile image Cedric van Putten Updated on ・4 min read

Releasing your apps can be a repetitive, sometimes even annoying task. You prepared and built your app for the stores, only to find out you forgot to bump a version code. If you don't like to do this, the great people from Conventional Changelog got just the thing for you!

Standard version is a tool to simplify the release process with a single command, yarn standard-version. It's customizable and should have everything you need, like generated changelogs from conventional commits. If you don't know the tool yet, check out the documentation first.

In this guide, I'll show you how to configure Standard version for Expo. We will set up an example project and configure it for automated expo.version, expo.android.versionCode and expo.ios.buildNumber.

🚀 Let's get going

First things first, create an empty Expo project using the blank template.

$ expo init --template blank

Next, we need to define a starting version for our project. Standard version uses the package.json's version property to determine the current version. This value is used to calculate the next release. Let's set this property to 0.0.0.

{
  "version": "0.0.0",
  "main": "node_modules/expo/AppEntry.js",
  ...
}

Now add Standard version, with the Expo extension, to our dev dependencies.

$ yarn add --dev standard-version@next standard-version-expo

Currently, standard-version@7.1.0 is the only version that supports updaters from packages. That's why we need @next here.

You can test the project by running standard-version in dry-run mode. This mode only tells what it will do without doing anything.

$ yarn standard-version --dry-run

If you get the Invalid Version: undefined error, it means the package.json doesn't have a starting version.

⚙️ Configure Standard version

Now that we've set up the basics, we need to configure Standard version for Expo. Create a file named .versionrc.js with:

module.exports = {
  bumpFiles: [
    {
      filename: 'package.json',
    },
    {
      filename: 'app.json',
      updater: require.resolve('standard-version-expo'),
    },
  ],
};

This tells Standard version that we want to update app.json, using the default updater from the Expo extension. The updater bumps expo.version with the new version, so you don't have to! 😬

Note: We also want to update our package.json, with the default updater, to keep a single source of truth for our versions. (See PR #3 for more details)

Test your configuration again with --dry-run, if you see the following output, you did an excellent job. 🦄

$ yarn standard-version --dry-run

✔ bumping version in app.json from 1.0.0 to 0.0.1
✔ created CHANGELOG.md
✔ outputting changes to CHANGELOG.md
...
✔ committing app.json and CHANGELOG.md
✔ tagging release v0.0.1

Now commit these changes and create a new minor version.

$ git add .
$ git commit -m 'feat: add standard version for releases'
$ yarn standard-version --release-as minor

After running the tool, you should have a new CHANGELOG.md and an updated app.json file! You still need to push the local changes to remote, but that also gives you an option to revert changes if something went wrong. 🧑‍🔧

📱 Configure build versions

If you are planning on releasing your app to the stores, we need to configure Standard version a bit more. It also needs to update the Android version codes and iOS build numbers. Let's start by updating our manifest with iOS and Android configuration.

{
  "expo": {
    ...
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.bycedric.awesomeapp",
      "buildNumber": "0.0.0"
    },
    "android": {
      "package": "com.bycedric.awesomeapp",
      "versionCode": 0
    }
  }
}

Great, now we need to tell Standard version about these new properties. The values should change on every release, just like our expo.version. To do this, open up .versionrc.js and add the new version bumpers.

module.exports = {
  bumpFiles: [
    {
      filename: 'package.json',
    },
    {
      filename: 'app.json',
      updater: require.resolve('standard-version-expo'),
    },
    {
      filename: 'app.json',
      updater: require.resolve('standard-version-expo/android'),
    },
    {
      filename: 'app.json',
      updater: require.resolve('standard-version-expo/ios'),
    },
  ],
};

There are multiple types of version updaters, each with their own "tactic". You can find them all here. For simplicity, let's stick to the recommended bumpers for now.

That's it! If you commit these changes and run Standard version, it will update the build version numbers for you too. 🌈

$ git add .
$ git commit -m 'feat: add standard version for releases'
$ yarn standard-version --release-as patch

🤝 Thanks for reading!

I hope this can be useful for anyone. If you use this library, feel free to reach out. I'd love to hear about your experiences with the tool. Also, feel free to reach out if you have great ideas to make it better or if you are stuck. 🙆‍♂️

📚 Extra goodies

Edit: I made a mistake of not adding package.json to our .versionrc.js. Thanks to awinograd for spotting and fixing it!

Cover photo by Robert Metz

Posted on by:

bycedric profile

Cedric van Putten

@bycedric

Doing stuff with #Expo and maintainer #Commitlint. Solving problems caused by software, using software.

Discussion

markdown guide
 

Just this week I started building my app and pushing it to TestFlight so I'm very happy to have come across this. Thank you, Cedric. It looks to be exactly what I need to make the process a little easier.

 

Excellent tool! exactly what I was looking for 💪 automating CI/CD.
given that the native part of my app will rarely update, does it makes sense updating the package.json only, as a way of keeping the bundle version?
or should I update ios/android versions too and skip uploading the apk/ipa?

 

Hi Pavel, thanks! The tool was initially built for managed projects without native code. For the native part, we might need to add a few "version bumpers". I'll look into this asap!

Edit: just created #9, if you have good ideas feel free to share them there! 😁

The package.json is used by standard-version itself as a kind of "single source of truth". So it's always good to update it there. That being said, only updating the version in package.json will still require you to manually update the build numbers, like versionCode in Gradle, when you publish to stores.

Hope it helps!

 
 

This is a great helper! Thank a lot Cedric!

 

No problem! Thanks for reading it! 😁