Meteor-RSPack Integration: A Modern Bundler Meets Meteor 3.4

Incredible stuff! I really think this addresses the primary DX pain point of working with Meteor apps.

While I would’ve loved to see Vite become a part of the Meteor build system, mainly due to the current ecosystem. RSPack does feel like a better choice for an everything-included framework like Meteor, and a huge leap for the platform.

This should open up for a lot of flexibility and allow for interoperability with build tools that weren’t hand-crafted just for Meteor.

The “UnJS (unplugin)” plugins aim to be an universal and compatible with most major build systems. And with RSPack, Meteor automatically gets to benefit from this. And hopefully the inverse as well, where it moves the JS community slightly closer to standardization within the bundler ecosystem.

I’m really excited for this!

4 Likes

No release date yet. We’re focused on stability in 3.3.1 while progressing on 3.4, the Rspack bundler and Change Streams.

Like with Meteor 3.3’s SWC and other optimizations, we’ll ship several betas to test both small and large apps, address edge cases, and gather feedback. We also plan core improvements, such as dev-only packages to slim production bundles. Betas should begin at the end of July, with Rspack support beta likely in August. After the beta phase, we’ll move toward an RC and the final release.

would be possible through an RSPack plugin (for example the @nx/angular-rspack) or would there be limitations on meteor’s side?

We can try that. It should be supported, but I’m not familiar with @nx/angular-rspack. It doesn’t act as a loader or plugin for rspack.config.js and instead uses its own config approach, similar to what we plan for Meteor, so I’m not sure how it would fit. Thanks for bringing this up.

Could you share a small Angular app repo that uses Rspack? That would make it easier to test compatibility later.

2 Likes

It doesn’t act as a loader or plugin for rspack.config.js and instead uses its own config approach, similar to what we plan for Meteor, so I’m not sure how it would fit.

From what I understand, it’s just a wrapper, so it returns a compatible RsPackOptions configuration at runtime. This is how an output would look like: Untitled (ri3sgor0) - PasteCode.io

Could you share a small Angular app repo that uses Rspack?

I’ve created a github repository with a working example using angular 20 and the latest version of rspack and @nx/angular-rspack. GitHub - Joyzyy/angular-rspack-test: rspack integration with angular 20

I’ve also tried to implement the angular rs-pack configuration over on the modern-bundler-integration branch, but to no avail. I might be misunderstanding some things about how meteor works internally (since I don’t have that much experience), so i might’ve done something wrong, that being said, these were issues I ran into:

  • I’ve manged to compile the angular frontend, deploying it on port 3005, and serving the assets on the publicPath of __rspack__/, so the rspack_server can create the proxy. What i fail to understand is why there is a need for the main-client.dev.js inside the _rspack folder since in development we are using setMeteorAppCustomScriptUrl(addEnvSuffixToFilename('/__rspack__/main-client.js')); which just uses the proxy?
  • Also, is it possible to add multiple script tags to the <body></body> of the generated html by meteor’s static-html plugin? Since the compilation of the angular frontend generates 6 main files: vendor.js, polyfills.js, main.js, runtime.js, styles.js, styles.css which all are needed in the index.html on localhost:3000, or can we skip the index.html generated by meteor and use the index.html generated by rspack (but using this option, how would meteor append the needed scripts (like ddp, tracker) to the index.html)?

I’m sorry in advance if some of the question don’t make any sense, didn’t get a chance to get a good look into how meteor works fully.

I think it’s too soon to check out that branch. I haven’t even created a PR yet since it’s still in an early experimental phase. It’s not final code, it isn’t fully automated, and it doesn’t cover every config or setup scenario.

I’ve made it work: as shown in this post, a React setup with build times as a preview of what’s coming. Over the past week I’ve tested other setups on manual and local apps. I’m building an abstraction to handle different setups and configs, and I’m continuing with automation and cleanup. I’ll create a PR once it covers the abstraction and addresses basic edge cases, and I’ll explain the approach when the time is right.

Thanks for the Angular example repository. It will help me understand Angular requirements. First, we need to cover the basics of Rspack integration in Meteor. Then we can address any remaining Angular config questions and code needs, like having multiple script tags and etc, if needed.


From what I understand, it’s just a wrapper, so it returns a compatible RsPackOptions configuration at runtime. This is how an output would look like: Untitled (ri3sgor0) - PasteCode.io

I understand, that’s helpful. Meteor will also add a wrapper around the rspack config with its own expectations, which may conflict with the Angular config from that package. We should be able to make both configs work together and support Meteor. Let’s revisit this later. :pray:

While I know the integration is not complete, I’ve patched together an implementation (tested in only dev mode) of the said @nx/angular-rspack and meteor (your branch, not 100% up-to-date) in the hopes that it helps you in the creation of the wrapper config of meteor over rspack.

Here is the repo, (which is just a proof of concept): GitHub - Joyzyy/angular-meteor-dev-rspack: implementation of angular-rspack and meteor modern-bundler-integration branch

and a video of meteor and angular working together (sorry for the low quality, had to transform from .mov to .webp to be able to upload it):
ScreenRecording2025-07-17at23.43.10-ezgif.com-video-to-webp-converter

3 Likes

Maybe a bit off topic, but will version 3.4 fix the exports issue in package.json?

1 Like

Meteor 3.4 will let you optionally use the Meteor-Rspack integration mentioned in this post by adding the new rspack package. Using it unlocks many bundler features, including support for the exports field in package.json.

For projects that choose to keep the default Meteor bundler, we still need a contribution to add this feature to Meteor itself:

We’re open to assisting with its inclusion once it’s ready by the author, but the modern path to support it is via Rspack.

4 Likes

After successfully automating Rspack in Meteor and focusing on production deployment, it’s clear that build time isn’t the only improvement coming in Meteor 3.4.

Client bundles are now thinner, meaning less code delivered and faster initial load times for your apps.

By integrating the work-in-progress Rspack package in fredmaiaarantes/simpletasks and deploying it to a private instance on Galaxy Cloud, the client bundle size dropped by about 50% compared to the 3.3.1-rc.2 release.

Gains vary by app and dependencies, could be less or much more. This comes from long-awaited tree shaking support and other optimizations. Large libraries like ChakraUI benefit the most when properly tree-shaken, and with a modern bundler, your app can now take full advantage of this optimization phase.

Besides, Rspack comes with tooling to diagnose and analyze your bundles. I’ll demo that soon once it’s properly integrated with Meteor’s bundle visualizer. After wrapping up a few things, we aim to hit the first beta sometime in August.

12 Likes

Any ETA on when the RSPack beta is going to be released? Are we still on track in the next couple of weeks? Super looking forward to it, and setting up a bunch of tools/projects in anticipation for it.

2 Likes

No ETA yet, but we’re committed to delivering the beta as soon as possible, still aiming for August. We’re also continuing the 3.3.x series with 3.3.1, the upcoming 3.3.2, and a 2.16.2 with Cordova 14 support.

Rspack integration has automation in place. We’re building a modern test suite to ensure quality and stability over time, along with documentation outlining the basic adoption steps. We’re also reviewing other apps and project configurations to make sure the integration can handle any customized project from the Rspack ecosystem. This flexibility work will continue through the betas to ensure compatibility for everyone. Once we have the basic examples, test coverage, and docs in place, we’ll be ready for first 3.4-beta. We’ll communicate here.

3 Likes

For any project that wants to adopt Rspack, start by addressing the prerequisites needed for this to work in any Meteor app.

Today I’ll mention the first one: clearly defining your Meteor app’s entry points.

Meteor apps with a modular structure can adopt the Rspack integration. Modular here means declaring the entry files that start your client and server apps, along with the tests. Your app should specify at package.json:

{
  "meteor": {
    "mainModule": {
      "client": "client/main.js",
      "server": "server/main.js"
    },
    "testModule": "tests.js"
  }
}

Learn more on “Modular application structure” in Meteor.

Before using this modular config with entrypoints (before Meteor 1.7), the Meteor bundler eagerly loaded every JS file it encountered in your project directory and constructed the booter itself. That was less efficient and didn’t match how modern bundlers work. During the Meteor 3.3 beta, some projects that sent me profiles didn’t describe their entrypoints, and I’m not sure they know how.

Describing entrypoints isn’t about creating blank files and listing them in package.json. Those entrypoints must import the rest of your app’s modules in order. An entrypoint is the first module that builds the module tree for your app, so it’s the starting point for booting it. You need to migrate your app to use this approach to use the opt-in Rspack integration.


Please answer the next question so we can understand your app’s state and decide whether to add more automation, documentation or guide to ensure a modular structure with clear entry points.

Do you use entry points in your Meteor app?

  • Yes, my project already uses entry points for the app and tests
  • No, my project doesn’t use entry points, but I know how to migrate
  • No, my project doesn’t use entry points, and I don’t know how to migrate
0 voters
3 Likes

An entry point file for an app makes total sense but for tests it would be a big deterioration to not just include all *.tests.* files. Would it be possible to keep that mode for tests only?

1 Like

In my Meteor‑Rspack app, I first compiled each *.test.js separately by finding them and adding each as a bundler entry. That added overhead and hurt performance. I switched to a single entry point that I maintain manually with “meteor.testModule”.

I’m open to adding an automatic “virtual” entry point, limited to tests, as it only seems to require listing .tests.js files that are likely independent, and ensure watcher keeps active filling that entry point. This approach appears efficient to keep. I’ll consider it for the first beta if time allows, otherwise later.

Definitely, app entrypoints are needed, as you noted. With the app we can’t guarantee the proper load order. We could try to mimic what Meteor internals do, but that’s likely time consuming. I don’t have experience with it yet.

I also considered automatically adding entry points when a project lacks them, as @radekmie suggested here. I could automate it later, and it would help others replicate the process and migrate their apps to proper entry points.

1 Like

Yes I +1 the wanting the test files. note that there are two version .app-test and .test that are the difference between unit test files and functional test files.

It would be possible to do it manually, but its a nice piece of meteor architecture that would be annoying to lose

1 Like

I tried this:

  "meteor": {
    "mainModule": {
      "client": "client/main.js",
      "server": "server/init.js"
    },
    "modern": {
      "transpiler": {
        "verbose": false
      }
    }
  },

However, my server has this folder structure, and the files in the synced-cron folder weren’t being launched.

My file server/init.js is contains:

import "../imports/startup/server";

Should I just update it to this?

import "../imports/startup/server";
import "server/synced-cron/cron.js";
import "server/synced-cron/main.js;

To speed up test and make use of all the cores and RAM on the build server, we partition tests with METEOR_IGNORE to only include certain *.tests.* files and then run test processes in parallel on the same circleci “machine”. Each instance gets a unique port and results file.

    "test:xunit-first-half": "parallel --xapply --tagstring '{= $_=3000+3*seq() =}' --linebuffer --header : 'INCLUDE_RANGE={RANGE} PORT={= $_=3000+3*seq() =} MOCHA_OUTPUT_FILE=result{#} yarn test:xunit' ::: RANGE a-c d-j k-n",
"test:xunit": "unset MONGO_URL && bash -c 'TEST_CONSOLE_LOGGING=true TYPESCRIPT_FAIL_ON_COMPILATION_ERRORS=1 METEOR_IGNORE=$(server/buildmeteorignore $INCLUDE_RANGE) TEST_CLIENT=0 MOCHA_REPORTER=xunit MOCHA_TIMEOUT=60000 SERVER_MOCHA_OUTPUT=$PWD/mocha/${MOCHA_OUTPUT_FILE:-results}.xml meteor test --once --driver-package meteortesting:mocha --exclude-archs web.browser.legacy --port \"[::]:${PORT:-3000}\"'",    

with buildmeteorignore being:

#!/usr/bin/env bash
# builds contents for METEOR_IGNORE to include only test files that start with
# the character range provided as arg1
# OR with invert as arg2 to EXCLUDE that character range
# TEST_PREFIX is set to "app-" when running ui tests since then the test files are named XX.XX.app-tests.ts
echo "# Generated METEOR_IGNORE contents"

if [[ -z $1 ]]; then
    # no argument => no contents
    exit
fi

RANGE=${1:-a-z}
if [[ $2 == invert ]]; then
    PREFIX=""
else
    echo "*.${TEST_PREFIX}tests.ts"
    PREFIX="!"
fi

# for debugging
# echo >&2 RANGE=$RANGE PREFIX=$PREFIX

echo $PREFIX[$RANGE]*.${TEST_PREFIX}tests.ts

/me checking the Meteor Forums every day, to see if the new 3.4 RSPack release has shipped yet.

4 Likes

Same! :joy: It’s in my muscle memory now first thing in the morning I type “for” and this thread on the forums autocompletes in my chrome address bar.

Definitely anxious for an RC to try with my projects!

2 Likes

Thanks to everyone who voted. Most projects already use the expected package.json entrypoints in Meteor’s config.

For those who don’t but know how to adapt them, that’s great. For those who don’t and need help, please reach me privately via DM in the forums. Over the coming weeks, while the beta is running, I’ll assist on adapting projects. I’ll also work to understand how to add entrypoints to projects without them by the approach mentioned above. @vikr00001 let’s move this to private messages, I’ll DM you when available.

For tests, projects still use both eager runs and full-app mode. I’ve updated the Rspack integration to support all test setups, and results look fine. Whether you use testModule with separate configs for client and server, a single config, no testModule at all with the eager approach, or run --full-app, everything pass as expected. :white_check_mark:


@permb your approach to partitioning tests with Meteor ignore is solid. Since Meteor was the bundler in charge, that worked well. With the new Rspack integration, METEOR_IGNORE now applies broadly to source code (including tests), and delegation goes to Rspack. To achieve a similar setup you’ll need to use rspack.config.js at your project root with the Rspack IgnorePlugin, for example:

import path from "path";
import { IgnorePlugin } from "@rspack/core";
import { defineConfig } from "@meteorjs/rspack";

export default defineConfig(Meteor => {
  const range = process.env.TEST_RANGE || "a-z";         // e.g. "a-m"
  const invert = process.env.TEST_INVERT === "true";     // "true" to exclude range
  const testPrefix = Meteor.isTestApp ? "app-" : "";     // matches ".app-tests.ts" vs ".tests.ts"
  const testSuffix = `.${testPrefix}tests.ts`;
  const rangeRe = new RegExp(`^[${range}]`);

  return {
    plugins: [
      ...(Meteor.isTest || Meteor.isTestApp
        ? [
            new IgnorePlugin({
              checkResource(resource) {
                const filename = path.basename(resource);
                // Only act on test files with the expected suffix
                if (!filename.endsWith(testSuffix)) return false;
                const inRange = rangeRe.test(filename);
                return invert ? inRange : !inRange;
              },
            }),
          ]
        : []),
    ],
  };
});

This is just an example to show how rspack.config.js is introduced in Meteor projects. The code snippet above is not tested, but should work similarly in your env once you adopt Rspack.

The rspack.config.js file lets you customize your Rspack setup with plugins and configurations, acting directly on the modern bundler process. Meteor now only handles Atmosphere packages and linking app code with the Meteor core.

Keep in mind Rspack is optional, but if you opt in, you’ll need to adjust parts of your current setup, at least for more complex projects.

3 Likes

I’m really excited about all the attention this integration is getting. Like many of you, I can’t wait to see it evolve. This will go through several betas before a stable RC, but it’s worth it. The benefits are huge for Meteor users: better performance, smaller bundles, and new features. What’s even better is how much ground a single integration already covers, solving long-standing bundler issues that would have been nearly impossible to address one by one with a small team.

A quick update on the state: our initial goal was to ship the first beta in August. But after the releases of 3.3.1, 3.3.2, and 2.16.2, plus some uncovered Rspack integration details (like full support for Meteor test options), the timeline has slipped a bit.

The good news is we now support all official Meteor skeleton projects: React, TypeScript, Blaze, CoffeeScript, Solid, Svelte, and Vue. Angular experiments may follow after the first beta. Some setups need small migration steps, but they’re straightforward and already covered in the Rspack docs with clear rspack.config.js examples.

To ensure stability and avoid regressions, we’ve built a new modern test suite. It runs across all skeletons and checks key things: server responses, page rendering, dev/prod builds, and multiple configurations. Every skeleton now passes these tests as shown in the picture.

The suite also goes beyond skeleton coverage. It validates critical features and past Meteor limitations: HMR, dynamic imports, custom aliases with file and node_module redirects, SWC/Babel configs, React compiler, ESM imports (like react-router v7), style compilers (Less, SCSS, Tailwind), and more. This gives us a strong base to add tests/features without breaking existing ones. Before, skeletons had no tests at all, some even broken over time.

What’s left now is documentation and final cleanup before the PR. I expect to try an internal beta next week. Public beta will take longer, since I want to ensure published version works as from checkout tests, deployment on Galaxy and docs readiness. Realistically, that means at least one more week if everything goes well. In the meantime, I’ll share more details in this post about migration steps and integration benefits so you can start preparing.

9 Likes