[RFC] Rethink view
See original GitHub issue我们现在的模板规范,约定插件名为 view,这样可以通过配置不同插件来切换模板,controller 不需要修改。
但是会遇到多模板的情况的,比如 markdown 渲染会和普通模板同时存在,而且应用在模板过渡场景也会遇到多模板的情况,所以这种模板约定就会存在问题。
方案
提供模板注册机制,开发者可根据习惯来配置模板。
提供 app.view
,插件可通过 app.view.register
来注册模板
app.view.use('ejs', EjsView);
这时框架会将这个映射关系存到 map 中,EjsView 为类而非实例,和现在实现的类一致。
开发者使用时需要配置映射关系
// config/config.default.js
exports.view = {
root: '',
cache: true,
defaultExt: '.html',
mapping: {
'.ejs': 'ejs',
'.html': 'ejs',
}
};
exports.ejs = {
// ejs config
}
在渲染时,会根据后缀匹配对应的 view 进行渲染,内置 loader 功能并带缓存。
插件开发
插件开发者跟原来会有一些差异
插件名和配置不需要约定 view,自定义插件名
{
"eggPlugin": {
"name": "ejs"
}
}
config/config.default.js
exports.ejs = { ... };
注册 view 实例,render
和 renderString
支持 promise、async function 和 generator function。
// app.js
module.exports = app => {
class EjsView {
constructor(ctx) {}
* render() {}
// render() { return Promise.resolve('html'); }
// async render() {}
* renderString() {}
static getCache() {}
}
app.view.register('ejs', EjsView);
};
view 配置
view 自带默认的 loader 功能,但不支持各种 view 的 include
特性。
root
默认为 app/view
,也支持多目录,可以遍历多个目录搜索文件。但是模板的 include
特性需要模板自己实现,这个差异比较大。
cache
文件缓存(非渲染缓存,这个由模板引擎实现),如果文件已经搜索过了就不会再去搜索。
不做渲染缓存是因为需要缓存 compile 结果,但不是每个模板引擎都支持的。
defaultExt
默认后缀,如果在 ctx.render
时不填后缀,则使用默认后缀。
mapping
后缀和模板的匹配关系。
viewOptions
ctx.render(name, locals, [viewOptions])
viewOptions 可以覆盖 view 配置,优先级最高。
比如渲染时可以手动指定 viewEngine,而不根据后缀探测
ctx.render('xx.html', {}, {
viewEngine: 'nunjucks',
});
是否兼容
考虑还未发布 1.0,可以去除原来的 view 方案,插件改造成本不高。
已有插件改造
- egg-view https://github.com/eggjs/egg-view/pull/1
- egg 依赖 egg-view https://github.com/eggjs/egg/pull/402
- egg-view-nunjucks https://github.com/eggjs/egg-view-nunjucks/pull/11
- egg-view-react
- egg-view-ejs https://github.com/eggjs/egg-view-ejs/pull/2
- egg-view-xtpl
- egg-view-vue
Issue Analytics
- State:
- Created 7 years ago
- Reactions:5
- Comments:72 (72 by maintainers)
Top GitHub Comments
妈蛋(害我说粗话)。 你们改插件好点同步都改了,文档都没同步改
后面等到发 2.x 的时候再考虑 peerDependencies 吧,现在不稳定情况下没什么意义