I have a Meteor Package that depends on the zod library via import * as z from "zod" . Unfortunately, zod only provides a modern version, and when building the application, no legacy version is built for this package.
I know that if this were a regular NPM package, I could use either:
meteor.nodeModules.recompile.zod in package.json , or
Meteor.compileWithRspack(['zod']) in rspack.config.js
However, I can’t seem to find a way to achieve this within a Meteor package context.
Has anyone encountered this issue or found a better solution for forcing legacy builds of NPM dependencies within Meteor packages?
In case the link expires one day, this suggests adding the NPM to the main project and recompiling it with meteor.nodeModules.recompile.zod: [‘legacy’]. Do not add it to the package.js of the project. Use meteor/tmeasday:check-npm-versions to lock NPM version and use the NPM as a peer dependency.
I am actually curious if this works :).
// server side
import { checkNpmVersions } from 'meteor/tmeasday:check-npm-versions';
checkNpmVersions({
'problematic-npm-package': '^2.0.0', // Specify the required version range
'another-needed-pkg': '1.x.x'
}, 'my:package'); // Replace 'my:package' with your package's actual name
// Now you can import/require the package; it expects the app to have installed it
// This runs on the server, but the app developer installs it at the app level
const ProblematicPackage = require('problematic-npm-package');
Thanks for your response. However, based on my experiments, the meteor.nodeModules.recompile option only takes effect for the node_modules within the project itself. It doesn’t work for NPM dependencies inside Atmosphere packages. While Atmosphere packages can compile their own legacy code via the ecmascript dependency, any NPM dependencies within them are simply copied as-is without recompilation.
You do not have an NPM inside your Meteor package anymore. You have it in the top level of the project and just use it inside the package. I remember I do this a lot to prevent having to update Meteor packages when NPM moves up fast (e.g. aws packages which release a new version almost every day). I do not need to recompile to legacy but I do use inside Meteor packages libraries of the top dependencies.
I did exactly as you suggested by not using Npm.depends in package.js, but in bundle/programs/web.browser.legacy/***.js, the modern version of Zod is still being included.
I tried removing import { z } from ‘zod’ from the Atmosphere package and did a rebuild, and then the Zod version in web.browser.legacy/***.js became the legacy version. It appears that Meteor follows the import statements and copies the corresponding modules from node_modules into the bundle.
As I understand it, Atmosphere packages can’t treat Npm.depends dependencies as modern modules, so they won’t be understood or processed that way.
This is another reason to move Atmosphere packages to local NPM packages instead. Atmosphere has long-standing limits and few recent changes, aside from bundle size work in 3.4. Standard NPM packages avoid those limits and prepare you for the future.
So, is there anything in your package code setup blocking to move to a NPM package instead of an Atmosphere one? I’d only use Atmosphere when you need to hook the bundler or Meteor runtime lifecycle in a specific way, or you can be 100% compatibility. For incompatibilities or in general, I’d shift them to NPM packages so the code lives in your app and you can handle it with recompile or rspack’s compileWithRspack helper.
Feel free to open a Meteor tracker issue for future support. I’d still prioritize moving to standard, easy-to-integrate NPM packages.
Thanks for your reply. I tried migrating to a local NPM package, but I found that when I import and run the package on the Meteor server, it throws an error: “Error: Cannot find module ‘meteor/meteor’”. However, when I import the package on the Meteor client, ‘meteor/meteor’ can be injected normally. I originally thought this was an abnormal usage, so I’ll go ahead and submit an issue about it.