Meteor Codebase Standardization

Meteor Codebase Standardization

[edit]
After a poll with 10 votes dor OXC vs 0 to Biome we can follow with OXC for formatting and lintering the pkgs


[RFC] Gradual Code Standardization with Biome across Meteor packages

Hi Meteor community!

We’d like to share a plan and invite everyone to participate in a long-overdue modernization effort: gradually introducing formater/linter across the Meteor core packages.

Background

The Meteor codebase is large, mature, and historically inconsistent in its formatting and linting conventions. Different packages use different indentation styles, quote types, semicolon usage, and have little to no automated style enforcement. This makes contributing harder than it needs to be(especially for newcomers) and slows down code reviews with style-related noise.

What we’re proposing

A phased, careful rollout of:

  • Code formatting using the default values
  • Linter (with a gradual rule set) for code quality and modern JavaScript patterns

We are not doing a massive one-shot reformat of the entire codebase. Instead, we’ll proceed package by package, starting with less-trafficked packages to minimize risk and disruption.

Why phased?

  • Avoids massive diffs that break git blame everywhere at once
  • Lets us validate the tooling config on lower-risk packages first
  • Gives the community time to review and provide feedback at each step
  • Reduces the chance of introducing regressions in critical packages

How you can help

  • Review the config: we’ll open PRs for each phase with the proposed Biome config
  • Adopt for your package: if you maintain a package that lives in this repo, reach out or open a PR following the established config
  • Report issues: if formatting changes cause unexpected behavior (it shouldn’t, but let’s be safe), open an issue

Timeline

We’ll proceed in multiple phases over several months. Each phase will have its own tracking issue and PRs. No phase will be merged without community review.

We’ll post updates in this thread as we progress.

Looking forward to working on this with you all. Let’s make contributing to Meteor a smoother experience!


Phase Plan: Meteor Code Standardization

Code formatter

// TODO

Linter

Phase 1 - Maybe wont have impact:

  • noUnusedVariables
  • useConst
  • useTemplate

Phase 2 - We should mensure the impact:

  • noVar
  • noDoubleEquals
  • noUndeclaredVariables
  • noDuplicateImports
  • useArrowFunction

Subphases per package

For each package, the work is split into subphases:

Subphase Action Risk
A Apply formatter Low
B Apply linter with basic rules ( noUnusedVariables, noDoubleEquals, useConst) Low-Medium
C Apply linter with modern rules ( noVar, useTemplate, etc.) Medium

Subphase C is optional and can be done in a later iteration, separate from B.


Phase 1 — Non-core packages (lowest risk, lowest traffic)

Location: packages/non-core/

Package Subphase A Subphase B Subphase C
geojson-utils
mongo-decimal
xmlbuilder
bundle-visualizer
facts-base
facts-ui

Phase 2 — Simple utility packages

Low-complexity packages with no critical runtime dependencies.

Package Subphase A Subphase B Subphase C
base64
binary-heap
diff-sequence
callback-hook
ejson
check
random
id-map
ordered-dict
rate-limit
retry
sha
url

Phase 3 — Infrastructure packages (moderate)

Packages used internally by the build system or with limited production usage.

Package Subphase A Subphase B Subphase C
boilerplate-generator
browser-policy-common
browser-policy-content
browser-policy-framing
browser-policy
caching-compiler
force-ssl-common
force-ssl
audit-argument-checks
ddp-rate-limiter
allow-deny
email

Phase 4 — Authentication packages

Heavily used but with a well-defined scope. Require extra attention in tests.

Package Subphase A Subphase B Subphase C
accounts-base
accounts-password
accounts-oauth
accounts-ui
accounts-ui-unstyled
accounts-passwordless
accounts-2fa

Phase 5 — Reactivity and data packages

Core of the Meteor experience. High risk — requires extensive testing before each merge.

Package Subphase A Subphase B Subphase C
tracker
reactive-var
reactive-dict
minimongo
mongo

Phase 6 — DDP and transport packages

Critical for client-server communication. Highest risk.

Package Subphase A Subphase B Subphase C
ddp-common
ddp-client
ddp-server
ddp

Phase 7 — Build and runtime packages (high risk)

Package Subphase A Subphase B Subphase C
ecmascript
ecmascript-runtime
babel-compiler
webapp
autoupdate
reload
dynamic-import

Phase 8 — tools/ (CLI and Isobuild)

The tools/ directory is Meteor’s build system (Isobuild + CLI). Requires its own phase with special care, as any regression here breaks the entire toolchain.

  • Subphase A: Formatter on tools/ (excluding generated files)
  • Subphase B: LINTER basic rules
  • Subphase C: LINTER modern rules

Completion criteria per package

A package is considered complete in a subphase when:

  1. The PR was opened with only the formatting/lint changes for that subphase
  2. Existing package tests continue to pass (./meteor test-packages ./packages/<name>)
  3. No logic was changed — style only
  4. The PR was reviewed and approved by at least one maintainer
  5. The package config file (if any) was updated to reference the root config

Important notes

  • Formatting commits must be isolated — never mix refactor/feature with formater/lint in the same PR
  • git blame can be preserved with .git-blame-ignore-revs — add the SHA of each formatting commit to the .git-blame-ignore-revs file at the root
  • Packages with missing or incomplete tests should have tests added before subphase C
  • Deprecated or inactive packages can be skipped or archived
8 Likes

Are you set on Biome?

Have you seen https://oxc.rs/

What are your thoughts on it? Seems more “modular” to integrate the right packages within Meteor’s tooling.

4 Likes

I have been using Biome and have been pretty happy with it.
OXC seems to me to make sense if Meteor was going towards the Vite ecosystem, but currently it is not. It could still be adopted and I have heard that it might eventually kill Biome. That said its parses is still in Beta.

@italojs still worth looking at OXC, maybe we should think about making the structure so that if needed we could switch with minimal effort.

3 Likes

not yet, we can discuss it better and choose togheter, I’ll take a look into oxc :wink:

Somewhat related but:

What is the state of typescript and type generation for meteor packages?

I’m not familiar with it meteor package development, but is there “tsup” or “tsdown” equivalent for meteor packages?

1 Like

From what I recall, atm the current state is still the one described in the docs:

We plan to give some love to this soon.

It is in our roadmap: Roadmap | Docs

On a macro level this is a good step for Meteor but on a micro level this still needs some refining. Biome and OXC got mentioned but no https://rslint.rs/

Actually we’re in a bit of a conundrum post 3.4. Do we double down on the entire RS stack or only keep what’s useful? @nachocodoner

I think this would be a good opportunity for Meteor to issue a standardized linting guide as the current eslint ones have fallen out of favor. meteor/npm-packages/eslint-config-meteor at 86a32d99841e682fc23e52bb58f30ee0e8a88fc1 · meteor/meteor · GitHub

2 Likes

Good call. With RSPack integration it makes more sense to integrate further with RS ecosystem.

1 Like

And this is why a public discussion helps a lot. The original decision is not to implement this directly with a closed decision, but to discuss it with the whole community. Many eyes are better than a few.

About using rslint, I would not necessarily encourage us to use the whole Rust ecosystem as the main reason. It is true that it has benefits, and we have already done that with Rust through SWC and Rspack, but for instance rslint is not even stable yet. It is still in early development. So it is important to understand the project’s current status and what limitations we would have.

According to rslint, it claims compatibility with most ESLint and TypeScript-ESLint configurations to reduce migration costs, and it ships with existing TypeScript-ESLint rules and widely used ESLint rules out of the box. It also delivers 20-40x faster linting than traditional ESLint. It is currently in an experimental phase, but under active development. The latest release is v0.2.3 from last week. So it seems promising and active.

Anyway, the Meteor codebase currently does not have a well-applied linter strategy, so starting with one, even something as simple as rslint, is already better than having nothing at all. We can try reusing ESLint definitions and see what happens, or start fresh with what rslint supports at the moment. Since this is an incremental effort, adoption can also move together with rslint as it matures toward more stable versions.

I tend to favor the stacks we have already invested effort in. To me, it seems like a good choice to grow with it together with the other Rspack tools and future collaborations in the same ecosystem. But I also understand that if we find strong limitations, or signs of inactive development, we should choose something else. In this specific moment, I do not think that is the case, or at least not until we have more practical experience with it.

Also, more than the specific tool to use, this is about enforcing a convention and guidelines for the core and Meteor contributors. So it is more about creating a habit and a standard. The tool is important, but if we stay within the ESLint compatibility and standards umbrella, moving and migrating across tools will be easy.

1 Like

I just noticed in the README that it’s actually written in Go so we can’t adopt it! u.u

Jokes aside, here is my take:

IMO unfortinately we don’t currently have capacity enougth to support another tool and While it’s a cool project(i’m really curious to contrib into rspack ecosystem with rust), it would distract us from Meteor, which already requires a lot of our attention.

Biome vs OXC:

Biome looks like more plug and play while oxc is more “low level”, btw biome uses oxc:
The resolution of the dependencies is powered by the library oxc-resolver, one of the many libraries provided by the OXC project. It’s battle-tested and spec compliant!

Second Perplexity, OXC is more for our case, but idk, still thin the simpler is better

Practical recommendation
	•	If you just want to replace Prettier + ESLint in a product repo with minimal fuss and good editor behavior, Biome is the safer, more ergonomic choice today.
	•	If you are building tooling (bundlers, custom compilers) or want to bet on a unified, ultra‑fast Rust toolchain (transform/minify/resolve, not just lint/format), leaning into Oxc (Oxlint + Oxfmt + parser) makes more sense.
1 Like

Biome is very opinionated by default, something many of us wished Meteor to be (again). At the same time, biome rules comply with rspack requirements. To me the biggest pro biome point is, that it’s not only a linter but also formatter and extends beyond js, if desired.

2 Likes

I researched OXC a bit, and it seems it could be the tool that best fits us now and later. It implements many components, all written in Rust, that could be useful not only to ensure linting and formatting, but also as tools that can be used as part of the bundler to get more out of it.

As you know, we adopted Rspack in Meteor 3.4, which uses SWC via builtin:swc-loader. The builtin: part means SWC runs entirely inside Rspack’s Rust process with no JS bridge overhead. Rspack has shown some interest in OXC recently. It used OXC’s resolver but later forked it, and community packages let you use OXC as a transformer (oxc-webpack-loader or unplugin-oxc), but they lose the builtin: advantage through the JS bridge. Rspack’s 2.0 roadmap does not mention OXC for core transpilation, and the team seems more inclined to build its own tooling. It could happen that other tooling like Rslint use directly OXC at some point. Deeper integration may or may not happen, but at least there have already been moves toward its benefits in some bundler parts.

Worth noting that Rolldown, Vite 8’s bundler, already bets on this fully, using OXC for parsing, transformation, and minification. This is where toolchain fatigue feels real. Babel to SWC was 20x faster. Webpack to Rspack was 23x faster. Now OXC is apparently 3x faster than SWC. Each leap is meaningful, but none of them are just optimizations. They are architectural rewrites that result in better memory allocation, unified ASTs, and tighter coupling from day one. A newer tool starts with the lessons of the previous one, and the cycle repeats.

That makes doing this at the Meteor level worthwhile on its own. By adopting it as the linter, it would be good to start experimenting with the tool. It may or may not become part of Rspack at some point, officially or through the community, as already happens today. If it really claims to be faster and users can measure that, it can be a tool ecosystem worth investing resources in. I can also see OXC being part of Meteor atmosphere package processing as a replacement for SWC, to theoretically gain 3x faster builds in package compilation or in Meteor apps using the pure bundler. I am not sure yet about SWC/Babel plugin support for the transpiler, though. Anyway, for the moment, and seeing how quickly the ecosystem evolves, that 3x gain may not be worth it yet. We could wait and see what direction Rspack takes regarding OXC adoption before making a core decision.

With this, I just want to say that OXC is a really interesting tool that we could explore and gain experience with for later benefit, even for Meteor core integration. I remember some community member already shared it before or even opened a PR recently adopting the parser (experiment(isobuild): Isobuild Performance Optimizations by mvogttech · Pull Request #14218 · meteor/meteor · GitHub), so now that we have the chance to adopt it, I would go with it.

So after all this discussion, my preference would be to focus on adopting OXC as the linting and formatting tool, with the possibility of benefiting from other areas it touches later, and knowing it’s the approach followed by Vite’s next-gen bundler.

What do you think?

1 Like

I opened the Isobuild experiment PR – I chose to implement OXC during my experiment to modernize the build tool because of Vite’s adoption.

2 Likes

Let’s vote and hit the hammer

  • OXC
  • Biome
  • Other
0 voters

I appreciate all the work y’all have put into making Rspack work with Meteor. Fwiw, it seems to me OXC / Vite ecosystem is the better long term bet.

2 Likes

It can be. When integrating Rspack, Vite did not look promising, neither in speed nor in how easy it was to integrate and make it work smoothly with the Vite-Meteor HMR server, without hard rewrites to perserve Meteor’s specifics and similar changes. I talked about it in this Twitter thread: https://x.com/nachocodoner/status/2022270373216108945

In parallel, Vite v8 has made huge efforts to add Rolldown and integrate the OXC ecosystem. So the approach followed with Rspack for a smoother and easier integration could be revisited, and it may be possible. Anyway, Meteor 3.4 was focused on making sure we got the gains the community wanted so their apps could evolve on the bundler side. That was the best reason to move forward, making sure we could deliver the best speed, but also all the other features around it. Rspack passed that test easily.

Anyway, we will see what the future brings to the JS ecosystem. The fatigue and hype around tools is real. Every time, a new tool appears that beats the previous one in speed, resource usage, or features. It’s crazy.

Nowadays we are in a really good spot on bundler features, but it’s good to see opportunities on the horizon. More importantly, what matters is how easily those tools can be integrated with Meteor’s specifics.

Maybe at some point, once we are further along with the next roadmap items (native, ddp, testing infra rework, core code quality and so on), we can see whether Vite v8 with its latest improvements could be an Atmosphere package option like rspack, mirroring the approach of this package but with Vite.

2 Likes

JS fatigue is definitely real :slight_smile: . Feels like it’s been this way for ~15 years or so.

2 Likes

Don’t worry just 10 more years and it’ll be fixed… maybe… hopefully :crossed_fingers:

2 Likes

FIY: I’m preparing a PR with the base OXC config where we will be able to discuss about the best formatting config