DEV Community

Cover image for Gradually upgrading a Meteor.js project to 3.0
Jan Küster for Meteor

Posted on • Edited on

Gradually upgrading a Meteor.js project to 3.0

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


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 (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 logo meteor / meteor

Meteor, the JavaScript App Platform


Travis CI Status CircleCI Status built with Meteor built with Meteor


Meteor is an ultra-simple environment for building modern web applications.



📚 Create your applications using modern JavaScript

Benefit from the latest technology updates to rapidly prototype and develop your applications.


Integrate technologies you already use

Use popular frameworks and tools right out-of-the-box. Focus on building features instead of configuring disparate components yourself.


💻 Build apps for any device

Use the same code whether you’re developing for web, iOS, Android, or desktop for a seamless update experience for your users.


🔥 Getting Started

How about trying a tutorial to get started with your favorite technology?

Next, read the documentation and get some examples.

🚀 Quick Start

On your platform, use this line:

> npm install -g meteor
Enter fullscreen mode Exit fullscreen mode

🚀 To create a project:

> meteor create my-app
Enter fullscreen mode Exit fullscreen mode

☄️ Run it:

cd my-app
meteor
Enter fullscreen mode Exit fullscreen mode

🧱 Developer Resources

Building an application with Meteor?

  • Deploy…

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:

const document = MyCollection.findOne({ title: 'foo' })
Enter fullscreen mode Exit fullscreen mode

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:

const document = await MyCollection.findOneAsync({ title: 'foo' })
Enter fullscreen mode Exit fullscreen mode

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:


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 and my article 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:

# 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
Enter fullscreen mode Exit fullscreen mode

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)
  • create packages folder for package-repos that have a direct structure (see this example)
  • commit your state

1.3 Upgrade to latest 2.x

  • run meteor update --release=2.13.3 (or newer; see the changelog)
  • 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!

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 in .meteor/packages
    • remove @ 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!
    • 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
    • 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
  • 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.

How to migrate to Meteor Async in Meteor 2.x | Meteor Guide

How to migrate your application to async methods and be ready to 3.0.

favicon guide.meteor.com

Migrating to Meteor 3.0 | Meteor Guide

How to migrate your application to Meteor 3.0.

favicon 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.

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.


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) 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, 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:

Deploy to Galaxy | Galaxy Docs

Learn how to deploy on Galaxy by setting up Push to Deploy. The easiest and fastest way of deploying your Meteor app.

favicon galaxy-guide.meteor.com

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

GitHub logo zodern / meteor-up

Production Quality Meteor Deployment to Anywhere

Meteor Up GitHub Workflow Status (branch) Gitter Backers on Open Collective Sponsors on Open Collective

Production Quality Meteor Deployments

Meteor Up is a command line tool that allows you to deploy any Meteor app to your own server.

You can install and use Meteor Up on Linux, Mac and Windows. It can deploy to servers running Ubuntu 14 or newer.

This version of Meteor Up is powered by Docker, making deployment easy to manage and reducing server specific errors.

Read the getting started tutorial.

Features

  • Single command server setup
  • Single command deployment
  • Deploy to multiple servers, with optional load balancing and sticky sessions
  • Environment Variable management
  • Support for settings.json
  • Password or Private Key (pem) based server authentication
  • Access logs from the terminal (supports log tailing)
  • Support for custom docker images
  • Support for Let's Encrypt and custom SSL certificates

Roadmap

Server Configuration

  • Auto-restart if the app crashes
  • Auto-start after server reboot
  • Runs with docker for better security and isolation
  • Reverts to the…

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:

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, which contains the newest from Meteor.js and the community.

You can also find (and contact) me on GitHub, Twitter/X and LinkedIn.

If you like what you are reading and want to support me, you can sponsor me on GitHub, send me a tip via PayPal or sponsor me a book form my Amazon wishlist.

Top comments (0)