[solved] How to update Meteor+svelte 3 to svelte 5

hi all, My project is using Meteor 3.4 + svelte 3.59.2. So I want to update to svelte 5. Do someone know how? or, is there any course about this? Thank you for help. :blush:

Here is the package info of my project:

➜ meteor list
accounts-base           3.2.0  A user account system
accounts-password       3.2.2  Password support for accounts
accounts-passwordless   3.1.0  No-password login/sign-up support for accounts
ecmascript              0.17.0  Compiler plugin that supports ES2015+ in all .js files
email                   3.1.2  Send email messages
es5-shim                4.8.1  Shims and polyfills to improve ECMAScript 5 support
hot-module-replacement  0.5.4  Update code in development without reloading the page
jam:offline             0.4.1  An easy way to give your Meteor app offline capabilities and make it feel instant
mdg:seo                 3.5.2  Provide SEO support for enabled apps.
meteor-base             1.5.2  Packages that every Meteor app needs
mobile-experience       1.1.2  Packages for a great mobile user experience
mongo                   2.2.0  Adaptor for using MongoDB and Minimongo over DDP
montiapm:agent          3.0.0-beta.16  Performance Monitoring for Meteor
shell-server            0.7.0  Server-side component of the `meteor shell` command.
standard-minifier-css   1.10.0  Standard css minifier used with Meteor apps by default.
standard-minifier-js    3.2.0  Standard javascript minifiers used with Meteor apps by default.
static-html             1.5.0  Define static page content in .html files
typescript              5.9.3  Compiler plugin that compiles TypeScript and ECMAScript in .ts and .tsx files
zodern:melte            1.7.4  Svelte compiler with tracker integration, HMR and Typescript support
zodern:types            1.0.13  Type definitions for Meteor packages
➜ meteor npm ls svelte  
ai_app@1.1 /Users/wolf3c/Project/yezi2
├─┬ svelte-dnd-action@0.9.69
│ └── svelte@3.59.2 deduped
├─┬ svelte-exmarkdown@2.1.0
│ └── svelte@3.59.2 deduped
└── svelte@3.59.2

I started a new 3.4 Meteor app with rspack. Updated svelte to the last version, and it works perfectly. No need for zodern:melte. Runes work fine too.

My packages file:

meteor-base@1.5.2             # Packages every Meteor app needs to have
mobile-experience@1.1.2       # Packages for a great mobile UX
mongo@2.2.0                   # The database Meteor supports right now

standard-minifier-css@1.10.0   # CSS minifier run for production mode
standard-minifier-js@3.2.0    # JS minifier run for production mode
es5-shim@4.8.1                # ECMAScript 5 compatibility for older browsers
ecmascript@0.17.0              # Enable ECMAScript2015+ syntax in app code
typescript@5.9.3              # Enable TypeScript syntax in .ts and .tsx modules
shell-server@0.7.0            # Server-side component of the `meteor shell` command


static-html@1.5.0             # Define static page content in .html files
hot-module-replacement@0.5.4  # Update client in development without reloading the page
zodern:types            # Enable types from meteor/atmosphere packages

rspack@1.0.0                  # Integrate Rspack into Meteor for client and server app bundling
accounts-base@3.2.0
accounts-password@3.2.2
universe:i18n

My packages.json

{
  "name": "meteor-svelte",
  "private": true,
  "scripts": {
    "start": "NODE_NO_WARNINGS=1 meteor run",
    "test": "meteor test --once --driver-package meteortesting:mocha",
    "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
    "visualize": "meteor --production --extra-packages bundle-visualizer"
  },
  "dependencies": {
    "@babel/runtime": "^7.23.5",
    "@swc/helpers": "^0.5.17",
    "bcrypt": "^6.0.0",
    "meteor-node-stubs": "^1.2.12",
    "page": "^1.11.6",
    "svelte-routing": "^2.13.0"
  },
  "devDependencies": {
    "@meteorjs/rspack": "^1.0.0",
    "@rsdoctor/rspack-plugin": "^1.5.1",
    "@rspack/cli": "^1.7.4",
    "@rspack/core": "^1.7.4",
    "postcss-load-config": "^6.0.1",
    "svelte": "^5.49.1",
    "svelte-check": "^4.3.1",
    "svelte-loader": "^3.2.4",
    "svelte-preprocess": "^6.0.3"
  },
  "meteor": {
    "mainModule": {
      "client": "client/main.js",
      "server": "server/main.js"
    },
    "testModule": "tests/main.js",
    "modern": true
  }
}

My rspack.config.js

const { defineConfig } = require("@meteorjs/rspack");
const sveltePreprocess = require("svelte-preprocess");

/**
 * Rspack configuration for Meteor projects.
 *
 * Provides typed flags on the `Meteor` object, such as
 * - `Meteor.isClient` / `Meteor.isServer`
 * - `Meteor.isDevelopment` / `Meteor.isProduction`
 * - …and other flags available
 *
 * Use these flags to adjust your build settings based on the environment.
 */
module.exports = defineConfig((Meteor) => {
  return {
    ...(Meteor.isClient && {
      resolve: {
        extensions: [".mjs", ".js", ".ts", ".svelte", ".json"],
        mainFields: ["svelte", "browser", "module", "main"],
        conditionNames: ["svelte", "browser", "import", "module", "default"],
      },
      module: {
        rules: [
          {
            test: /\.svelte$/,
            use: [
              {
                loader: "svelte-loader",
                options: {
                  compilerOptions: { dev: !Meteor.isProduction },
                  emitCss: Meteor.isProduction,
                  hotReload: !Meteor.isProduction,
                  preprocess: sveltePreprocess({
                    sourceMap: !Meteor.isProduction,
                    postcss: true,
                  }),
                },
              },
            ],
          },
        ],
      },
    }),
  };
});
1 Like

Not a direct course on this migration yet. We have a basic experience migrating a Svelte 3.x app to Svelte 5.x. By migrating the Svelte 3 skeleton app (Meteor <=3.3) to the new skeleton using Rspack and Svelte 5 at the same time (Meteor 3.4<=), we needed to apply several code changes.

My recommendation would be:

1 - Apply Svelte 3 standardization on your Meteor app.

This step involves removing specifics from previous Meteor 3 support using zodern:melte, specifically removing the usage of $m tracker statements. The new way to support Svelte is through what is available in the JS standard ecosystem, and this helper is implemented there. Anyone with Svelte experience could try to extract it and make it available as an npm package with direct Svelte compatibility.

Removing tracker statements means you need to handle reactivity on your own, which can make the code uglier, or requires additional refactors.

2 - Migrate to Meteor-Rspack.

At this point you can stop using the build plugin zodern:melte, add the Rspack package, and migrate your app to it. There are migration requirements for Meteor-Rspack that you should consider.

You can compare your app with the provided skeleton. Use meteor create --svelte to start from a preconfigured Meteor-Rspack + Svelte 5 app. You can copy the rspack.config.js contents that preconfigure Svelte, or follow the official Rspack guide. Also consider anything specific from your current Svelte 3 setup on the svelte-loader side. From the skeleton, also review the portion that cleans up and improves HMR in the client bootstrap code to be adapted to your app.

3 - Migrate Svelte 3 to 4.

Follow the official guide to handle breaking changes:
https://v4.svelte.dev/docs/v4-migration-guide

Focus only on syntax changes, as bundler changes are handled by Rspack, not Vite. There is also a script that performs most of the migration automatically.

4 - Migrate Svelte 4 to 5.

Follow the official guide for breaking changes:
https://svelte.dev/docs/svelte/v5-migration-guide

Again, focus on syntax changes only. There is also a script to automate most of the work. Note that Svelte 5 supports Svelte 4 syntax, so you may already be able to upgrade the npm dependencies without further changes.


As you can see, starting directly with Svelte 5 on an existing project requires many considerations. We do not yet know how costly this effort is for larger apps, but even step 1, moving away from $m specifics, can be expensive. This could be a good opportunity for Svelte experts to reimplement $m behavior in a more standard way, or to fully replace tracker usage.

If you have further questions during this migration, please share them here. Svelte 5 apps work in Meteor, as shown by the minimal skeleton we provide. Existing apps may face challenges, but with shared effort this could become as a guidence of everybody else.

The output of this process could be a good candidate for an article later, written by those who have completed the experience successfully, even within the Galaxy Writing program, which you get paid for it.

2 Likes

The only issue I have is that with every code change I need to refresh the browser page manually.

I believe you used meteor create --svelte. That creates a basic Svelte 5 app already migrated to Rspack and the latest setup, with the code adapted accordingly. Starting new is as easy as that. Existing apps may require more effort for the transition, as mentioned above.

Do you have this in your main clinet point?

It’s weird. HMR is part of test coverage, including on Svelte skeleton app. It should work. Can you replicate it?

No, I don’t have it. Probably, because I started from a beta version of Meteor 3.4. I will add it and revert.

You can create a new app using official Meteor 3.4 with the latest configured state using meteor create --release 3.4 --svelte (--release 3.4 likely can be omited since 3.4 is recommended).

Thank you very much. I’ll try it with codex.

FWIW Svelte 5 has worked great for me with meteor-vite in production for a long time now. I did the whole migration-to-RSPack last month but then learned that Svelte only supports hot-reloading with Vite (this is what you are referring to @lluis) so I’m back to meteor-vite.

I was on zodern:melte before and did a migration straight to Svelte 5; going straight to runes made things a lot more straightforward because I could use my trackerEffect helper which I’ll paste below.

Claude 3.7 did a lot of the heavy lifting, and even back then it did an OK job with enough instruction. I have a feeling Opus 4.5/4.6 or Codex 5.3 would do a bang-up job, especially given Svelte’s official MCPs/skills that are now available.

Here’s my trackerEffect helper:

import { Tracker } from 'meteor/tracker';

export const trackerEffect = (func: () => void) => {
  $effect.pre(() => {
    const comp = Tracker.autorun(func);
    return () => {
      comp.stop();
    };
  });
};

Usage:

let queryParamSubscribed = $state(false);
trackerEffect(() => (queryParamSubscribed = FlowRouter.getQueryParam('subscribed') === '1'));

As time has gone on I’ve replaced much of my trackerEffect usage with Svelte-reactive classes.

Moving from Svelte 5 (and from the old Meteor bundler to Vite) was a big effort but I’m SO glad I did it.

2 Likes

Progress update: I have migrated to Svelte 5 in Svelte 4 syntax. All work well. Thank you for your course. It’s the best guide for migrating.

1 Like