重大变更
服务器中的 MongoDB 方法
如常见问题中所述,insert
、update
、remove
、find
、findOne
、upsert
方法不再在服务器中工作。
您应该迁移到使用它们的 Async
对应项。
const docs = MyCollection.find({ _id: '123' }).fetch(); This will not work in the server
const doc = MyCollection.findOne({ _id: '123' }); This will not work in the server
// in Meteor 3.x you should use the Async methods
const docs = await MyCollection.find({ _id: '123' }).fetchAsync(); This will work in the server
const doc = await MyCollection.findOneAsync({ _id: '123' }); This will work in the server
CLI
vue2
--vue2
标志不再可用。我们放弃了对 vue2 的支持。您可以在此PR中查看更多信息。
为什么?
做出此决定是因为 vue2 已于 2023 年 12 月 31 日达到生命周期结束,团队决定停止对其支持。
重置
meteor reset
命令默认只清除本地缓存。使用 --db
选项还会删除本地 Mongo 数据库。如果需要,请确保您的 CI 流程通过传递 --db
选项来适应任何更改。
为什么?
通常建议使用此命令通过清除缓存来修复您的开发项目。以前,它还会清除本地 MongoDB,这可能会意外删除重要数据。
Node v20
Meteor 3.0 现在使用 Node v20。这意味着如果您有任何 Node v14 的依赖项或用法,您将需要更新它们以与 Node v20 兼容。
NPM 安装程序更新
Meteor 的 npm 安装程序已更改。对于正式发布,您可以使用以下命令安装 Meteor
npx meteor
在发布候选阶段,请使用
npx meteor
或直接指定版本
npx meteor@<version>
确保您正在使用 Node 20.0.0 或更高版本,尤其是在您的 CI/CD 工作流程中,以与最新的 Meteor 版本兼容。
Call x CallAsync
提示
您可以查看call x callAsync页面以全面了解。
由于 Meteor 现在如何与 async/await
一起工作,您应该在方法中使用 callAsync
而不是 call
。
在 Meteor 2.x 中,这是一种常见的模式
import { Meteor } from 'meteor/meteor'
Meteor.methods({
async getAllData() {
return await MyCollection.find().fetch();
},
async otherMethod() {
return await MyCollection.find().fetch();
}
});
Meteor.call('getAllData')
Meteor.call('otherMethod')
现在在 Meteor 3.x 中,它应该变成
import { Meteor } from 'meteor/meteor'
Meteor.methods({
async getAllData() {
return await MyCollection.find().fetchAsync();
},
async otherMethod() {
return await MyCollection.find().fetchAsync();
}
});
await Meteor.callAsync('getAllData')
await Meteor.callAsync('otherMethod')
WebApp 切换到 Express
提示
WebApp 已从 Connect 切换到 Express。此升级允许您在 Meteor 应用程序中使用所有 Express 功能。如果您之前已自定义 WebApp 包,请验证这些自定义是否适用于 Express。
webapp
包现在导出这些新属性
type ExpressModule = {
(): express.Application;
json: typeof express.json;
raw: typeof express.raw;
Router: typeof express.Router;
static: typeof express.static;
text: typeof express.text;
urlencoded: typeof express.urlencoded;
};
export declare module WebApp {
// ...
/**
* @deprecated use handlers instead
*/
var connectHandlers: express.Application;
var handlers: express.Application;
/**
* @deprecated use rawHandlers instead
*/
var rawConnectHandlers: express.Application;
var rawHandlers: express.Application;
var httpServer: http.Server;
var expressApp: express.Application;
var express: ExpressModule;
// ...
}
// import { WebApp } from 'meteor/webapp';
使用 WebApp 和 Express 的路由
要在您的应用程序中添加 Express 路由,请查看Express 指南并遵循此示例
import { WebApp } from 'meteor/webapp';
const app = WebApp.express(); you can use as a normal express app
app.get('/hello', (req, res) => {
res.send('Hello World');
});
WebApp.handlers.use(app);
以下代码演示了如何使用 handlers
属性在您的应用程序中创建路由
import { WebApp } from 'meteor/webapp';
WebApp.handlers.get('/hello', (req, res) => {
res.send('Hello World');
});
使用 WebApp 和 Express 的中间件
要在您的应用程序中包含**路由级** Express 中间件,请查看Express 指南并遵循此示例
import { WebApp } from 'meteor/webapp';
const app = WebApp.express();
const router = WebApp.express.Router();
// This middleware is executed every time the app receives a request
router.use((req, res, next) => {
console.log('Router-level - Time:', Date.now());
next();
})
// This middleware shows request info for any type of HTTP request to the /hello/:name path
router.use('/hello/:name', (req, res, next) => {
console.log('Router-level - Request URL:', req.originalUrl);
next();
}, (req, res, next) => {
console.log('Router-level - Request Type:', req.method);
next();
})
// mount the router on the app
app.use('/', router);
WebApp.handlers.use(app);
要在您的应用程序中包含**应用程序级** Express 中间件,请查看Express 指南并遵循此示例
import { WebApp } from 'meteor/webapp';
const app = WebApp.express();
const router = WebApp.express.Router()
// This middleware is executed every time the app receives a request
router.use((req, res, next) => {
console.log('Router-level - Time:', Date.now());
next();
})
// This middleware shows request info for any type of HTTP request to the /hello/:name path
router.use('/hello/:name', (req, res, next) => {
console.log('Router-level - Request URL:', req.originalUrl);
next();
}, (req, res, next) => {
console.log('Router-level - Request Type:', req.method);
next();
})
// mount the router on the app
app.use('/', router);
WebApp.handlers.use(app);
新的 API 名称
从 Connect 切换到 Express 后,我们更新了 API 名称以与 Express 保持一致。请参阅以下详细信息
WebApp.connectHandlers.use(middleware)
现在是WebApp.handlers.use(middleware)
WebApp.rawConnectHandlers.use(middleware)
现在是WebApp.rawHandlers.use(middleware)
WebApp.connectApp
现在是WebApp.expressApp
WebApp 内部的一些方法现在是异步的
WebAppInternals.reloadClientPrograms()
WebAppInternals.pauseClient()
WebAppInternals.generateClientProgram()
WebAppInternals.generateBoilerplate()
WebAppInternals.setInlineScriptsAllowed()
WebAppInternals.enableSubresourceIntegrity()
WebAppInternals.setBundledJsCssUrlRewriteHook()
WebAppInternals.setBundledJsCssPrefix()
WebAppInternals.getBoilerplate
Meteor.userAsync
您应该在代码中使用 Meteor.userAsync
而不是 Meteor.user
,尤其是在您想要同构或想要在服务器中获取用户时。
// Before
const user = Meteor.user();
// After
const user = await Meteor.userAsync();
环境变量
Meteor 提供了 Meteor.EnvironmentVariable
类,它有助于在不同的边界之间维护上下文。
使用 Meteor 3.0,我们添加了对异步流程的支持并改进了上下文管理方式。结果,某些包开始丢失上下文数据,如此问题中所述。
如果您的应用程序或包使用 EnvironmentVariable
,请确保在顶层使用 EnvironmentVariable.withValue
以正确保留和传播上下文。
例如,在更新发布行为并引入 new EnvironmentVariable
上下文时,您需要调整代码如下
const _publishConnectionId = new Meteor.EnvironmentVariable<
string | undefined
>();
// Before
function patchPublish(publish: typeof Meteor.publish) {
return function (this: typeof Meteor, name, func, ...args) {
return publish.call(
this,
name,
function (...args) {
return _publishConnectionId.withValue(this?.connection?.id, () =>
func.apply(this, args),
);
},
...args,
);
} as typeof Meteor.publish;
}
// After
function patchPublish(publish: typeof Meteor.publish) {
return function (this: typeof Meteor, name, func, ...args) {
return _publishConnectionId.withValue(this?.connection?.id, () => {
return publish.call(
this,
name,
function (...args) {
return func.apply(this, args);
},
...args,
);
});
} as typeof Meteor.publish;
}
此示例演示了应用于universe:i18n
包的迁移。