Feathers v3(秃鹰)¶
Feathers v3带有一些很棒的改进和新功能,我们强烈建议您尽快升级.一开始看起来有点令人生畏,但几乎在所有情况下,新的CLI都会自动为您提供所有方式.此页面包含有关快速升级路径的信息以及有关从Feathers v2升级到v3的所有更改的更多信息.
阅读 飞入2018年 的发布帖子
快速升级¶
要快速升级任何Feathers插件或应用程序,您可以使用新CLI中的 upgrade 命令.首先,如果安装了它,请卸载旧的 feathers-cli:
npm uninstall feathers-cli -g
然后安装 @feathersjs/cli 并升级项目:
npm install @feathersjs/cli -g
cd path/to/project
feathers upgrade
CLI将使用
package.json中的directories.lib来知道源文件的位置,如果没有提供,则默认为src.如果您有一个已转换的应用/模块,例如使用babel,包括lib和src文件夹,最简单的是将package.json中的directories.lib更改为src而不是lib,以便CLI将正确升级原始源文件而不是已转换的源文件.
简而言之(有关详细信息,请参见下文),这将:
将所有核心软件包升级到新的作用域软件包名称及其最新版本
删除所有
feathers-hooks导入和单行app.configure(hooks());(链接.configure(hooks())调用必须手动删除))为任何使用
feathers-rest的应用程序添加Express兼容性(其他没有feathers-rest的Feathers应用程序必须手动更新)删除所有
.filter导入并调用已被通道功能取代的service.filter
添加频道¶
如果您使用实时(使用Socket.io或Primus),请将以下文件添加为 src/channels.js:
module.exports = function(app) {
if(typeof app.channel !== 'function') {
// If no real-time functionality has been configured just return
return;
}
app.on('connection', connection => {
// On a new real-time connection, add it to the anonymous channel
app.channel('anonymous').join(connection);
});
app.on('login', (authResult, { connection }) => {
// connection can be undefined if there is no
// real-time connection, e.g. when logging in via REST
if(connection) {
// Obtain the logged in user from the connection
// const user = connection.user;
// The connection is no longer anonymous, remove it
app.channel('anonymous').leave(connection);
// Add it to the authenticated user channel
app.channel('authenticated').join(connection);
// Channels can be named anything and joined on any condition
// E.g. to send real-time events only to admins use
// if(user.isAdmin) { app.channel('admins').join(connection); }
// If the user has joined e.g. chat rooms
// if(Array.isArray(user.rooms)) user.rooms.forEach(room => app.channel(`rooms/${room.id}`).join(channel));
// Easily organize users by email and userid for things like messaging
// app.channel(`emails/${user.email}`).join(channel);
// app.channel(`userIds/$(user.id}`).join(channel);
}
});
app.publish((data, hook) => { // eslint-disable-line no-unused-vars
// Here you can add event publishers to channels set up in `channels.js`
// To publish only for a specific event use `app.publish(eventname, () => {})`
// e.g. to publish all service events to all authenticated users use
return app.channel('authenticated');
});
// Here you can also add service specific event publishers
// e..g the publish the `users` service `created` event to the `admins` channel
// app.service('users').publish('created', () => app.channel('admins'));
// With the userid and email organization from above you can easily select involved users
// app.service('messages').publish(() => {
// return [
// app.channel(`userIds/${data.createdBy}`),
// app.channel(`emails/${data.recipientEmail}`)
// ];
// });
};
并且需要在 src/app.js 中配置它(注意它应该在所有服务之后配置,以便 channels.js 可以注册服务特定的发布者):
const channels = require('./channels');
// After `app.configure(services)`
app.configure(channels);
重要
The channels.js file shown above will publish
all real-time events to all authenticated users. This is already
safer than the previous default but you should carefully review the
事件频道 documentation and implement
appropriate channels so that only the right users are going to
receive real-time events.
将应用程序迁移到通道后,可以删除所有 <servicename> .filter.js 文件.
保护领域¶
Feathers v3有一种新机制可确保敏感信息永远不会发布到任何客户端.要保护始终保护用户密码,请在 src/services/users/users.hooks.js 中添加 api/authentication/local#protect,而不是 remove('password') 钩子:
const { hashPassword } = require('@feathersjs/authentication-local').hooks;
const { hashPassword, protect } = require('@feathersjs/authentication-local').hooks;
module.exports = {
before: {
all: [],
find: [ authenticate('jwt') ],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
after: {
all: [
// Make sure the password field is never sent to the client
// Always must be the last hook
protect('password')
],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
error: {
all: [],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
}
};
更新客户端应用程序¶
Client side Feathers applications can also be updated using the CLI but
may need some manual intervention. Most importantly, since Feathers core
now natively ships as ES6 code, the module bundler, like Webpack, has to
be instructed to transpile it. More information can be found in the
Feathers 客户端. For Webpack and
create-react-app usage (which both will throw a minification error
without changes), see Webpack.
@feathersjs npm scope¶
所有Feathers核心模块都已移至 @feathersjs npm范围.这使得更清楚哪些模块被视为核心模块以及哪些模块受社区支持,并且还允许我们更轻松地管理发布权限.以下模块已重命名:
主要Feathers¶
旧名 |
范围名称 |
|---|---|
feathers |
@feathersjs/feathers |
feathers-cli |
@feathersjs/cli |
feathers-commons |
@feathersjs/commons |
feathers-rest |
@feathersjs/express/rest |
feathers-socketio |
@feathersjs/socketio |
feathers-primus |
@feathersjs/primus |
feathers-errors |
@feathersjs/errors |
feathers-configuration |
@feathersjs/configuration |
feathers-socket-commons |
@feathersjs/socket-commons |
认证¶
旧名 |
范围名称 |
|---|---|
feathers-authentication |
@feathersjs/authentication |
feathers-authentication-jwt |
@feathersjs/authentication-jwt |
feathers-authentication-local |
@feathersjs/authentication-local |
feathers-authentication-oauth1 |
@feathersjs/authentication-oauth1 |
feathers-authentication-oauth2 |
@feathersjs/authentication-oauth2 |
feathers-authentication-client |
@feathersjs/authentication-client |
客户端 Feathers¶
旧名 |
范围名称 |
|---|---|
feathers/client |
@feathersjs/feathers |
feathers-client |
@feathersjs/client |
feathers-rest/client |
@feathersjs/rest-client |
feathers-socketio/client |
@feathersjs/socketio-client |
feathers-primus/client |
@feathersjs/primus-client |
feathers-authentication/client |
@feathersjs/authentication-client |
文档更改¶
通过更好地关注Feathers核心,非核心模块的存储库,文档和指南已移至更合适的位置:
非核心模块已被转移到 feathersjs-ecosystem 和 feathers-plus 组织. 这些模块的文档可以在各自的GitHub存储库的自述文件中找到.
Database adapter specific documentation can now be found in the respective repositories readme. Links to the repositories can be found in the 数据库适配器
The
feathers-hooks-commondocumentation can be found at feathers-plus.github.io/v1/feathers-hooks-common/离线和身份验证管理文档也可以在 feathers-plus.github.io 找到.
生态系统页面现在指向 awesome-feathersjs
框架独立¶
@feathersjs/feathers v3与框架无关,可以在客户端和开箱即用的Node中运行.这意味着它不再默认扩展Express.
而 @feathersjs/express 在 require('@feathersjs/express').rest 或 @feathersjs/ 中提供框架绑定和REST提供程序(以前称为 feathers-rest).express/rest``. @feathersjs/express 还带有Express内置中间件,如 express.static 和最近包含的 express.json 和 express.urlencoded 身体解析器.一旦Feathers应用程序被 “表达”,它就可以像以前的版本一样使用:
Before
const feathers = require('feathers');
const bodyParser = require('body-parser');
const rest = require('feathers-rest');
const errorHandler = require('feathers-errors/handler');
const app = feathers();
app.configure(rest());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Register an Express middleware
app.get('/somewhere', function(req, res) {
res.json({ message: 'Data from somewhere middleware' });
});
// Statically host some files
app.use('/', feathers.static(__dirname));
// Use a Feathers friendly Express error handler
app.use(errorHandler());
Now
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
// Create an Express compatible Feathers application
const app = express(feathers());
// Add body parsing middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Initialize REST provider (previous in `feathers-rest`)
app.configure(express.rest());
// Register an Express middleware
app.get('/somewhere', function(req, res) {
res.json({ message: 'Data from somewhere middleware' });
});
// Statically host some files
app.use('/', express.static(__dirname));
// Use a Feathers friendly Express error handler
app.use(express.errorHandler());
钩子在核心¶
feathers-hooks 插件现在是核心的一部分,不再需要导入和配置.所有服务都将立即包含挂钩功能.此外,现在还可以定义应该在 hook.dispatch 中发送给客户端的不同数据,这样可以正确保护不应该显示给客户端的属性.
Before
const feathers = require('feathers');
const hooks = require('feathers-hooks');
const app = feathers();
app.configure(hooks());
app.use('/todos', {
get(id) {
return Promise.resolve({
message: `You have to do ${id}`
});
}
});
app.service('todos').hooks({
after: {
get(hook) {
hook.result.message = `${hook.result.message}!`;
}
}
});
Now
const feathers = require('feathers');
const app = feathers();
app.use('/todos', {
get(id) {
return Promise.resolve({
message: `You have to do ${id}`
});
}
});
app.service('todos').hooks({
after: {
get(hook) {
hook.result.message = `${hook.result.message}!`;
}
}
});
事件频道和出版¶
以前,过滤器用于为每个事件和每个连接运行,以确定是否应该发送事件.
事件通道是一种更安全,更高效的方式,用于定义将实时事件发送到的连接.而不是为每个事件和每个连接运行,而是在建立或验证连接时定义连接属于哪个通道.
// On login and if it is a real-time connectionn, add the connection to the `authenticated` channel
app.on('login', (authResult, { connection }) => {
if(connection) {
const { user } = connection;
app.channel('authenticated').join(connection);
}
});
// Publish only `created` events from the `messages` service
app.service('messages').publish('created', (data, context) => app.channel('authenticated'));
// Publish all real-time events from all services to the authenticated channel
app.publish((data, context) => app.channel('authenticated'));
要仅发布到用户所在的房间:
// On login and if it is a real-time connection, add the connection to the `authenticated` channel
app.on('login', (authResult, { connection }) => {
if(connection) {
const { user } = connection;
// Join `authenticated` channel
app.channel('authenticated').join(connection);
// Join rooms channels for that user
rooms.forEach(roomId => app.channel(`rooms/${roomId}`).join(connection));
}
});
更好地分离客户端和服务器端模块¶
自v2以来,Feathers核心一直在客户端和服务器上运行,但并不总是很清楚应该使用哪些相关模块.现在,所有客户端连接器都位于它们自己的存储库中,而主要的Feathers存储库在客户端和服务器上可能需要相同的方式.
Before
const io = require('socket.io-client');
const feathers = require('feathers/client');
const hooks = require('feathers-hooks');
const socketio = require('feathers-socketio/client');
const auth = require('feathers-authentication-client');
const socket = io();
const app = feathers()
.configure(hooks())
.configure(socketio(socket))
.configure(auth());
Now
const io = require('socket.io-client');
const feathers = require('@feathersjs/feathers');
const socketio = require('@feathersjs/socketio-client');
const auth = require('@feathersjs/authentication-client');
const socket = io();
const app = feathers()
.configure(socketio(socket))
.configure(auth());
Node 6+¶
上面提到的核心存储库也已经被迁移到可以直接使用(例如,当npm将存储库安装为Git/GitHub依赖关系时),而不需要Babel转换步骤.
由于所有存储库都广泛使用ES6,这也意味着不再支持 node 4.
一种新的Socket消息格式¶
在尝试调用不存在的服务或方法(而不是仅仅超时)时,websocket消息传递格式已更新为支持正确的错误消息.使用新的 @feathersjs/socketio-client 和 @feathersjs/primus-client 将自动使用该格式.您可以在 Socket.io 客户端 和 Primus 客户端 文档中找到详细信息.
注解
仍支持旧邮件格式,因此不必同时更新客户端.
弃用和其他API更改¶
Feathers服务方法不再支持回调.所有服务方法总是返回Promise.自定义服务必须返回Promise或使用
async/await.service.before和service.after已被替换为单个app.hooks({before,after})app.service(path)只返回一个服务,不再用于注册新服务(通过app.service(path,service)).请使用app.use(path,service).之前直接添加到“params”的路由参数现在位于
params.route中像
feathers.static这样的快速中间件现在位于const express = require('@feathersjs/express')使用express.static已从所有核心存储库中删除实验性TypeScript定义.可以在 feathersjs-ecosystem/feathers-typescript 中开发此版本的TypeScript定义.欢迎帮助.
向后兼容性polyfill¶
除了上面列出的步骤,现有的钩子,数据库适配器,服务和其他插件应该与Feathers v3完全兼容,无需任何额外的修改.
本节包含一些快速向后兼容性polyfill,用于突破性更改,可用于简化迁移或继续使用使用弃用语法的插件.
基本服务过滤器¶
这是先前事件过滤器功能的基本模拟.它不使用promises或允许修改数据(现在应该通过设置 hook.dispatch 来处理).
app.mixins.push(service => {
service.mixin({
filter(eventName, callback) {
const args = callback ? [ eventName ] : [];
// todos.filter('created', function(data, connection, hook) {});
if(!callback) {
callback = eventName;
}
// A publisher function that sends to the `authenticated`
// channel that we defined in the quick upgrade section above
args.push((data, hook) => app.channel('authenticated')
.filter(connection =>
callback(data, connection, hook)
)
);
service.publish(... args);
}
});
});
路线参数¶
app.hooks({
before(hook) {
Object.assign(hook.params, hook.params.route);
return hook;
}
})
.before 和 .after 挂钩注册¶
app.mixins.push(service => {
service.mixin({
before(before) {
return this.hooks({ before });
},
after(after) {
return this.hooks({ after });
},
})
});