3.4-rc.1 Release Candidate, Faster Builds, Smaller Bundles and Modern Setups with the Rspack integration ⚡

Thank you.

Your input has been determinant for me to understand the issue and provide a quick fix.

I will include this on the next RC version as well as all other last critical/quick fixes reported.


Regarding the CI, I’m not sure what the problem is. Could it be from the CI environment itself? Maybe a missing timeout or something similar. Exit code 137 usually means the OS/CI killed the process because it was using too many resources, like RAM. Maybe you need to tweak the limits.

I know that by removing the entry in .meteorignore it will load more things until it crashes, maybe. Or maybe running the tests eagerly requires more RAM. I don’t know for sure without a way to further debug that scenario. Could you try to run just few tests first by removing most of them, and incrementally enable them to see the crash point?

Release candidate available: 3.4-rc.1. This release brings the last round of critical and quick fixes reported, now in a stable and test-covered state for the Rspack integration, build improvements, and recent contributions. All this moves Meteor forward into the new era of tools and improvements.

  • Review and fix legacy builds for the SWC modern transpiler and Rspack integration.
  • Support browser tests in full app mode.
  • Ensure Meteor.compileWithRspack accepts SWC rule options as the second parameter.
  • Add new config helper Meteor.extendConfig(obj1, obj2, ...) to merge custom objects safely.
  • Install tool dependencies as part of meteor update and improve related messages.
  • Update SWC core to latest 1.15.3 and Rspack minumum 1.6.5

We also included the last community contribution originally planned for the release but delayed while solving test stability:

React packages also bumped for its RC version:

With this RC, we enter the final steps before the official Meteor 3.4 announcement. From now on, we will review docs and tutorials in case bundler details need updates for the Rspack integration, work on CI internals for Rspack test coverage, and prepare the final release materials. This is the last call for reporting critical issues so we can expand coverage if needed. Non-critical items will move to the Meteor 3.4.x series.


Remember to check out the docs for details of the new modern build stack.

:page_with_curl: Modern Build Stack docs

:comet: Meteor Bundler optimizations docs

:zap: Rspack Bundler integration docs

10 Likes

Just some more details about the circleci issue:

It does look like this is using a full 4GB of RAM and all of the CPU usage:

I paired down the number of tests added (to only 3 server tests) and got this

Rspack Test failed in Client with exit code 1
meteor://💻app/packages/rspack_plugin.js:1449
              const error = new Error("Rspack ".concat(label, " failed in ").concat(endpoint, " with exit code ").concat(code));
                            ^

Error: Rspack Test failed in Client with exit code 1
    at Object.onExit (packages/rspack/lib/processes.js:485:25)
    at ChildProcess.<anonymous> (packages/tools-core/lib/process.js:51:33)
    at ChildProcess.emit (node:events:519:28)
    at maybeClose (node:internal/child_process:1101:16)
    at Socket.<anonymous> (node:internal/child_process:456:11)
    at Socket.emit (node:events:519:28)
    at Pipe.<anonymous> (node:net:346:12)
    at Pipe.callbackTrampoline (node:internal/async_hooks:130:17)

Node.js v22.21.1

Exited with code exit status 1

Edit:
I figured out at least part of the issue.
In meteor 3.3:
server unit tests would load only stuff under /server folders
client unit tests would load only stuff under /client folders
That means other files would not be loaded at all

In meteor 3.4
server unit tests load anything not under /client folders
client unit tests load anything not under /server folders
That means other files would be loaded in both contexts

I’m working to see what exactly is making this fail on my end

2 Likes

Remember that with .meteorignore / METEOR_IGNORE you can set exclusions that will affect the test eager loading mechanism as well. You could, for example, ignore only in the CI context or when running tests in specific heavy paths.

In meteor 3.3:
server unit tests would load only stuff under /server folders
client unit tests would load only stuff under /client folders
That means other files would not be loaded at all

Are you sure? If so, how would it load tests from imports/, tests/ or other folders?

Meteor 3.4 with Rspack ensures it can eagerly load from all contexts, with the exception of the client folders when running server tests, and the server folders when running client tests.

Let us know what you find.

By the way, I also had some issues with GitHub Actions CI exiting with code 137. Since these instances are shared, I added a retry mechanism, as sometimes could randomly killed there. After some research I found that one specific test coverage job using the full Rspack setup (Jest and Playwright) also used ts-checker-rspack-plugin, which turned out to be very resource intensive, and being killed almost all time. Disabling it made the job pass consistently. Saying this in case your project may also use this plugin. It could be better to disable it for the purpose of passing runtime app tests.

Hello there, I’m trying out 3.4-rc.1. Thanks for all the latest updates to Meteor

I have a problem with an app, it seems not to be running fine.

Server does not seem to print some logs I have for startup, also it is warning about some imports but these are packages installed, so I can’t really fix the code (is there a way to fix these warnings)

And client, when loading via browser, is fully blank, like it has crashed or router was not working

=> Started proxy.                             
[Rspack Server Error] [.swcrc] Ignored custom "jsc.target" — reserved for Meteor-Rspack integration.

[Rspack Client Error] [.swcrc] Ignored custom "jsc.target" — reserved for Meteor-Rspack integration.

[Rspack Client] <i> [webpack-dev-server] Project is running at:

[Rspack Client] <i> [webpack-dev-server] Loopback: http://localhost:8081/, http://[::1]:8081/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.1.39:8081/
<i> [webpack-dev-server] Content not from webpack is served from '/home/ferjep/yourdnafamily/admin/public' directory

[Rspack Client] [client-rspack]:
  [client-rspack] compiled successfully in 82 ms

[Rspack Server] [server-rspack]:package ...  -
  WARNING in ./node_modules/bullmq/dist/esm/classes/child-processor.js
    ⚠ Critical dependency: the request of a dependency is an expression
      ╭─[26:58]
   24 │         let processor;
   25 │         try {
   26 │             const { default: processorFn } = await import(processorFile);
      ·                                                           ─────────────
   27 │             processor = processorFn;
   28 │             if (processor.default) {
      ╰────
  

  WARNING in ./node_modules/express/lib/view.js 81:13-25
    ⚠ Critical dependency: the request of a dependency is an expression
      ╭─[81:21]
   79 │ 
   80 │     // default engine export
   81 │     var fn = require(mod).__express
      ·                      ───
   82 │ 
   83 │     if (typeof fn !== 'function') {
      ╰────
  

  [server-rspack] compiled with 2 warnings in 319 ms

=> Started your app.                          

=> App running at: http://localhost:3001/

Which error logs are you getting on the client browser console?

Ideally, I would like to have a minimal reproduction in a repository. A project that triggers these errors on both server and client would help me understand them and explore possible solutions for each case if needed.

These are the DEV console logs. Nothing suspicious

image

Yeah I think the best is to create a repo and try to get it replicated. I’ll let you know.

Thanks for your help!

Are you sure? If so, how would it load tests from imports/ , tests/ or other folders?

It just wouldn’t, which means my tests were silently hiding.

     Error: Timeout of 30000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
      at listOnTimeout (node:internal/timers:588:17)
      at processTimers (node:internal/timers:523:7)




--------------------------------
----- RUNNING CLIENT TESTS -----
--------------------------------

Killed

Exited with code exit status 137

I got my server tests to run on circle ci (there are a bunch of unexpected failures I will have to investigate) but the client tests still exit with status 137.

I actually do not have a single client test left.

On my personal computer I am still often getting into a case where I am getting this error

=> Started MongoDB.                           
[Rspack Test Client] [test-client-rspack]:.  /
  [test-client-rspack] compiled successfully in 387 ms

[Rspack Test Server] [test-server-rspack]:.  -
  [test-server-rspack] compiled successfully in 813 ms



<--- Last few GCs --->

[39303:0x138008000]    66602 ms: Mark-Compact 4014.2 (4131.7) -> 3999.8 (4132.9) MB, pooled: 0 MB, 881.75 / 0.00 ms  (average mu = 0.419, current mu = 0.014) allocation failure; scavenge might not succeed
[39303:0x138008000]    68014 ms: Mark-Compact 4020.9 (4144.0) -> 4012.6 (4147.3) MB, pooled: 0 MB, 1241.75 / 0.00 ms  (average mu = 0.273, current mu = 0.121) allocation failure; GC in old space requested


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

I have to delete the _build folder to resolve it.

Is there anyway to debug this more effectively?

I never had these issues on 3.3

I will need more time to dive into your use case and pay attention to resource consumption as well. I just see it working, and I’m not sure what causes the high resource usage in some environments. This might be due to the project size, test eager mode, Rspack, or a mix of all of them.

Something I have noted are issues related to cache. Have you tried running rspack.config.js with: …Meteor.setCache(false)

This is the same as using:

cache: false, // disable cache
experiments: {
  cache: false // disable persistent cache (experimental flag)
}

Does this help with the issues? I don’t think test eager mode would use it, but it may still be affected by other problems we’ve seen around cache usage and resources. I also saw these were supposedly solved in the latest Rspack versions. But who knows… it may be worth to try if improves without it. If with cache the experience improves, we can consider disabling it by default when running tests in eager mode.

Ok @nachocodoner I seem to have managed to fix the issue with large memory usage in production. Looks really good now both client and server side.

Up until 3.3 it was not possible to cache split code via a CDN because thouse were fetched with a POST call.
With 3.4 … SURPRISE :smiley: “Hit from cloudfront.”
It is now fine to throw those massive libraries in the main bundle and split the code and not worry that your Node server turns into a file server.

I am really happy with where we are now.

5 Likes

Was any particular rspack.config.js utilized to enable this?

Indeed, this is another benefit of embracing standards established in bundlers for a long time, where the Meteor bundler had fallen behind. Every split of chunks you create using Rspack generates files as assets and serves them through the standard HTTP protocol. So you get the same benefits you would get from any other asset, like the one you mentioned.

Rspack’s split chunks are now loaded via standard HTTP GET requests, just like any other static asset, meaning:

  • A CDN (CloudFront, Cloudflare, etc.) can now cache these chunks.
  • When the client requests a dynamic chunk, the CDN returns it instead of your Node server.
  • As a result, the server no longer uses memory or CPU serving large JS files.
  • You finally get the real performance benefits of code-splitting: smaller initial bundles and offloaded traffic.

And the same advantage applies if you use a Service Worker: because chunks are now standard HTTP assets, a Service Worker can intercept and cache them efficiently as well. This gives you offline support and near-instant reloads of cached chunks, further reducing load on the server and improving the perceived performance of your app.

Glad you shared this example with all of us, so anyone can see what this means in practice.

By the way, I recommend checking the Rspack docs to understand the different ways to split your chunks. Besides that, we added Meteor helper for the rspack.config.js to easily split your vendor chunk (node_modules) with Meteor.splitVendorChunk. But there are customized way to act on these with Rspack’s SplitChunksPlugin.

6 Likes

I tried to get it done from the rspack.config.js but for some reasons that configuration was not passed to the “global” settings which were considered for building production.
I then used the official Rspack documentation, and that led me to success.

This didn’t work:

export default {
  output: {
    // this is the default value when `target` is `'web'` or `'webworker'`
    publicPath: 'auto',
  },
};

This worked:

__webpack_public_path__ = "your_cdn_url"

I already had a CDN serving my bundle files, so the final solution was literally 1 line of code. This line of code came after 3 hours of AI useless chatting :))). I would think I use the best tools for AI, the RouteLLM inside ChatLLM of Abacus.ai which selects the most “competent” AI provider depending on the nature of the conversation. These tools are moving too fast and make all LLMs pretty much useless. I learnt again that the official documentation is still the best source of information.

  • I created a new file in /app/client.
  • I added this to the file __webpack_public_path__ = "your_cdn_url"
  • I imported the file at the top of /app/client/main.js
3 Likes

Oh, I think I accidentally blocked publicPath from being overrided in the rspack.config.js config. Did you get a message saying Ignored custom "output.publicPath", reserved for Meteor-Rspack integration.?

In a future release I will remove this restriction. It should be fine for you to set publicPath as you need, at least for the production build. Because in development you don’t have the publicPath set, right? But you might need it for debugging purposes.

1 Like

I didn’t get any message. Got help from AI to create a pluging and printed out the configuration involved in the production build.

import { defineConfig } from '@meteorjs/rspack'
import { DefinePlugin } from '@rspack/core'
import fs from 'fs'
import path from 'path'

// const FALLBACK_CDN = 'https://cdn.activitree.com'
// const cdn = process.env.CDN_URL || FALLBACK_CDN

// Custom plugin to dump the final config
class DumpConfigPlugin {
  apply(compiler) {
    compiler.hooks.afterEnvironment.tap('DumpConfigPlugin', () => {
      const finalConfig = compiler.options
      const targetLabel = finalConfig.target || 'unknown'
      
      console.log(`\n========== FINAL RSPACK CONFIG (${targetLabel}) ==========`)
      console.log(JSON.stringify(finalConfig, null, 2))
      console.log('========== END CONFIG ==========\n')
      
      // Optionally write to file
      const filename = `rspack-final-config-${targetLabel}.json`
      fs.writeFileSync(
        path.join(process.cwd(), filename),
        JSON.stringify(finalConfig, null, 2)
      )
      console.log(`[DumpConfigPlugin] Config written to ${filename}`)
    })
  }
}

export default defineConfig(Meteor => {
  // const isProd = Meteor.isProduction === true
  // const assetPrefix = isProd ? `${cdn}/` : undefined

  return {
    output: {
       // this is the default value when `target` is `'web'` or `'webworker'`
       publicPath: // this is where you add cdn url for production and 'auto' or '/' or undefined for development 
       // some AI sources suggested the use of 'assetPrefix' instead of publicPath
    },
    parser: { javascript: { dynamicImportMode: 'lazy' } },
    plugins: [  
      // Add this plugin to dump final config
      new DumpConfigPlugin(),
    ]
  }
})

Separate log files for server and client are being created in the root directory.
In the client side, publicPath always shows ‘/’

Ok, I will do some tests. But I’m pretty sure that the publicPath always showing / is caused by an override on Meteor Rspack plugin. I’ll review to overcome this and let anyone set it here in any value they like. Thanks to bring this up!

1 Like

Cloudflare is my CDN. Is “your_cdn_url” identical to the public-facing, regular URL for my site?

Hello @nachocodoner! A question: by default, in rspack.config.js, jsc.target for builtin:swc-loader is set to es2015 (ref)

In our .swcrc config we have

{
  "jsc": {
    "target": "es2020"
  }
}

But the jsc.target option is explicitly omitted when .swcrc settings are merged into rspack.config.js (ref). There’s no info in the commit why is it so. Could you please explain why it’s important to keep it as es2015?

Obviously, we’re still able to override the jsc.target with Meteor.extendSwcConfig helper:

...Meteor.extendSwcConfig({
  jsc: {
    ...Meteor.swcConfigOptions.jsc,
    target: "es2020",
  },
}),

but curious what the consequences will be. Thanks!

1 Like

I rules I had to add the full rule to get to 2023. I copied it from the log I see in my debug console as the project starts. Even so, I still don’t know if this is this overwrites the default configuration entirely.

rules: [
      {
        test: /\.(?:[mc]?js|jsx|[mc]?ts|tsx)$/i,
        exclude: /node_modules|\.meteor\/local/,
        loader: 'builtin:swc-loader',
        options: {
          jsc: {
            baseUrl: '/Users/paulailincai/Projects/activitree/app',
            paths: { '/*': [ '*', '/*' ] },
            parser: { syntax: 'ecmascript', jsx: true, decorators: true },
            target: 'es2023',
            transform: {
              react: {
                development: true,
                refresh: true,
                runtime: 'automatic'
              }
            },
            externalHelpers: true
          },
          module: { type: 'es6', strict: true }
        }
      }
]