Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Rethink view #398

Closed
5 of 7 tasks
popomore opened this issue Feb 17, 2017 · 72 comments
Closed
5 of 7 tasks

[RFC] Rethink view #398

popomore opened this issue Feb 17, 2017 · 72 comments

Comments

@popomore
Copy link
Member

popomore commented Feb 17, 2017

我们现在的模板规范,约定插件名为 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 实例,renderrenderString 支持 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 方案,插件改造成本不高。

已有插件改造

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

还以为正文是英文-.-

@popomore
Copy link
Member Author

English is hard to discuss for Chinese people

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

  • 还需要考虑 helper, app/filter.js, security inject 的方案
  • loader 文件加载差异性会不会太大, react 这些 webpack 打的 bundler 不知道差异怎么样

@popomore
Copy link
Member Author

就是 ctx.render('viewPath') 中的 viewPath 到真实路径的映射

@popomore
Copy link
Member Author

还需要考虑 helper, app/filter.js, security inject 的方案

这些原来就支持了

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

喔, 明白了.

  • helpersecurity inject 如果具体的 view 插件实现了就支持.
  • app/filter.js 也是看具体插件, 反正里面是纯函数, 框架就用 loadToApp()app.filter, 具体挂载的模板引擎由插件实现, 要不要把 app.filter 这个挂载, 做到 egg-view 里面? 比较常见的场景

@popomore
Copy link
Member Author

是的,原来的 view 对象不用改,只是改了注册方式

@fengmk2
Copy link
Member

fengmk2 commented Feb 17, 2017

跟 passport 很像,passport 也是通过 app.passport.use('twitter', strategy) 注册一种新的用户授权策略。

考虑到一个应用会渲染多种模板引擎的话,必须得改造了。

+1

@gxcsoccer
Copy link
Contributor

不错,这样更灵活点

@popomore
Copy link
Member Author

那我也改成 app.view.use?

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

app.use 混淆了, 建议统一改为 register, app.passport.register()

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

app.view or app.View ?

@fengmk2
Copy link
Member

fengmk2 commented Feb 17, 2017

use 更加是遵循 koa 中间件的命名啊, app.use(mw)

@fengmk2
Copy link
Member

fengmk2 commented Feb 17, 2017

app.view 是 ViewManager 的一个实例

@atian25 atian25 added this to the 1.0.0 milestone Feb 17, 2017
@popomore
Copy link
Member Author

app.view 是 ViewManager 的一个实例

是的,是这样考虑的

@popomore popomore self-assigned this Feb 17, 2017
@dead-horse
Copy link
Member

这样也很适合一些需要 SEO 的页面用 nunjucks,另外的页面直接用客户端 react 渲染。

@jtyjty99999
Copy link
Member

这个按照扩展名区分会不会出现扩展名冲突的问题啊,俩都用html呢

@popomore
Copy link
Member Author

@jtyjty99999 不会冲突,mapping 配了什么就用什么,冲突就改下扩展名。比如我们现在用 nunjucks 也是用 .html,如果其他模板引擎要用就可以写成 .nj

@jtyjty99999
Copy link
Member

我觉得
app.view.getEngine('ejs').render('a');
app.view.getEngine('art').render('b')

这样会不会好点

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

应用层自己覆盖.

如 ejs 的默认 ext 是 .ejs, 但是有人习惯用 .tpl 的话, 那他自己在应用层修改 config.mapping['.ejs'] = 'ejs'

@popomore
Copy link
Member Author

这样对应用层太不友好了

@popomore
Copy link
Member Author

@jtyjty99999 我想到了,在 render 的时候可以指定 view。

@jtyjty99999
Copy link
Member

但是实际情况下经常遇到这种,比如推送系统的时候推送过来是velocity模板,自己应用是nunjucks模板,这样分开渲染的场景

@jtyjty99999
Copy link
Member

@popomore 我的意思就是需要这种能指定view engine的能力

@atian25
Copy link
Member

atian25 commented Feb 17, 2017

@popomore renderString 的时候是没有后缀名的, 这个要考虑支持 locals, 如

renderString('{{ name }}', { SOMEKEY?: 'nunjucks' })

@popomore
Copy link
Member Author

@atian25 @jtyjty99999 是的,我已经加了,多谢提醒

@atian25
Copy link
Member

atian25 commented Feb 20, 2017

@popomore 在顶楼更新下进度和链接?

popomore added a commit that referenced this issue Feb 21, 2017
Use `app.view` to register multiple view engine, then
more than once view engine can be used in one application.

Different templte engine can be seperated to plugins, such as
egg-view-nunjucks, egg-view-ejs

Ref #398
popomore added a commit to eggjs/egg-view-ejs that referenced this issue Feb 22, 2017
popomore added a commit to eggjs/egg-view-nunjucks that referenced this issue Feb 22, 2017
popomore added a commit that referenced this issue Feb 22, 2017
Use `app.view` to register multiple view engine, then
more than once view engine can be used in one application.

Different templte engine can be seperated to plugins, such as
egg-view-nunjucks, egg-view-ejs

Ref #398
popomore added a commit that referenced this issue Feb 22, 2017
Use `app.view` to register multiple view engine, then
more than once view engine can be used in one application.

Different templte engine can be seperated to plugins, such as
egg-view-nunjucks, egg-view-ejs

Ref #398
popomore added a commit that referenced this issue Feb 22, 2017
Use `app.view` to register multiple view engine, then
more than once view engine can be used in one application.

Different templte engine can be seperated to plugins, such as
egg-view-nunjucks, egg-view-ejs

Ref #398
popomore added a commit that referenced this issue Feb 23, 2017
Use `app.view` to register multiple view engine, then
more than once view engine can be used in one application.

Different templte engine can be seperated to plugins, such as
egg-view-nunjucks, egg-view-ejs

Ref #398
@AnzerWall
Copy link
Contributor

AnzerWall commented Feb 24, 2017

妈蛋(害我说粗话)。
你们改插件好点同步都改了,文档都没同步改

@popomore
Copy link
Member Author

popomore commented Feb 24, 2017

一步步来,先喝杯咖啡 ☕️

@atian25
Copy link
Member

atian25 commented Feb 24, 2017

@AnzerWall 你指哪一份文档?

PS: 欢迎直接 PR 修改.

@atian25
Copy link
Member

atian25 commented Feb 24, 2017

@atian25
Copy link
Member

atian25 commented Feb 27, 2017

@jtyjty99999 有空改改 egg-view-react

@jtyjty99999
Copy link
Member

@atian25 好的

@popomore
Copy link
Member Author

@atian25 react 和 vue 咋搞

@atian25
Copy link
Member

atian25 commented Feb 28, 2017

react 就是 @jtyjty99999 那个改改, vue 的还没写

@popomore
Copy link
Member Author

popomore commented Mar 1, 2017

这个关了,剩下的 @jtyjty99999 @ngot 跟进,不过这些都还没发版本吧?

@popomore popomore closed this as completed Mar 1, 2017
@atian25
Copy link
Member

atian25 commented Mar 1, 2017

都没发.

egg-view-nunjucks 那边是不是要发一个 1.x 的 patch 配置 peer deps,昨天 #481 这个里面就是历史用户升级时会踩到的坑。

@popomore
Copy link
Member Author

popomore commented Mar 1, 2017

peer deps 是否有坑,让 @dead-horse @fengmk2 来说说

@dead-horse
Copy link
Member

我们这种用法问题不大,但是现在是因为 egg 1.0 还没正式发,所以 peerDependencies 也解决不了问题。

@dead-horse
Copy link
Member

后面等到发 2.x 的时候再考虑 peerDependencies 吧,现在不稳定情况下没什么意义

@atian25 atian25 changed the title Rethink view [RFC] Rethink view Aug 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants