reactive-publish
reactive-publish
is a Meteor package that adds reactive publishing with async support. It's based on peerlibrary:reactive-publish, fully overhauled for compatibility with Meteor 3 and its fiber-free environment.
-
🔄 Reactively publish data with related field changes across collections
-
⚙️ Supports
autorun
in publication functions for realtime updates -
🧵 Integrates
AsyncTracker
andReactiveVarAsync
for async-compatible reactivity -
🚀 Optimized with unique cursors per computation to avoid redundant re-instantiation
🔥 Learn about the motivation for reviving this package for Meteor 3.
🗺️ Explore the roadmap for future updates and support.
Installation
meteor add nachocodoner:reactive-publish@1.0.0-alpha.2
Usage
Basic
1Meteor.publish('subscribed-posts', function () { 2 this.autorun(async () => { 3 const user = await User.findOneAsync(this.userId, { 4 fields: { subscribedPosts: 1 }, 5 }); 6 7 return Posts.find({ _id: { $in: user?.subscribedPosts || [] } }); 8 }); 9});
In the example above, you publish the user’s subscribed posts. When the User’s subscribedPosts
field changes, autorun reruns and publishes the updated posts. Any queries with related data work the same way. You can also publish an array of cursors and use the same logic as in a normal publication body.
Since most use cases involve a single autorun
block, you can use Meteor.publishReactive
for cleaner syntax:
1Meteor.publishReactive('subscribed-posts', async function () { 2 const user = await User.findOneAsync(this.userId, { 3 fields: { subscribedPosts: 1 }, 4 }); 5 6 return Posts.find({ _id: { $in: user?.subscribedPosts || [] } }); 7});
Time-based queries
1import { ReactiveVarAsync } from 'meteor/nachocodoner:reactive-publish'; 2 3const currentTime = new ReactiveVarAsync(Date.now()); 4 5Meteor.setInterval(() => { 6 currentTime.set(Date.now()); 7}, 1000); // ms 8 9Meteor.publish('recent-posts', function () { 10 this.autorun(() => { 11 return Posts.find({ 12 timestamp: { 13 $exists: true, 14 $gte: currentTime.get() - 60 * 1000, 15 }, 16 }, { 17 sort: { timestamp: 1 }, 18 }); 19 }); 20});
Multiple autoruns
1Meteor.publish('users-posts-and-addresses', function (userId) { 2 this.autorun(async () => { 3 const user = await Users.findOneAsync(userId, { 4 fields: { posts: 1 }, 5 }); 6 return Posts.find({ _id: { $in: user?.posts || [] } }); 7 }); 8 9 this.autorun(async () => { 10 const user = await Users.findOneAsync(userId, { 11 fields: { addresses: 1 }, 12 }); 13 return Addresses.find({ _id: { $in: user?.addresses || [] } }); 14 }); 15});
Roadmap
-
Stability
- Ensure core changes in this package don't affect Meteor core tests
- Release betas and RCs, with a feedback period for early adopters
-
Expansion
- Support for
AsyncTracker
andReactiveVarAsync
on the client - Migrate
peerlibrary:subscription-data
to support publishing derived data reactively
- Support for
-
Performance
- Run benchmarks to identify performance improvement opportunities
- Compare results with
reywood:publish-composite
to ensure equal or better behavior
Acknowledgments
This package builds on over a decade of work by PeerLibrary during the legacy Meteor era. Big thanks to everyone involved over those years, , especially mitar.
The original idea came from the excellent work of Diggory Blake, who created the first implementation.