Gradually upgrading a Meteor.js project to 3.0
Tags: meteor, javascript, tutorial
Published: 2023-12-15 12:28:47

TL;DR - In this first part of the Migration series we will start upgrading an existing Meteor.js project to 3.0 (alpha). We will be using a determined strategy that should apply to **any existing Meteor.js project**. Focus is fixing dependency conflicts during the update process.

> Follow-up articles will show how to fix dependencies (packages and build-tools) by example 💪

---
## Table of Contents

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [What is Meteor.js 3.0 and why should I care? ☄️](#what-is-meteorjs-30-and-why-should-i-care)
  - [Meteor 3.0 is still in Alpha, why doing this now? 🧐](#meteor-30-is-still-in-alpha-why-doing-this-now)
  - [Biggest challenges while migrating to 3.0 🏗️](#biggest-challenges-while-migrating-to-30)
- [A Generic Migration strategy 🧩](#a-generic-migration-strategy)
  - [Part 1 - Preparations 📝](#part-1-preparations)
  - [Part 2 - updating to 3.0 and dependency triage 🔬](#part-2-updating-to-30-and-dependency-triage)
  - [Part 3 - Fixing a dependency 🔥](#part-3-fixing-a-dependency)
  - [Part 4 - migrate your project code ⌨️](#part-4-migrate-your-project-code)
  - [Step 5 - deployment 🚀](#part-5-deployment)
- [Summary and Outlook 🔭](#summary-and-outlook)
- [About me 👋](#about-me)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

---
## What is Meteor.js 3.0 and why should I care? ☄️

> If you already know about Meteor's next major version then you can safely skip this section.

Meteor.js 3.0 is an upcoming major release. The platform  is moving away from [Fibers](https://www.npmjs.com/package/fibers) (coroutines) in favor of Node's native async-await implementation. The reason behind this step is, that Fibers are not compatible anymore with Node (add links here), beginning with version 16. Due to this circumstance, Meteor is stuck in at Node 14 and this brings lots of implications (security, maintenance, being up to date etc.) for any developer and company.

{% github https://github.com/meteor/meteor %}

However, this transition to async-await comes with a massive impact on the very core of Meteor's execution model: In the past you were able to write sync-style code for async operations, for example a MongoDB-Collection fetch:

```js
const document = MyCollection.findOne({ title: 'foo' })
```

This MongoDB operation has always been async in nature, but Meteor used Fibers to keep track of thing in a way, that the above code resolved without the need of Promises or async/await. In 3.0 operations like these will be replaced by they native Promise implementations and therefore require to be awaited:


```js
const document = await MyCollection.findOneAsync({ title: 'foo' })
```

> This implies a necessary upgrade for **every** Meteor.js project out there.

---
### Meteor 3.0 is still in Alpha, why doing this now? 🧐

Depending on the size of your project and your team being able to work on such an upgrade you will face challenges on a varying scale and this article should help you to get a first glimpse on the upcoming effort.

> This will also help you to make a much better estimation with regards to the complexity and effort of the upcoming migration.

The API of the Alpha versions is 99% stable and most development resides around details or bugs. You can therefore safely start upgrading and refactoring, while you later will only have to switch from Alpha to the stable release.

I have already compiled some steps for preparing your existing projects that won't require an update to 3.0 yet:

{% embed https://dev.to/jankapunkt/prepare-your-meteorjs-project-for-the-big-30-release-14bf %}

---
### Biggest challenges while migrating to 3.0 🏗️

From my current efforts I could compile a short but fundamental list of challenges and their manageability:

|Challenge|Manageability|
|---------|-------------|
|Direct dependency conflicts|Easily manageable for your own packages; requires manual fixing for third-party packages|
|Indirect dependencies version conflicts|Will definitely require manual cloning and fixing|
|Build tools|Will depend on the complexity of the plugin; will require manual fixing|
|Breaking Isomorphism|Manageable with big efforts; may require major architectural changes, depending on how much your projects rely on isomorphic code|
|Rewrite code to use async/await|Involves effort but manageable; read the [official docs](https://guide.meteor.com/prepare-meteor-3.0) and [my article](https://dev.to/jankapunkt/prepare-your-meteorjs-project-for-the-big-30-release-14bf) on this topic for more info|
|Deployment|Managed for you, when using Galaxy; effort when doing custom deployment; for example with MUP; involves finding correct images, may require to build custom images| 

As you can see the actual change in your project's code is just a small portion of the overall challenges. This is why this article series tries to deal with all the other parts of it.

---
## A Generic Migration strategy 🧩

My goal for this article was to provide a generic strategy that any of us could apply on their existing projects. Of course, the effort and complexity will vary but the overall procedure should work for anyone. A good approach is to start with a smaller project to get used to the process. Once you succeeded there you will already know most of the intricacies in order to be ready for your larger projects.

> This strategy involves using git and assumes to commit often in order to being able to revert to the state of the last step/substep. This will apply for the project, as well as for cloned dependencies. The following example shows how to hard-revert to a certain commit hash:

```sh
# show the full list of commits on this branch
$ git log
 commit 126669f9b29f9172bea4ebaf0599670bd4493f03 (HEAD -> migrate-3.0, origin/master, origin/HEAD)
Merge: a8ac876 7dc118a
Author: Jan Küster <info@jankuester.com>
Date:   Mon Nov 28 16:37:38 2023 +0200

    migration(1.2): prepared project structure
# reset to the latest commit, omit anything newer than this commit
$ git reset --hard 126669f9b29f9172bea4ebaf0599670bd4493f03
```

The following is a high-level overview of the strategy

---
### Part 1 - Preparations 📝

#### 1.1 Work on an exclusive branch
- commit any remaining changes
- checkout your most recent development branch
- checkout a new branch, exclusively to migration towards 3.0: `git checkout -b migrate-3.0`


#### 1.2 Prepare project structure for fixing dependency conflicts
- if project is in top-level
  - create a new folder `src` and move project files in this folder
  - keep all Git-related files in top-level
- create a `lib` folder in top-level (next to `src`) where all package-repos will be cloned, that may contain multiple packages or nested structures (see [this example](https://github.com/Meteor-Community-Packages/meteor-autoform-themes))
- create `packages` folder for package-repos that have a direct structure (see this [example](https://github.com/Meteor-Community-Packages/meteor-link-accounts))
- commit your state

#### 1.3 Upgrade to latest 2.x
- run `meteor update --release=2.13.3` (or newer; see the [changelog](https://github.com/meteor/meteor/blob/devel/docs/history.md)) 
- if this causes issues you have to fix them first (out of scope; see the migration notes on the specific versions in the docs)
- commit your state

**Optional:**

- place `jkuester:migration-helper (after all core-packages, but before all non-core packages)
- flag all non-core packages as `# fixme:async` that use sync mongo/cursor calls or create sync style methods/publications
- more at my previous article [Prepare your Meteor.js project for the big 3.0 release!](https://dev.to/jankapunkt/prepare-your-meteorjs-project-for-the-big-30-release-14bf)

#### 1.4 Prepare next update to 3.0
- Clear any caches of package version
  - clear all entries .meteor/versions file
  - remove .meteor/local folder
  - comment all packages, expect [core packages](https://github.com/meteor/meteor/tree/devel/packages) in .meteor/packages
  - remove @<version> suffix from all entries
- commit your state  

---
### Part 2 - updating to 3.0 and dependency triage 🔬

> Important note

During this phase you will often have to run/rerun the app in order to see which dependencies cause a conflict. However, since many of your packages are commented you should not expect the app to successfully start. You will likely then encounter other errors. But that's not the point of this step, it's only about resolving dependency conflicts.

#### 2.1 Update only with core packages
- run update `meteor update --release=3.0-alpha.19`
- all core packages should have upgraded successfully and there should be no error message, involving version conflicts (other errors are to be expected, though)
- if there is a version conflict, then
  - make sure the packages left uncommented in this step were only [core packages](https://github.com/meteor/meteor/tree/devel/packages)!
  - comment all core-packages that are involved with the conflict and flag them as `fixme:core`
  - if you are **100% sure** this is a core-package problem then open an issue in the [Meteor GitHub repository](https://github.com/meteor/meteor)
  - best would be to also add the issue link to the comment flag: `fixme:core (link to issue)`
  - if you are < 100% sure then reach out to the community on the Forums, Slack or Discord    
- else commit your state

#### 2.2 Uncomment non-core packages stepwise (loop)
- uncomment a single **non-flagged** non-core package 
- try to rerun the app
- if this package cause a version conflict
  - comment and flag as `fixme:deps`
  - Proceed with step 3 for this package
- else commit your state
- if there are commented packages left in `.meteor/packages` then proceed with Step 2.2
- else proceed to step 4

---
### Part 3 - Fixing a dependency 🔥

This step has the scope of a single dependency (package or build tool).

#### 3.1. Determine the package's location
- if it's one of your local packages then keep it in it's place
- else look up the package name on [Packosphere](https://packosphere.com/)
- look for the GitHub link on the package's page and navigate to the repository
  - if this package contains no GitHub repository link then you need to contact the owner to open this package or provide an upgrade, you may also seek help in the community
- fork the repository
- check the folder structure and determine, whether to place it in `packages` (proceed with 3.2) or in `lib` (proceed with 3.3)

#### 3.2. Clone the package into `packages`
- select the green button in the repo (labelled "code") and select the repo link (favorably ssh) 
- cd into the `packages` folder
- run `git clone <link>`
- cd into the new cloned package
- run `git checkout -b migrate-3.0` 
- if you get `fatal: A branch named 'migrate-3.0' already exists.` then you are still in the `packages` folder!

#### 3.3. Clone the package into `lib`
- select the green button in the repo (labelled "code") and select the repo link (favorably ssh)
- cd into the `lib` folder
- run `git clone <link>`
- cd into the new cloned package
- run `git checkout -b migrate-3.0` 
- if you get `fatal: A branch named 'migrate-3.0' already exists.` then you are still in the top-level folder!
- now you need to link the content of this package (or a subdirectory of the package) with your `packages` folder
- cd back into `src/packages`
- link using `ln -sf ../../lib/<repo-name>/path/to/package`



#### 3.3 Fixing the package versions
  - open `package.js` in your editor/IDE
  - fix `api.versionsFrom`, it should look something like `api.versionsFrom(['2.8', '3.0-alpha.19'])` 
  - search for further dependencies that caused confwhat-is-meteorjs-30-and-why-should-i-care-licts
  - fix their required dependency version, for example
    `api.use('minifier-css@1.6.0 || 2.0.0-alpha300.19')`
  - continue with all dependencies in this file until no conflicts occur
  - commit this state in the package
  - commit this state in your project

#### 3.4 Fixing the package's code to use async-await

It might be a good opportunity to review the package's code for usage of being involved in any MongoDB Collection or Cursor activity or any imports of `'fibers/future'` or `Promise.await` inside the package's code. If any of them is the case then you will have to migrate this code as well, in order to have the package function properly.

It might be exhausting to realize that the package you used for years and which ran fine now of sudden needs thewhat-is-meteorjs-30-and-why-should-i-care-se big changes. You have basically three options now:

- A) find a replacement (causing your project code to be rewritten to the new package's api)
- B) contact the package maintainer (can take from a day to infinity to be fixed)
- C) do it on your own (involves effort but you are in control of the situation)

This step assumes you go with option C and the follow-up articles will deal with this situation in detail.

#### 3.5 post-fix cleanup
- you may have to update the package's tests as well
- document and commit your changes
- push to your fork `git push origin migrate-3.0` while being in the package repository folder
- If you want to make this fix available for others then I encourage you to open a pull request

---
### Part 4 - migrate your project code ⌨️

> At this step you should have resolved all dependency conflicts and committed the current state. 
> If not, make sure this is the case, in order to being able of reverting to the state of this commit at any time.

This is the time where your own project code is to be migrated. In an optimal world you may have done this already when being on Meteor 2.x. If you didn't, worry not! 🧙‍♂️

Here are a few important resources, that might help you to advance in your own code migration:

#### Guides on upgrading to async/await

The following link should help you with the majority of issues when migrating your projects.

{% embed  https://guide.meteor.com/prepare-meteor-3.0 %}

{% embed https://guide.meteor.com/3.0-migration %}

{% link https://dev.to/jankapunkt/prepare-your-meteorjs-project-for-the-big-30-release-14bf %}

- [List of all Methods that needs to be updated (Meteor core and core packages)](https://github.com/meteor/meteor/blob/d5c3b2eeafd0ad78ee7e2553f3f269c5c2a2e2a9/docs/generators/changelog/versions/3.0.md)
- [Meteor API docs](https://docs.meteor.com/)
- [Meteor Guide](https://guide.meteor.com/)

#### Help and support for your upgrade process

Engage with the Meteor community if you're getting stuck or if you want to share your migration success or if you simply want to get in touch with fellow Meteor developers.

- [Meteor forums](https://forums.meteor.com/)
- [Meteor Community Slack](https://meteor-community.slack.com/)
- [Meteor Community Discord](https://discord.gg/9GDmECsYdH)

#### Background topics

If you are interested in the more technical reasons behind this whole migration topic when you might want to check out these links.

- [Original discussion about how Meteor should execute native async/await](https://github.com/meteor/meteor/discussions/11505)

---
### Part 5 - deployment 🚀

You are finished with your migration and your project runs fine, including all tests. That's awesome! 💪
However, now it's time to get this up and running on the target infrastructure

Deploying a Meteor app can be done in multiple ways but you have to be aware that your deployment environment is 3.0 ready!

#### Hosting on Galaxy

First of all, there is [Meteor Cloud, the official hosting platform (formerly known as Galaxy)](https://www.meteor.com/cloud?utm_source=jkuester&utm_medium=online&utm_campaign=Q2-2022-Ambassadors) by Meteor Software, the company backing the Meteor.js ecosystem and core contributors to the Meteor.js open source repository. 

With the Meteor Cloud managed services **you will already face a Meteor 3.0-enabled environment** and you can easily deploy your app in one command. You can try their services with the [free plan](https://www.meteor.com/cloud/pricing?utm_source=jkuester&utm_medium=online&utm_campaign=Q2-2022-Ambassadors), perfectly suitable for demos, MVP or proof of concepts.

Deployment to Galaxy is a no-brainer, either via a single cli-command or automated via push-to-deploy. You can read it all up in the deployment guide:

{% embed https://galaxy-guide.meteor.com/deploy-to-galaxy %}

#### Custom Hosting using Meteor-Up (MUP)

For those who need alternatives, for example hosting on-premise, there is a great tool out there that simplifies the deployment process a lot: Meteor-Up

{% embed https://meteor-up.com/ %}

{% github https://github.com/zodern/meteor-up/ %}

With this option you are entirely free to choose where your Meteor apps will run. Of course, this also brings the duties to manage the entire infrastructure on your own.

Furthermore, you will have to get deeper into Docker and Images in order to be able to successfully deploy your 3.0 app using MUP.

---
## Summary and Outlook 🔭

With this article you were given methods and resources to migrate your app towards Meteor 3.0 with a big focus on resolving dependencies.

If you have any questions or trouble with any step of this process, please don't hesitate to share it in the comments or get in contact with the community:

- [Meteor forums](https://forums.meteor.com/)
- [Meteor Community Slack](https://meteor-community.slack.com/)
- [Meteor Community Discord](https://discord.gg/9GDmECsYdH)

In the next article I will demonstrate the migration process from 2.x to 3.0 with an example app that runs into some dependency conflicts. Together we will solve these conflicts, fix up the code and make the app run again but on the latest 3.0 alpha version.

---
## About me 👋

I regularly publish articles here on dev.to about **Meteor.js** and **JavaScript**. Recently I also co-host the [weekly Meteor.js community podcast](https://www.youtube.com/@meteorjscommunity), which contains the newest from Meteor.js and the community.

You can also find (and contact) me on [GitHub](https://github.com/jankapunkt/), [Twitter/X](https://twitter.com/kuester_jan) and [LinkedIn](https://www.linkedin.com/in/jan-kuester/).

If you like what you are reading and want to support me, you can [sponsor me on GitHub](https://github.com/jankapunkt), [send me a tip via PayPal](https://paypal.me/kuesterjan) or sponsor me a book form [my Amazon wishlist](https://www.amazon.de/-/en/hz/wishlist/ls/12YMIY0QNH9TK?ref_=list_d_wl_lfu_nav_1).