├── source ├── zh-cn │ ├── fekey │ │ ├── quickstart.md │ │ └── index.md │ ├── docs │ │ ├── core │ │ │ ├── deployment.md │ │ │ ├── development.md │ │ │ ├── logger.md │ │ │ ├── runtime.md │ │ │ └── view.md │ │ ├── advanced │ │ │ ├── framework.md │ │ │ ├── fetch-server.md │ │ │ ├── server-isoloton.md │ │ │ └── plugin.md │ │ ├── faq │ │ │ ├── deploy.md │ │ │ ├── wechat.md │ │ │ ├── contributing.md │ │ │ ├── start.md │ │ │ └── debug.md │ │ ├── intro │ │ │ ├── index.md │ │ │ └── quickstart.md │ │ └── basics │ │ │ ├── router.md │ │ │ ├── structure.md │ │ │ ├── service.md │ │ │ └── mock.md │ ├── index.md │ ├── page │ │ ├── user.md │ │ └── process.md │ └── faq.md ├── api │ └── index.md ├── en │ ├── index.md │ └── faq.md └── _data │ ├── languages.yml │ ├── menu.yml │ └── sidebar.yml ├── .gitignore ├── themes ├── docs │ ├── source │ │ ├── images │ │ │ ├── banner.jpg │ │ │ ├── logo.png │ │ │ ├── search.png │ │ │ ├── favicon.png │ │ │ ├── feature1.svg │ │ │ ├── github.svg │ │ │ ├── feature2.svg │ │ │ ├── feature3.svg │ │ │ ├── logo-new.svg │ │ │ └── logo.svg │ │ ├── css │ │ │ ├── partial │ │ │ │ ├── var.less │ │ │ │ ├── footer.less │ │ │ │ ├── main.less │ │ │ │ ├── toc.less │ │ │ │ ├── mobile.less │ │ │ │ └── nav.less │ │ │ ├── index.less │ │ │ ├── page │ │ │ │ ├── page.less │ │ │ │ └── index.less │ │ │ └── vendor │ │ │ │ ├── highlight-github.less │ │ │ │ ├── normalize.less │ │ │ │ └── github-markdown.less │ │ └── js │ │ │ └── mobile-aside.js │ ├── layout │ │ ├── page.swig │ │ ├── partial │ │ │ ├── aside.swig │ │ │ ├── footer.swig │ │ │ ├── head.swig │ │ │ └── header.swig │ │ ├── post.swig │ │ ├── layout.swig │ │ └── index.swig │ ├── lib │ │ └── renderer.js │ ├── languages │ │ ├── en.yml │ │ └── zh-cn.yml │ └── scripts │ │ └── helpers.js └── navy │ ├── source │ ├── css │ │ ├── _partial │ │ │ ├── post.styl │ │ │ ├── archive.styl │ │ │ ├── footer.styl │ │ │ ├── sidebar.styl │ │ │ ├── base.styl │ │ │ ├── header.styl │ │ │ ├── highlight.styl │ │ │ ├── plugins.styl │ │ │ ├── index.styl │ │ │ ├── mobile_nav.styl │ │ │ └── page.styl │ │ ├── navy.styl │ │ └── _variables.styl │ └── js │ │ ├── lang_select.js │ │ ├── mobile_nav.js │ │ ├── toc.js │ │ ├── plugins.js │ │ └── scrollingelement.js │ ├── layout │ ├── partial │ │ ├── sidebar.swig │ │ ├── plugin.swig │ │ ├── google_analytics.swig │ │ ├── post.swig │ │ ├── theme.swig │ │ ├── footer.swig │ │ ├── comment.swig │ │ ├── mobile_nav.swig │ │ ├── after_footer.swig │ │ ├── share.swig │ │ ├── header.swig │ │ └── head.swig │ ├── post.swig │ ├── layout.swig │ ├── plugins.swig │ ├── archive.swig │ ├── page.swig │ └── index.swig │ ├── scripts │ ├── tags.js │ └── helpers.js │ └── languages │ ├── en.yml │ └── zh-cn.yml ├── package.json ├── README.md └── _config.yml /source/zh-cn/fekey/quickstart.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/api/index.md: -------------------------------------------------------------------------------- 1 | layout: api 2 | title: API 3 | --- 4 | -------------------------------------------------------------------------------- /source/zh-cn/docs/core/deployment.md: -------------------------------------------------------------------------------- 1 | title: 应用部署 2 | --- 3 | 4 | -------------------------------------------------------------------------------- /source/en/index.md: -------------------------------------------------------------------------------- 1 | layout: index 2 | subtitle: baiduwaimai 3 | --- 4 | -------------------------------------------------------------------------------- /source/zh-cn/docs/advanced/framework.md: -------------------------------------------------------------------------------- 1 | title: 框架开发 2 | --- 3 | 4 | 5 | -------------------------------------------------------------------------------- /source/zh-cn/docs/faq/deploy.md: -------------------------------------------------------------------------------- 1 | title: NodeUI环境及部署问题汇总 2 | --- 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | db.json 4 | *.log 5 | node_modules/ 6 | public/ 7 | .deploy*/ -------------------------------------------------------------------------------- /source/zh-cn/docs/core/development.md: -------------------------------------------------------------------------------- 1 | title: 本地开发 2 | --- 3 | 4 | 为了提升研发体验,我们提供了便捷的方式在本地进行开发、调试、单元测试等。 5 | 6 | -------------------------------------------------------------------------------- /source/zh-cn/docs/core/logger.md: -------------------------------------------------------------------------------- 1 | title: 日志 2 | --- 3 | 4 | 日志对于 Web 开发的重要性毋庸置疑,它对于监控应用的运行状态、问题排查等都有非常重要的意义。 5 | 6 | -------------------------------------------------------------------------------- /themes/docs/source/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/younth/hexo-site-kit/HEAD/themes/docs/source/images/banner.jpg -------------------------------------------------------------------------------- /themes/docs/source/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/younth/hexo-site-kit/HEAD/themes/docs/source/images/logo.png -------------------------------------------------------------------------------- /themes/docs/source/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/younth/hexo-site-kit/HEAD/themes/docs/source/images/search.png -------------------------------------------------------------------------------- /themes/docs/source/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/younth/hexo-site-kit/HEAD/themes/docs/source/images/favicon.png -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/post.styl: -------------------------------------------------------------------------------- 1 | .post 2 | margin: 0 auto 3 | float: none 4 | @media screen 5 | max-width: 800px -------------------------------------------------------------------------------- /themes/docs/source/css/partial/var.less: -------------------------------------------------------------------------------- 1 | @bg_default: #F6F8F8; 2 | @bg_dark: #121724; 3 | @bg_light: #FFFFFF; 4 | 5 | @max_width: 1136px; 6 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/sidebar.swig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/zh-cn/index.md: -------------------------------------------------------------------------------- 1 | layout: index 2 | description: Hexo is a fast, simple & powerful blog framework powered by Node.js. 3 | subtitle: 百度外卖企业级高可用Node渲染容器 4 | comments: false 5 | --- -------------------------------------------------------------------------------- /source/zh-cn/page/user.md: -------------------------------------------------------------------------------- 1 | layout: post 2 | title: 谁在使用NodeUI 3 | --- 4 | 5 | 目前广泛的应用在外卖运营活动,糯米组件接口,外卖各类APP内嵌h5页面等服务。 6 | 7 | - 糯米组件 8 | - 小度商城 9 | - 运营活动 10 | - 会员卡 11 | - banff 12 | - ....... -------------------------------------------------------------------------------- /themes/navy/layout/post.swig: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{ partial('partial/post', {post: page}) }} 5 |
6 |
7 |
-------------------------------------------------------------------------------- /themes/docs/layout/page.swig: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ page.title }}

4 | {{ page.content }} 5 |
6 | {# 左侧导航 #} 7 | {{ partial('partial/aside') }} 8 |
9 | -------------------------------------------------------------------------------- /themes/docs/layout/partial/aside.swig: -------------------------------------------------------------------------------- 1 | 8 | {{ js('js/mobile-aside') }} 9 | -------------------------------------------------------------------------------- /source/_data/languages.yml: -------------------------------------------------------------------------------- 1 | en: English 2 | zh-tw: 3 | name: 正體中文 4 | disqus_lang: zh_TW 5 | zh-cn: 6 | name: 简体中文 7 | disqus_lang: zh 8 | ru: 9 | name: Русский 10 | disqus_lang: ru 11 | ko: 12 | name: 한국어 13 | disqus_lang: ko -------------------------------------------------------------------------------- /source/_data/menu.yml: -------------------------------------------------------------------------------- 1 | guide: /docs/intro/ 2 | process: /page/process.html 3 | # api: /api 4 | # tutorials: /tutorials/index.html 5 | # plugins: https://github.com/search?q=topic%3Aegg-plugin&type=Repositories 6 | # release: https://github.com/eggjs/egg/releases 7 | user: /page/user.html 8 | fekey: /fekey/index.html -------------------------------------------------------------------------------- /themes/navy/layout/partial/plugin.swig: -------------------------------------------------------------------------------- 1 |
  • 2 | {{ plugin.name }} 3 |

    {{ plugin.description }}

    4 |
    5 | {% for tag in plugin.tags %} 6 | {{ tag }} 7 | {% endfor %} 8 |
    9 |
  • -------------------------------------------------------------------------------- /themes/navy/source/css/navy.styl: -------------------------------------------------------------------------------- 1 | @import "nib" 2 | @import "_variables" 3 | 4 | @import "_partial/base" 5 | @import "_partial/header" 6 | @import "_partial/index" 7 | @import "_partial/sidebar" 8 | @import "_partial/page" 9 | @import "_partial/post" 10 | @import "_partial/plugins" 11 | @import "_partial/archive" 12 | @import "_partial/mobile_nav" 13 | @import "_partial/footer" 14 | @import "_partial/highlight" -------------------------------------------------------------------------------- /themes/navy/layout/layout.swig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ partial('partial/head') }} 4 | 5 |
    6 | {{ partial('partial/header') }} 7 | {{ body }} 8 | {{ partial('partial/footer') }} 9 |
    10 | 11 | {{ partial('partial/mobile_nav') }} 12 | {{ partial('partial/after_footer') }} 13 | 14 | -------------------------------------------------------------------------------- /source/zh-cn/docs/faq/wechat.md: -------------------------------------------------------------------------------- 1 | title: 微信授权 2 | --- 3 | 4 | 后端服务通常对微信授权相关接口做了IP限制,我们联调测试时候需要关闭其限制。 5 | 6 | ### 内网接口 7 | 8 | - /hongbao/getmobilebyopenid 9 | - /hongbao/addmobileopenid 10 | - /hongbao/updatemobilebyopenid 11 | 12 | ### 关闭内网限制 13 | 14 | /home/map/odp_cater/app/hongbao/actions/api 15 | 16 | 注释:$this->checkIp = true; 17 | 18 | ### 附微信授权原理流程图 19 | 20 | ![wechat](http://younth.coding.me/static/wechat-auth.png) -------------------------------------------------------------------------------- /themes/docs/source/js/mobile-aside.js: -------------------------------------------------------------------------------- 1 | // 移动端导航处理 2 | (function(){ 3 | 'use strict'; 4 | var mobileTrigger = document.getElementById('mobileTrigger'); 5 | var mobileAside = document.getElementById('mobileAside'); 6 | mobileTrigger.onclick = function(e) { 7 | if (mobileAside.className.indexOf('mobile-show') === -1) { 8 | mobileAside.className += ' mobile-show'; 9 | } else { 10 | mobileAside.className = 'toc'; 11 | } 12 | }; 13 | })(); 14 | -------------------------------------------------------------------------------- /source/zh-cn/docs/core/runtime.md: -------------------------------------------------------------------------------- 1 | title: node-runtime原理及升级方式 2 | --- 3 | 4 | 目前外卖线上机器的nodejs环境基于一套运行时的noderuntime(即机器上并未安装node)。具体我们利用 `Node Source Release` 进行编译。 5 | 6 | ### 为什么是 runtime 7 | 8 | node版本迭代较快,为了便于我们自己维护升级,提高可控性,所以采用runtime的形式。用一个svn/git 分支去管理node版本。 9 | 10 | 11 | ### 如何编译 12 | 13 | 1. node官网下载 node tar.gz包 ,注意版本 14 | 2. 再机器上拉下runtime分支,进入source 目录 15 | 2. build.sh 里面修改 VERSION="X.X.X" 跟上面的node源码tar包文件名保持一致 16 | 3. 执行 sh build.sh 17 | 4. 将产出的noderunitme替换老的runtime即可 -------------------------------------------------------------------------------- /source/zh-cn/docs/faq/contributing.md: -------------------------------------------------------------------------------- 1 | title: NodeUI文档平台正式启动 2 | --- 3 | 4 | 各位同学,**NodeUI本季度将对外承接服务**,为保证其他业务部门同学顺利接入,同时也为其他对NodeUI感兴趣的同学提供学习平台,文档建设亟待完善。 5 | 6 | 无论你是刚接触 Node 还是 Node 的老司机,都可以贡献出自己的文章(`仅限markdown文档格式`)。包括不局限: 7 | 8 | - NodeUI如何在业务中使用 9 | - NodeUI 服务通信原理 10 | - NodeUI 运维 11 | - fekey 开发工具在 NodeUI 中的使用 12 | - 微信授权的那些坑 13 | - Universal Link 流程 14 | - NodeUI 服务运行原理 15 | - 线上部署 16 | - 监控报警 17 | - 守护进程原理 18 | - ...... 19 | 20 | 大家平时使用过程中有任何建议也欢迎提出来,共同改进,建设 NodeUI 生态 ~~ 21 | 22 | -------------------------------------------------------------------------------- /themes/docs/layout/post.swig: -------------------------------------------------------------------------------- 1 | 2 |
    3 |

    4 |
    5 | {{ page.title }} 6 |
    7 |

    8 |
    9 | 10 |
    11 |
    12 | 13 | {{ page.content }} 14 |
    15 | {# 移动端导航需要 #} 16 | {{ partial('partial/aside') }} 17 |
    18 | {# 19 | {{ partial('egg/footer') }} 20 | #} 21 | 22 | -------------------------------------------------------------------------------- /themes/navy/source/js/lang_select.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | function changeLang(){ 5 | var lang = this.value; 6 | var canonical = this.dataset.canonical; 7 | if (lang === 'en') lang = ''; 8 | if (lang) lang += '/'; 9 | 10 | location.href = '/' + lang + canonical; 11 | } 12 | 13 | document.getElementById('lang-select').addEventListener('change', changeLang); 14 | document.getElementById('mobile-lang-select').addEventListener('change', changeLang); 15 | })(); -------------------------------------------------------------------------------- /themes/docs/source/css/index.less: -------------------------------------------------------------------------------- 1 | @import "vendor/normalize"; 2 | @import "vendor/github-markdown"; 3 | @import "vendor/highlight-github"; 4 | 5 | @import "partial/var"; 6 | @import "partial/main"; 7 | @import "partial/nav"; 8 | @import "partial/toc"; 9 | @import "partial/footer"; 10 | 11 | @import "page/index"; 12 | @import "page/page"; 13 | @import "partial/mobile"; 14 | 15 | .release { 16 | padding: 40px; 17 | h1 { 18 | font-size: 1.5em; 19 | } 20 | } 21 | 22 | .cnzz { 23 | display: none; 24 | } -------------------------------------------------------------------------------- /themes/navy/scripts/tags.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | hexo.extend.tag.register('note', function(args, content){ 4 | var className = args.shift(); 5 | var header = ''; 6 | var result = ''; 7 | 8 | if (args.length){ 9 | header += '' + args.join(' ') + ''; 10 | } 11 | 12 | result += '
    ' + header; 13 | result += hexo.render.renderSync({text: content, engine: 'markdown'}); 14 | result += '
    '; 15 | 16 | return result; 17 | }, true); -------------------------------------------------------------------------------- /themes/navy/layout/partial/google_analytics.swig: -------------------------------------------------------------------------------- 1 | {% if config.google_analytics %} 2 | 11 | {% endif %} -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/archive.styl: -------------------------------------------------------------------------------- 1 | .archive-post 2 | padding: 1em 0 3 | border-top: 1px solid color-border 4 | &:last-child 5 | padding-bottom: 40px 6 | 7 | .archive-post-link 8 | clearfix() 9 | display: block 10 | color: color-default 11 | text-decoration: none 12 | line-height: line-height 13 | &:hover 14 | color: color-link-hover 15 | 16 | .archive-post-title 17 | font-family: font-title 18 | float: left 19 | font-weight: bold 20 | 21 | .archive-post-date 22 | color: color-gray 23 | float: right 24 | font-size: 0.9em -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-site-kit", 3 | "version": "0.0.1", 4 | "hexo": { 5 | "version": "3.3.1" 6 | }, 7 | "dependencies": { 8 | "hexo": "^3.2.0", 9 | "hexo-deployer-git": "^0.2.0", 10 | "hexo-generator-index": "^0.2.0", 11 | "hexo-generator-tag": "^0.2.0", 12 | "hexo-renderer-less": "^0.2.0", 13 | "hexo-server": "^0.2.0", 14 | "markdown-it": "^8.2.2", 15 | "markdown-it-replace-link": "^1.0.0", 16 | "markdown-it-toc-and-anchor": "^4.1.1", 17 | "hexo-renderer-marked": "^0.2.10", 18 | "hexo-renderer-stylus": "^0.3.1", 19 | "lunr": "^0.6.0" 20 | } 21 | } -------------------------------------------------------------------------------- /themes/docs/layout/layout.swig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial('partial/head') }} 5 | 6 | 7 | {{ partial('partial/header') }} 8 |
    9 | {{ body }} 10 |
    11 | 12 | 21 | 22 | -------------------------------------------------------------------------------- /source/zh-cn/page/process.md: -------------------------------------------------------------------------------- 1 | layout: post 2 | title: NodeUI接入流程 3 | --- 4 | 5 | 如果当前的产品开发陷入了如下的困惑: 6 | 7 | - 前端开发环境强依赖后端 8 | - 基于`React/Vue`移动端性能优化遇到首屏瓶颈 9 | - 想用`bigpipe`加速渲染 10 | - 后端统一输出的接口不满意,想拆分 or 想合并请求 11 | - 我是前端,我就是想用`Node.js` 12 | 13 | 那么,恭喜你,NodeUI是非常适合你的。我们的接入流程是: 14 | 15 | #### 1. 流量预估 16 | 17 | 如果你想直接把自己的业务接入线上的NodeUI服务,那么需要实现评估业务的流量。主要包括 `PV` 及 `QPS`。 18 | 19 | 项目 | 预估值 20 | --- | --- 21 | QPS峰值 | 10 22 | PV总量 | 10W 23 | 24 | #### 2. 申请路由及模块 25 | 26 | 项目 | 说明 27 | --- | --- 28 | 模块名称 | cfe_h5 29 | iCode地址 | 30 | 路由名称 | fly/vip 31 | BNS服务 | 32 | 33 | **注意:项目模块名称及fekey构建时候的namespance,与路由名称可以不一致** 34 | 35 | #### 3. 发送邮件 36 | -------------------------------------------------------------------------------- /themes/docs/layout/partial/footer.swig: -------------------------------------------------------------------------------- 1 | 15 | {# 16 | 17 |
    18 | 19 |
    20 | #} 21 | 22 | 23 | -------------------------------------------------------------------------------- /themes/docs/source/css/partial/footer.less: -------------------------------------------------------------------------------- 1 | .footer { 2 | background: #F9F9F9; 3 | border-top: 1px solid rgba(230, 230, 230, 0.99); 4 | position: absolute; 5 | width: 100%; 6 | bottom:0; 7 | footer { 8 | overflow: hidden; 9 | height: 60px; 10 | line-height: 60px; 11 | max-width: @max_width; 12 | margin: 0 auto; 13 | } 14 | 15 | ul { 16 | float: left; 17 | } 18 | 19 | li { 20 | display: inline-block; 21 | margin-right: 30px; 22 | } 23 | 24 | &, & a { 25 | color: #6E717C; 26 | } 27 | 28 | .license { 29 | float: right; 30 | 31 | img { 32 | vertical-align: -5px; 33 | margin-left: 4px; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /themes/docs/source/css/partial/main.less: -------------------------------------------------------------------------------- 1 | body { 2 | min-width: 320px; 3 | background: @bg_light; 4 | font-size: 14px; 5 | font-family: 'Helvetica Neue', 'Helvetica', tahoma, 'Hiragino Sans GB', 'PingFang SC', 'STHeitiSC-Light', 'Microsoft YaHei', Arial, sans-serif; 6 | & a:hover { 7 | color: #148a1a; 8 | } 9 | } 10 | 11 | h1, h2, h3, h4, h5, h6 { 12 | margin: 0; 13 | } 14 | 15 | ul, li, dl, dt, dd { 16 | margin: 0; 17 | padding: 0; 18 | } 19 | 20 | a { 21 | text-decoration: none; 22 | } 23 | 24 | p { 25 | margin: 0; 26 | } 27 | 28 | /* big font */ 29 | .ft-b { 30 | font-size: 32px; 31 | font-weight: 500; 32 | letter-spacing: 1px; 33 | line-height: 2.5em; 34 | } 35 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/post.swig: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {% if is_post() %} 4 |

    {{ post.title }}

    5 | {% else %} 6 |

    7 | {{ post.title }} 8 |

    9 | {% endif %} 10 | 11 |
    12 |
    13 | {{ page_anchor(post.content) }} 14 |
    15 | {{ partial('partial/comment') }} 16 |
    17 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/theme.swig: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | 4 | {% if plugin.preview %} 5 | 6 | {% endif %} 7 |
    8 | {{ plugin.name }} 9 |

    {{ plugin.description }}

    10 |
    11 | {% for tag in plugin.tags %} 12 | {{ tag }} 13 | {% endfor %} 14 |
    15 |
  • -------------------------------------------------------------------------------- /themes/docs/layout/partial/head.swig: -------------------------------------------------------------------------------- 1 | {{ page.title || 'NodeUI' }} - {{ __('index.slogan') }} 2 | 3 | 4 | 5 | 6 | 7 | {# 加载带版本号的css 8 | 9 | #} 10 | 11 | {{ css('css/index') }} 12 | 13 | {# 14 | 15 | #} 16 | 17 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/footer.swig: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /themes/navy/layout/plugins.swig: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    {{ page.title }}

    6 | 7 |
    {{ site.data[page.data].length }} items
    8 |
    9 |
      10 | {% for plugin in _.sortBy(site.data[page.data], 'name') %} 11 | {{ partial('partial/' + page.partial, {plugin: plugin}) }} 12 | {% endfor %} 13 |
    14 |
    15 |
    16 |
    17 | -------------------------------------------------------------------------------- /source/zh-cn/docs/intro/index.md: -------------------------------------------------------------------------------- 1 | title: NodeUI 是什么? 2 | --- 3 | 4 | **NodeUI 是基于Node.js的一套高可用的渲染容器**,目前用在百度外卖多个产品线。NodeUI并不是一个框架,而是一套完整的解决方案,主要包括: 5 | 6 | - 运行框架:`Fly` 基于`Express`的运行时框架 7 | - 开发工具:`fekey`,对fis3解决方案的封装,更好的与Node能力结合 8 | - 运行时:基于`Node`及`PM2`源码编译出的可维护的`Runtime`环境 9 | - 基础运维:与公司内部运维系统`Noah`,DA数据结合形成了一套高效稳定的运维能力 10 | 11 | 12 | ## 设计原则 13 | 14 | - 利用插件系统分离**配置与实现** 15 | - 奉行『**约定优于配置**』,按照[一套统一的约定]进行应用开发,从开发工具,到目录结构。 16 | - 遵循百度现有服务体系。与下游服务的通信采用`ral`请求方式,日志遵循统一日志格式。 17 | 18 | ## 特性 19 | 20 | - 舒适的开发体验:与FIS一致 21 | - 高效的通信:Node与PHP的通信 22 | - 便捷的部署:自动重启,负载均衡 23 | - 可靠的运维:日志 监控 报警 24 | 25 | ## 什么样的项目适合用NodeUI 26 | 27 | 目前NodeUI的定位主要是`数据处理能力`及`模板渲染能力`。基于这两大能力,NodeUI有自己的特定应用场景。主要如下: 28 | 29 | - h5页面 30 | - 接口转发,数据裁剪 31 | - 强烈希望前后端分离 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | **vuepress更好用,推荐大家使用:https://github.com/vuejs/vuepress** 3 | 4 | ## hexo-site-kit 5 | 6 | 基于Hexo快速搭建项目官网及文档平台。效果见:https://github.com/younth/hexo-site-kit/issues/1 7 | 8 | ### 安装依赖 9 | 10 | #### 1. 全局安装 hexo-cli 11 | 12 | npm i -g hexo-cli --registry=https://registry.npm.taobao.org 13 | 14 | #### 2. 安装项目依赖 15 | 16 | npm i --registry=https://registry.npm.taobao.org 17 | 18 | ### 查看效果 19 | 20 | hexo s 21 | 22 | ### 开发 23 | 24 | hexo n "My New Post" 25 | hexo s 26 | hexo s -g // 预览加部署 27 | hexo d -g // hexo g && hexo d 生成及部署 28 | 29 | ### 切换主题 30 | 31 | 修改`_config.yml` 里面的 `theme`。目前提供两种主题: 32 | 33 | - docs: 基于 egg 官网改造 34 | - navy: 基于 hexo 官网改造 35 | 36 | **切换主题的时候,务必先执行 `hexo clean` 清空之前的编译缓存** 37 | 38 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/comment.swig: -------------------------------------------------------------------------------- 1 | {% if page.comments && config.disqus_shortname %} 2 |
    3 |
    4 |
    5 | 18 | {% endif %} -------------------------------------------------------------------------------- /themes/navy/source/js/mobile_nav.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | var body = document.getElementsByTagName('body')[0]; 5 | var navToggle = document.getElementById('mobile-nav-toggle'); 6 | var container = document.getElementById('container'); 7 | var dimmer = document.getElementById('mobile-nav-dimmer'); 8 | var CLASS_NAME = 'mobile-nav-on'; 9 | if (!navToggle) return; 10 | 11 | navToggle.addEventListener('click', function(e){ 12 | e.preventDefault(); 13 | e.stopPropagation(); 14 | body.classList.toggle(CLASS_NAME); 15 | }); 16 | 17 | dimmer.addEventListener('click', function(e){ 18 | if (!body.classList.contains(CLASS_NAME)) return; 19 | 20 | e.preventDefault(); 21 | body.classList.remove(CLASS_NAME); 22 | }); 23 | })(); -------------------------------------------------------------------------------- /themes/navy/layout/archive.swig: -------------------------------------------------------------------------------- 1 | {% set page.title = 'News' %} 2 |
    3 |
    4 |
    5 | {% for post in page.posts %} 6 | {% if loop.index == 1 %} 7 | {{ partial('partial/post', {post: post}) }} 8 | {% else %} 9 | 15 | {% endif %} 16 | {% endfor %} 17 |
    18 |
    19 |
    -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/footer.styl: -------------------------------------------------------------------------------- 1 | #footer 2 | clearfix() 3 | padding: 40px 0 4 | color: rgba(255, 255, 255, 0.6) 5 | font-family: font-title 6 | position: relative 7 | background: color-navy 8 | text-align: center 9 | @media mq-normal 10 | text-align: left 11 | @media print 12 | display: none 13 | a 14 | color: inherit 15 | text-decoration: none 16 | transition: 0.2s 17 | &:hover 18 | color: #fff 19 | 20 | #footer-copyright 21 | line-height: 1.4 22 | @media mq-normal 23 | float: left 24 | a 25 | font-weight: bold 26 | 27 | #footer-links 28 | margin-top: 1em 29 | @media mq-normal 30 | float: right 31 | margin-top: 0 32 | 33 | .footer-link 34 | font-size: 30px 35 | margin-left: 20px 36 | &:first-child 37 | margin-left: 0 -------------------------------------------------------------------------------- /source/zh-cn/fekey/index.md: -------------------------------------------------------------------------------- 1 | title: fekey前端工程化解决方案 2 | --- 3 | 4 | **fekey是一套前端工程化解决方案**,通过优化构建工具,解决方案集成的方式,帮助开发人员降低研发成本、提高研发效率。它主要包括以下几方面: 5 | 6 | * 构建工具:基于fis3封装的构建工具 7 | * 命令行扩展:支持通过插件的形式扩展fekey命令行 8 | * 脚手架:支持通过用户自定义脚手架 9 | * 构建解决方案:封装了构建层了解决方案,更好地与NodeUI集成 10 | 11 | ## 设计原则 12 | 13 | * 利用插件方式,实现系统的分离和扩展 14 | * 遵循降低研发成本原则,针对不同业务场景提供解决方案的集成 15 | * 深入理解FIS团队的fis3技术成果,构建最优化 16 | 17 | ## 特性 18 | 19 | * 业务场景优化:针对一些特定的业务场景提供完善的构架解决方案 20 | * 优秀的脚手架能力:支持自定义脚手架规则,从gihub上同步脚手架工程 21 | * 舒适的开发体验:本地server,proxy能力,多重mock 22 | * 便捷的工具继承:通过命令行扩展继承社区解决方案,当前继承了jsdoc、localserver等 23 | 24 | ## 什么样的项目适合用fekey 25 | 26 | * 目前fekey作为NodeUI配合使用的开发工具,针对NodeUI的app工程在构建上做了深度优化,NodeUI的各业务方可以使用fekey。 27 | * 原来基于fis3的项目,想要具有更丰富的脚手架和命令行扩展能力的工程,可以将工程迁移到fekey,迁移的成本很低。 28 | * 对构建能力感兴趣的同学,可以在项目中尝试使用fekey,fekey接管了fis3的构建核心,大家可以参与到构建核心能力的升级和深度优化中来。 -------------------------------------------------------------------------------- /themes/docs/source/css/partial/toc.less: -------------------------------------------------------------------------------- 1 | aside { 2 | width: 220px; 3 | height: 100%; 4 | position: fixed; 5 | top: 56px; 6 | background: #fff; 7 | border-right:1px solid #E6E6E6; 8 | overflow-y: scroll; 9 | 10 | dl { 11 | padding: 60px 0; 12 | } 13 | 14 | dt { 15 | padding-bottom: 10px; 16 | font-weight: bold; 17 | font-size: 16px; 18 | color: #333; 19 | } 20 | 21 | dd { 22 | margin-bottom: 30px; 23 | } 24 | 25 | ul li a { 26 | font-size: 14px; 27 | color: #585858; 28 | height: 30px; 29 | line-height: 30px; 30 | &:hover{ 31 | color: #22ab28; 32 | transition: 0.3s color; 33 | } 34 | &.cur { 35 | color: #22ab28; 36 | } 37 | } 38 | 39 | li { 40 | list-style-type: none; 41 | } 42 | } 43 | 44 | .index-aside aside { 45 | display: none; 46 | } 47 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: Hexo-docs 2 | subtitle: "快捷建设你的官网平台" 3 | description: "快捷建设你的官网平台" 4 | language: 5 | - zh-cn 6 | - en 7 | timezone: UTC 8 | url: http://baidu.com 9 | # 文件路径 10 | root: / 11 | archive_dir: news 12 | permalink: news/:year/:month/:day/:title/ 13 | new_post_name: :year-:month-:day-:title.md # File name of new posts 14 | post_asset_folder: true 15 | highlight: 16 | enable: true 17 | line_number: false 18 | per_page: 0 19 | 20 | # Extensions 21 | ## Plugins: https://hexo.io/plugins/ 22 | ## Themes: https://hexo.io/themes/ 23 | theme: docs 24 | # theme: navy 25 | 26 | less: 27 | compress: true 28 | 29 | # 忽略的文件,开始匹配的目录是source目录 30 | skip_render: 31 | - ci.yml 32 | - README.md 33 | 34 | # Deployment 35 | ## Docs: https://hexo.io/docs/deployment.html 36 | deploy: 37 | type: git 38 | # 仓库地址需要换成个人的 39 | repo: 40 | branch: master 41 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/sidebar.styl: -------------------------------------------------------------------------------- 1 | #sidebar 2 | width: sidebar-width 3 | float: left 4 | padding-bottom: 40px 5 | opacity: 0.8 6 | margin-left: sidebar-width * -1 7 | display: none 8 | @media mq-normal 9 | display: block 10 | 11 | .sidebar-title 12 | margin-top: 40px 13 | padding: 10px 0 14 | font-family: font-title 15 | font-weight: bold 16 | color: color-link 17 | display: inline-block 18 | border-top: 1px solid color-border 19 | line-height: 1 20 | 21 | .sidebar-link 22 | font-family: font-title 23 | display: block 24 | color: color-default 25 | text-decoration: none 26 | padding: 7px 0 27 | line-height: 1 28 | position: relative 29 | width: 100% 30 | text-overflow: ellipsis 31 | overflow: hidden 32 | white-space: nowrap 33 | &.current 34 | color: color-link 35 | &:hover 36 | color: color-link-hover -------------------------------------------------------------------------------- /source/zh-cn/docs/basics/router.md: -------------------------------------------------------------------------------- 1 | title: Router 路由 2 | --- 3 | 4 | Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系, 5 | 框架约定了 `server/router.js` 文件用于统一所有路由规则。 6 | 7 | 通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,集中在一起我们可以更方便的来查看全局的路由规则。 8 | 9 | ## 如何定义 Router 10 | 11 | ### 手动方式 12 | 13 | 寻找项目的router.js对应的路由映射。访问路径为`fly/${yourpath}/${routername}` 14 | 15 | ```js 16 | // app/router.js 17 | module.exports = { 18 | 'getwxtoken': 'action/common/wxtoken.js', 19 | 'bdwmurl': 'action/common/bdwmurl.js', 20 | 'universal': 'action/common/universal.js' 21 | } 22 | ``` 23 | 24 | ### 自动路由 25 | 26 | 以 `fly/h5/demo`为例,寻找的路径及顺序是: 27 | 28 | - action/huodong/demo.js 29 | - action/app/demo.js 30 | - action/demo.js 31 | 32 | ### 注意 33 | 34 | 路由支持时间戳:主要是为了防止微信屏蔽path,下面这两种路由效果是一样的 35 | 36 | - waimai.baidu.com/fly/h5/435353532342/demo 37 | - waimai.baidu.com/fly/h5/demo 38 | 39 | ## todo 40 | 41 | 路由系统需要升级 42 | -------------------------------------------------------------------------------- /themes/navy/source/js/toc.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | var header = document.getElementById('header'); 5 | var toc = document.getElementById('article-toc'); 6 | var tocTop = document.getElementById('article-toc-top'); 7 | var headerHeight = header.clientHeight; 8 | 9 | if (!toc) return; 10 | 11 | function updateSidebarPosition(){ 12 | var scrollTop = document.scrollingElement.scrollTop; 13 | 14 | if (scrollTop > headerHeight){ 15 | toc.classList.add('fixed'); 16 | } else { 17 | toc.classList.remove('fixed'); 18 | } 19 | } 20 | 21 | window.addEventListener('scroll', function(){ 22 | window.requestAnimationFrame(updateSidebarPosition); 23 | }); 24 | 25 | updateSidebarPosition(); 26 | 27 | tocTop.addEventListener('click', function(e){ 28 | e.preventDefault(); 29 | document.scrollingElement.scrollTop = 0; 30 | }); 31 | })(); 32 | -------------------------------------------------------------------------------- /themes/docs/lib/renderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const url = require('url'); 4 | const markdownItTocAndAnchor = require('markdown-it-toc-and-anchor').default; 5 | const markdownItReplaceLink = require('markdown-it-replace-link'); 6 | 7 | const md = require('markdown-it')({ 8 | // replace .md to .html in markdown files 9 | replaceLink(link) { 10 | const urlObj = url.parse(link); 11 | if (urlObj.pathname && urlObj.pathname[0] === '.' && /\.md$/.test(urlObj.pathname)) { 12 | urlObj.pathname = urlObj.pathname.replace(/md$/, 'html'); 13 | return url.format(urlObj); 14 | } 15 | return link; 16 | }, 17 | }); 18 | md.use(markdownItTocAndAnchor, { 19 | toc: true, 20 | anchorLink: true, 21 | anchorClassName: 'markdown-anchor', 22 | }); 23 | md.use(markdownItReplaceLink); 24 | 25 | module.exports = function(data) { 26 | const a = md.render(data.text); 27 | return a; 28 | }; 29 | -------------------------------------------------------------------------------- /themes/navy/source/css/_variables.styl: -------------------------------------------------------------------------------- 1 | // Config 2 | support-for-ie = false 3 | vendor-prefixes = webkit moz ms official 4 | 5 | // Colors 6 | color-default = #444 7 | color-gray = #999 8 | color-border = #e3e3e3 9 | color-navy = hsl(210, 25%, 12%) 10 | color-link = #0e83cd 11 | color-link-hover = lighten(color-link, 10%) 12 | 13 | // Typography 14 | font-sans = "Helvetica Neue", Helvetica, Arial, sans-serif 15 | font-serif = Garamond, Georgia, "Times New Roman", serif 16 | font-mono = "Source Code Pro", Monaco, Menlo, Consolas, monospace 17 | font-title = Lato, font-sans 18 | font-size = 15px 19 | line-height = 1.6em 20 | 21 | // Layout 22 | max-width = 1200px 23 | gutter-width = 20px 24 | sidebar-width = 220px 25 | mobile-nav-width = 260px 26 | 27 | // Media queries 28 | mq-mobile = "screen and (max-width: 768px)" 29 | mq-normal = "screen and (min-width: 769px)" 30 | mq-tablet = "screen and (min-width: 480px)" 31 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/mobile_nav.swig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /themes/docs/layout/index.swig: -------------------------------------------------------------------------------- 1 |
    2 | 15 |
    16 | {# 移动端导航需要 #} 17 |
    18 | {{ partial('partial/aside') }} 19 |
    20 | {{ partial('partial/footer') }} 21 | 22 | 23 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/after_footer.swig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ js('js/lang_select') }} 4 | {{ js('js/scrollingelement') }} 5 | {{ js('js/toc') }} 6 | {{ js('js/mobile_nav') }} 7 | 8 | 9 | {% if page.layout === 'plugins' %} 10 | 11 | 12 | 13 | {{ js('js/plugins') }} 14 | 15 | {% endif %} 16 | 17 | {% if config.algolia[page.lang] %} 18 | 19 | 27 | {% endif %} 28 | -------------------------------------------------------------------------------- /source/zh-cn/docs/intro/quickstart.md: -------------------------------------------------------------------------------- 1 | title: 快速入门 2 | --- 3 | 4 | 本文将以h5模块为实例,一步步地搭建出一个 NodeUI 应用,让你能快速的入门 NodeUI 开发。 5 | 6 | > h5模块是运营活动方向主要的开发模块。主要用于开发: 包括端上的榜单、品牌馆等常态运营页; 每个月的特型运营活动; 成长轨迹等用户成长方向的长期运营页。在nodeui层支持微信授权、接口转发与数据裁剪等能力。 7 | 8 | ### 模块目录结构: 9 | 10 | ``` 11 | node_h5 12 | ├─ client (客户端) 13 | │ ├─ node_modules (node_h5特殊依赖的npm包) 14 | │ ├─ page (入口文件) 15 | │ │ ├─ app (常态页) 16 | │ │ ├─ huodong (活动页) 17 | │ │ └─ layout.tpl 18 | │ ├─ widget (具体业务代码) 19 | │ │ ├─ app 20 | │ │ └─ huodong 21 | │ │ └─ common (通用组件及方法) 22 | │ └─ static (公共静态资源) 23 | ├─ server (服务端) 24 | │ ├─ action (自动路由及逻辑处理) 25 | │ │ ├─ app 26 | │ │ ├─ huodong 27 | │ │ └─ common 28 | │ ├─ model (数据处理) 29 | │ │ ├─ app 30 | │ │ └─ huodong 31 | │ │ └─ common 32 | │ ├─ lib (工具库及微信授权相关代码) 33 | │ └─ router.js (手动路由) 34 | ├─ mock (数据mock配置) 35 | ├─ fekey-conf.js (fekey编译配置) 36 | ├─ package.json (入口文件) 37 | ... 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /source/_data/sidebar.yml: -------------------------------------------------------------------------------- 1 | # nodeui文档 2 | docs: 3 | Intro: 4 | What is NodeUI: /docs/intro/index.html 5 | Get Start: /docs/intro/quickstart.html 6 | Basics: 7 | Structure: /docs/basics/structure.html 8 | Router: /docs/basics/router.html 9 | Service: /docs/basics/service.html 10 | Mock: /docs/basics/mock.html 11 | Core: 12 | Development: /docs/core/development.html 13 | # Unit Testing: /docs/core/unittest.html 14 | Deployment: /docs/core/deployment.html 15 | Logger: /docs/core/logger.html 16 | View: /docs/core/view.html 17 | Runtime: /docs/core/runtime.html 18 | Advanced: 19 | FetchServer: /docs/advanced/fetch-server.html 20 | ServerIsolation: /docs/advanced/server-isoloton.html 21 | FAQ: 22 | Deploy: /docs/faq/deploy.html 23 | debug: /docs/faq/debug.html 24 | wechat: /docs/faq/wechat.html 25 | contributing: /docs/faq/contributing.html 26 | 27 | # fekey 28 | fekey: 29 | Intro: 30 | What is Fekey: /fekey/index.html 31 | Fekey Get Start: /fekey/quickstart.html 32 | -------------------------------------------------------------------------------- /source/zh-cn/docs/basics/structure.md: -------------------------------------------------------------------------------- 1 | title: 目录结构 2 | --- 3 | 4 | 在[快速入门](../intro/quickstart.md)中,大家对框架应该有了初步的印象,接下来我们简单了解下目录约定规范。 5 | 6 | ### 1. 框架目录结构 7 | ![framework] 8 | 9 | ### 2. 业务模块结构 10 | ![business] 11 | 12 | [framework]: http://younth.coding.me/static/520/fly.png 13 | [business]: http://younth.coding.me/static/520/project.jpg 14 | 15 | ```bash 16 | nodeui-project 17 | ├── package.json 18 | ├── fis-config.js 19 | ├── client 20 | | ├── package.json 21 | │ ├── page 22 | │ ├── layout.tpl 23 | │ | └── index.tpl (可选) 24 | │ ├── static 25 | │ | └── test.js 26 | │ └── widget 27 | │ ├── common 28 | │ └── app (可选) 29 | ├── server 30 | | ├── router.js 31 | │ ├── action 32 | │ | └── test.js 33 | │ ├── model 34 | │ | └── test.js 35 | │ ├── lib (可选) 36 | │ | └── util.js.js 37 | │ └── dif (可选) 38 | │ └── test.js 39 | └── mock 40 | ├── server.conf 41 | ├── ral 42 | | └── hongbao-getmobilebyopenid.js(可选) 43 | └── common 44 | ├── sample.json (可选) 45 | └── dynamic.js (可选) 46 | ``` 47 | 48 | 如上,由框架约定的目录: 49 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/share.swig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tweet 7 | 8 | Follow @hexojs 9 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/base.styl: -------------------------------------------------------------------------------- 1 | global-reset() 2 | 3 | html 4 | box-sizing: border-box 5 | 6 | *, *:before, *:after 7 | box-sizing: inherit 8 | 9 | button 10 | input[type="reset"] 11 | input[type="button"] 12 | input[type="submit"] 13 | &::-moz-focus-inner 14 | padding: 0 15 | margin: 0 16 | border: 0 17 | 18 | input, button, select 19 | margin: 0 20 | padding: 0 21 | border: 0 22 | 23 | html, body 24 | @media screen 25 | height: 100% 26 | // overflow: hidden 27 | 28 | body 29 | background: color-navy 30 | font-size: font-size 31 | font-family: font-sans 32 | color: color-default 33 | text-rendering: optimizeLegibility 34 | -webkit-font-smoothing: antialiased 35 | -moz-osx-font-smoothing: grayscale 36 | position: relative 37 | 38 | .wrapper 39 | clearfix() 40 | @media screen 41 | max-width: max-width 42 | margin: 0 auto 43 | 44 | .inner 45 | clearfix() 46 | @media screen 47 | padding: 0 gutter-width 48 | 49 | #content-wrap 50 | background: #fff 51 | border-top: 1px solid darken(color-navy, 5%) 52 | border-bottom: 1px solid darken(color-navy, 5%) 53 | margin: -1px 0 54 | -------------------------------------------------------------------------------- /source/zh-cn/docs/faq/start.md: -------------------------------------------------------------------------------- 1 | title: 启动失败 2 | --- 3 | 4 | ``` 5 | FATAL: 17-03-27 15:45:52 [-:-] errno[0] logId[-] uri[-] user[-] refer[-] cookie[-] [yog-ral] [cluster main][Config] config [/home/map/nodeui/conf/ral] load failed 6 | 7 | AssertionError: [online] config error => [server]: expected undefined to be an array 8 | at validate (/home/map/nodeui/node_modules/node-ral/lib/config.js:122:45) 9 | at /home/map/nodeui/node_modules/node-ral/lib/config.js:141:9 10 | at Function._.map._.collect (/home/map/nodeui/node_modules/node-ral/node_modules/underscore/underscore.js:172:24) 11 | at loadRawConf (/home/map/nodeui/node_modules/node-ral/lib/config.js:134:7) 12 | at Object.load (/home/map/nodeui/node_modules/node-ral/lib/config.js:210:9) 13 | at Function.RAL.init (/home/map/nodeui/node_modules/node-ral/lib/ral.js:477:16) 14 | at module.exports (/home/map/nodeui/extension/tools/RAL.js:17:9) 15 | at /home/map/nodeui/kernel/middlewares/dispatcher/index.js:40:23 16 | at Array.forEach (native) 17 | at initCommonTools (/home/map/nodeui/kernel/middlewares/dispatcher/index.js:35:15) 18 | ``` 19 | 20 | 这种 `ral` 配置问题通常是因为向后请求模块引用错误。本地开发环境引用 `node-ral` ,生产环境必须用 `yog-ral`。 21 | 22 | ### node-ral 与 yog-ral 的区别 23 | 24 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/header.swig: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /themes/docs/layout/partial/header.swig: -------------------------------------------------------------------------------- 1 | 44 | -------------------------------------------------------------------------------- /source/zh-cn/faq.md: -------------------------------------------------------------------------------- 1 | title: 常见问题 2 | --- 3 | 4 | 如果下面的内容无法解决你的问题,请查看 [Egg issues](https://github.com/eggjs/egg/issues)。 5 | 6 | ## 为什么我的配置不生效? 7 | 8 | 框架的配置功能比较强大,有不同环境变量,又有框架/插件/应用等很多地方配置。 9 | 10 | 如果你分析问题时,想知道当前运行时使用的最终配置,可以查看下 `run/application_config.json` 和 `run/agent_config.json` 这两个文件。 11 | 12 | 也可参见[配置文件](https://eggjs.org/zh-cn/basics/config.html#配置结果)。 13 | 14 | ## 进程管理为什么没有选型 PM2 ? 15 | 16 | 1. PM2 模块本身复杂度很高,出了问题很难排查。我们认为框架使用的工具复杂度不应该过高,而 PM2 自身的复杂度超越了大部分应用本身。 17 | 2. 没法做非常深的优化。 18 | 3. 切实的需求问题,一个进程里跑 leader,其他进程代理到 leader 这种模式([多进程模型](./core/cluster-and-ipc.md)),在企业级开发中对于减少远端连接,降低数据通信压力等都是切实的需求。特别当应用规模大到一定程度,这就会是刚需。egg 本身起源于蚂蚁金服和阿里,我们对标的起点就是大规模企业应用的构建,所以要非常全面。这些特性通过 PM2 很难做到。 19 | 20 | 进程模型非常重要,会影响到开发模式,运行期间的深度优化等,我们认为可能由框架来控制比较合适。 21 | 22 | **如何使用 PM2 启动应用?** 23 | 24 | 尽管我们不推荐使用 PM2 启动,但仍然是可以做到的。 25 | 26 | 首先,在项目根目录定义启动文件: 27 | 28 | ```js 29 | // server.js 30 | const egg = require('egg'); 31 | 32 | const workers = Number(process.argv[2] || require('os').cpus().length); 33 | egg.startCluster({ 34 | workers, 35 | baseDir: __dirname, 36 | }); 37 | ``` 38 | 39 | 这样,我们就可以通过 PM2 进行启动了: 40 | 41 | ```bash 42 | pm2 start server.js 43 | ``` 44 | 45 | ## 为什么会有 csrf 报错? 46 | 47 | 通常有两种 csrf 报错: 48 | 49 | - `missing csrf token` 50 | - `invalid csrf token` 51 | 52 | Egg 内置的 [egg-security](https://github.com/eggjs/egg-security/) 插件默认对所有『非安全』的方法,例如 `POST`,`PUT`,`DELETE` 都进行 CSRF 校验。 53 | 54 | 请求遇到 csrf 报错通常是因为没有加正确的 csrf token 导致,具体实现方式,请阅读[安全威胁 CSRF 的防范](./core/security.md#安全威胁csrf的防范)。 55 | -------------------------------------------------------------------------------- /source/zh-cn/docs/basics/service.md: -------------------------------------------------------------------------------- 1 | title: Service 2 | --- 3 | 4 | NodeUI 中,使用 [node-ral] 进行后端服务管理,我们引入后端服务管理层主要是解决以下几个问题: 5 | 6 | - 后端服务配置统一管理 7 | - 封装异常处理、超时重试,提升系统稳定性 8 | - 封装日志,便于线上问题追查 9 | - 抽象请求协议、数据格式与数据编码,统一用户接口 10 | 11 | ## 主要特征 12 | 13 | - BNS Support 14 | - IDC Support 15 | - json,querystring,form ... 16 | - http/https 17 | - proxy 18 | - Load Balance 19 | 20 | ## 使用 Service 21 | 22 | `Fly`全局变量下面有`ral`及`ralP`两个方法,用于向后发送请求。区别是`ralP`返回的是一个`promise`对象。 23 | 24 | 25 | ```js 26 | module.exports = { 27 | getData: function(req, tools, params) { 28 | var options = { 29 | data: params || {}, 30 | path: '/huodong/gamebase', 31 | //enableMock: true, 32 | }; 33 | // ralP 推荐 34 | return Fly.ralP('SHOPUI', options) 35 | // ral 36 | FLy.RAL(serverName, defaultOptions).on('data', function (data) { 37 | resolve(data); 38 | }).on('error', function (error) { 39 | reject(error); 40 | }); 41 | } 42 | } 43 | 44 | ``` 45 | 46 | ## 服务配置 47 | 48 | ral请求的配置目录为`fly/conf/ral/config.js`,里面主要定义了向后请求的host及port。更改配置即可更新向后请求的服务。 49 | 50 | ```js 51 | // 全局配置 serverName为 SHOPUI 52 | let serverHost = 'waimai.baidu.com'; 53 | let serverPort = 80; 54 | 55 | // dev配置 serverName为 dev 56 | const devServerHost = 'waimai.baidu.com'; 57 | const devServerPort = 80; 58 | ``` 59 | 60 | 61 | ## 向后服务通信原理 62 | 63 | ![node-php](http://younth.coding.me/static/nodeui/bns.png) 64 | 65 | 66 | [node-ral]: https://github.com/fex-team/node-ral 67 | -------------------------------------------------------------------------------- /source/zh-cn/docs/faq/debug.md: -------------------------------------------------------------------------------- 1 | title: Node.js调试 2 | --- 3 | 4 | ## 线下调试 5 | 6 | ### 需求 7 | 8 | - http请求断点调试 9 | - node-ral 向后请求查看 10 | - 启动调试 11 | 12 | 13 | ## 版本 14 | 15 | node v4.2.4 16 | Node Inspector v0.12.5 17 | 18 | ## node-inspector 19 | 20 | ``` 21 | npm i -g node-inspector 22 | 23 | npm run debug(node --debug app.js) 24 | 25 | node-inspector --web-port=5006 26 | 27 | ``` 28 | 29 | > 建议配合 `supervisor` 使用,支持node 自动重启。 30 | 31 | ## devtool 32 | 33 | > 建议大家尝试,取代node-inspector 34 | 35 | https://github.com/Jam3/devtool 36 | 37 | ## 线上—日志 38 | 39 | 线上通过日志排查 access nodeui等 40 | 41 | ## 远程调试 42 | 43 | 44 | ## 错误捕获 45 | 46 | ```js 47 | 'use strict'; 48 | 49 | const Http = require('http'); 50 | 51 | const server = Http.createServer((req, res) => { 52 | const promise = new Promise((resolve, reject) => { 53 | let result = ''; 54 | req.on('data', (data) => { 55 | result += data; 56 | }); 57 | 58 | req.once('end', () => { 59 | const obj = JSON.parse(result); 60 | resolve(obj); 61 | }); 62 | }); 63 | 64 | promise.then((obj) => { 65 | res.writeHead(200); 66 | // 这里会报错 67 | res.end(obj.foo.bar); 68 | }).catch((reason) => { 69 | res.writeHead(500); 70 | res.end(); 71 | console.error(reason); 72 | // 抛错后退出程序 73 | process.abort() 74 | }); 75 | }); 76 | 77 | server.listen(8080, () => { 78 | console.log('listening at http://localhost:8080'); 79 | }); 80 | 81 | ``` 82 | // post请求 83 | curl -X POST http://localhost:8080 -d '{"Hi": "world"}' -------------------------------------------------------------------------------- /themes/docs/source/css/page/page.less: -------------------------------------------------------------------------------- 1 | .page-title { 2 | padding: 20px 0 150px; 3 | background: @bg_dark; 4 | text-align: center; 5 | h1{ 6 | text-shadow: 3px 4px 0px rgba(255,255,255,0.10); 7 | letter-spacing: 2px; 8 | font-size: 64px; 9 | color: #fff; 10 | font-weight: 500; 11 | } 12 | h2{ 13 | font-size: 16px; 14 | color: #4E5668; 15 | padding-top: 5px; 16 | font-weight: 300; 17 | letter-spacing: 0.5px; 18 | } 19 | } 20 | 21 | .page-main { 22 | margin: 0px auto 0px; 23 | max-width: @max_width; 24 | min-height: 200px; 25 | overflow: hidden; 26 | background: #FFFFFF; 27 | border-radius: 2px; 28 | margin-top: 56px; 29 | article { 30 | min-height: 400px; 31 | padding:50px 50px 50px 270px; 32 | } 33 | &.post { 34 | margin-top: 0; 35 | article{ 36 | padding: 40px; 37 | } 38 | aside { 39 | display: none; 40 | } 41 | } 42 | } 43 | .post-titlt { 44 | margin-top: 56px; 45 | position: relative; 46 | background: url("/images/banner.jpg") 0 80%; 47 | background-size: cover; 48 | } 49 | 50 | .docs-header { 51 | position: relative; 52 | margin-top: 0; 53 | margin-bottom: 0; 54 | padding: 50px 40px; 55 | text-align: center; 56 | color: #fff; 57 | font-size: 30px; 58 | z-index: 10; 59 | .container { 60 | margin-right: auto; 61 | margin-left: auto; 62 | padding-left: 15px; 63 | padding-right: 15px; 64 | @media (min-width: 1200px) { 65 | width:1170px 66 | } 67 | @media (min-width: 992px) { 68 | width:970px 69 | } 70 | @media (min-width: 768px) { 71 | width:750px 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /themes/navy/layout/page.swig: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |
    6 |
    7 |
    8 |
    9 |

    {{ page.title }}

    10 | 11 |
    12 |
    13 | {{ page_anchor(page.content) }} 14 |
    15 |
    16 | 17 | {{ page_nav() }} 18 |
    19 | {# 20 | {{ partial('partial/comment') }} 21 | #} 22 |
    23 |
    24 | 31 |
    32 |
    33 | {{ partial('partial/sidebar') }} 34 |
    35 |
    36 |
    37 | -------------------------------------------------------------------------------- /themes/docs/languages/en.yml: -------------------------------------------------------------------------------- 1 | # 对应中文需要翻译成英文 2 | menu: 3 | guide: Guide 4 | api: API 5 | tutorials: Tutorials 6 | user: Case 7 | process: 接入流程 8 | # plugins: 插件 9 | # release: 发布日志 10 | index: 11 | slogan: "高可用的渲染容器" 12 | feature11: "进程管理" 13 | feature12: "内置的进程管理和负载均衡" 14 | feature21: "自定义" 15 | feature31: "强大的插件系统" 16 | feature32: "插件系统可插拔及可扩展随心所欲" 17 | getstart: "getstart" 18 | readmore: "readmore" 19 | header: 20 | translations: "change language" 21 | sidebar: 22 | docs: 23 | Intro: 新手指南 24 | What is NodeUI: NodeUI 是什么 25 | Get Start: 快速入门 26 | Basics: 基础功能 27 | Structure: 目录结构 28 | Environment: 运行环境 29 | Config: 配置 30 | Middleware: 中间件 31 | Router: 路由 32 | Controller: Controller 33 | Service: Service 34 | Schedule: 定时任务 35 | Extend: 框架扩展 36 | Custom init: 启动自定义 37 | Development: 本地开发 38 | Unit Testing: 单元测试 39 | Core: 核心功能 40 | Security: 安全 41 | View: 模板渲染 42 | View Plugin: 模板插件开发规范 43 | # Passport: 44 | HttpClient: HttpClient 45 | Logger: 日志 46 | Error Handling: 异常处理 47 | Cluster and IPC: 多进程模型和进程间通讯 48 | Cooke and Session: Cookie 和 Session 49 | Tutorials: 教程 50 | Advanced: 进阶 51 | Cluster Client: 多进程研发模式增强 52 | Framework: 框架开发 53 | Plugin: 插件开发 54 | Progressive: 渐进式开发 55 | Async Function: Async Function 56 | Deployment: 应用部署 57 | # Loader: 58 | Community: 社区 59 | Contributing: 如何贡献 60 | Member Guide: 成员指南 61 | FAQ: 常见问题 62 | Resource: 资源 63 | FetchServer: 负载均衡 64 | Deploy: 部署问题 65 | Mock: 数据模拟 66 | ServerIsolation: 服务隔离 67 | contributing: 贡献文章 68 | debug: Node调试 69 | wechat: 微信授权 70 | fekey: 71 | Intro: Guide 72 | What is Fekey: what is fekey 73 | Fekey Get Start: Quick Start -------------------------------------------------------------------------------- /themes/docs/languages/zh-cn.yml: -------------------------------------------------------------------------------- 1 | menu: 2 | guide: 指南 3 | api: API 4 | tutorials: 教程 5 | user: 使用案例 6 | process: 接入流程 7 | # plugins: 插件 8 | # release: 发布日志 9 | 10 | index: 11 | slogan: "高可用的渲染容器" 12 | feature11: "进程管理" 13 | feature12: "内置的进程管理和负载均衡" 14 | feature21: "自定义" 15 | feature31: "强大的插件系统" 16 | feature32: "插件系统可插拔及可扩展随心所欲" 17 | getstart: "开始使用" 18 | readmore: "查看更多" 19 | 20 | header: 21 | translations: "切换语言" 22 | 23 | sidebar: 24 | docs: 25 | Intro: 新手指南 26 | What is NodeUI: NodeUI 是什么 27 | Get Start: 快速入门 28 | Basics: 基础功能 29 | Structure: 目录结构 30 | Environment: 运行环境 31 | Config: 配置 32 | Middleware: 中间件 33 | Router: 路由 34 | Controller: Controller 35 | Service: Service 36 | Schedule: 定时任务 37 | Extend: 框架扩展 38 | Custom init: 启动自定义 39 | Development: 本地开发 40 | Unit Testing: 单元测试 41 | Core: 核心功能 42 | Security: 安全 43 | View: 模板渲染 44 | View Plugin: 模板插件开发规范 45 | # Passport: 46 | HttpClient: HttpClient 47 | Logger: 日志 48 | Error Handling: 异常处理 49 | i18n: 国际化 50 | Cluster and IPC: 多进程模型和进程间通讯 51 | Cooke and Session: Cookie 和 Session 52 | Tutorials: 教程 53 | Advanced: 进阶 54 | Cluster Client: 多进程研发模式增强 55 | Framework: 框架开发 56 | Plugin: 插件开发 57 | Progressive: 渐进式开发 58 | Async Function: Async Function 59 | Deployment: 应用部署 60 | # Loader: 61 | Community: 社区 62 | Contributing: 如何贡献 63 | Member Guide: 成员指南 64 | FAQ: 常见问题 65 | Resource: 资源 66 | 67 | FetchServer: 负载均衡 68 | Deploy: 部署问题 69 | Mock: 数据模拟 70 | ServerIsolation: 服务隔离 71 | contributing: 贡献文章 72 | debug: Node调试 73 | wechat: 微信授权 74 | 75 | fekey: 76 | Intro: 新手指南 77 | What is Fekey: fekey 是什么 78 | Fekey Get Start: 快速开始 79 | -------------------------------------------------------------------------------- /themes/navy/languages/en.yml: -------------------------------------------------------------------------------- 1 | # 对应中文需要翻译成英文 2 | menu: 3 | guide: Guide 4 | api: API 5 | tutorials: Tutorials 6 | user: Case 7 | process: 接入流程 8 | # plugins: 插件 9 | # release: 发布日志 10 | index: 11 | slogan: "高可用的渲染容器" 12 | feature11: "进程管理" 13 | feature12: "内置的进程管理和负载均衡" 14 | feature21: "自定义" 15 | feature31: "强大的插件系统" 16 | feature32: "插件系统可插拔及可扩展随心所欲" 17 | getstart: "getstart" 18 | readmore: "readmore" 19 | header: 20 | translations: "change language" 21 | page: 22 | last_updated: last_updated %s 23 | sidebar: 24 | docs: 25 | Intro: 新手指南 26 | What is NodeUI: NodeUI 是什么 27 | Get Start: 快速入门 28 | Basics: 基础功能 29 | Structure: 目录结构 30 | Environment: 运行环境 31 | Config: 配置 32 | Middleware: 中间件 33 | Router: 路由 34 | Controller: Controller 35 | Service: Service 36 | Schedule: 定时任务 37 | Extend: 框架扩展 38 | Custom init: 启动自定义 39 | Development: 本地开发 40 | Unit Testing: 单元测试 41 | Core: 核心功能 42 | Security: 安全 43 | View: 模板渲染 44 | View Plugin: 模板插件开发规范 45 | # Passport: 46 | HttpClient: HttpClient 47 | Logger: 日志 48 | Error Handling: 异常处理 49 | Cluster and IPC: 多进程模型和进程间通讯 50 | Cooke and Session: Cookie 和 Session 51 | Tutorials: 教程 52 | Advanced: 进阶 53 | Cluster Client: 多进程研发模式增强 54 | Framework: 框架开发 55 | Plugin: 插件开发 56 | Progressive: 渐进式开发 57 | Async Function: Async Function 58 | Deployment: 应用部署 59 | # Loader: 60 | Community: 社区 61 | Contributing: 如何贡献 62 | Member Guide: 成员指南 63 | FAQ: 常见问题 64 | Resource: 资源 65 | FetchServer: 负载均衡 66 | Deploy: 部署问题 67 | Mock: 数据模拟 68 | ServerIsolation: 服务隔离 69 | contributing: 贡献文章 70 | debug: Node调试 71 | wechat: 微信授权 72 | fekey: 73 | Intro: Guide 74 | What is Fekey: what is fekey 75 | Fekey Get Start: Quick Start -------------------------------------------------------------------------------- /themes/navy/languages/zh-cn.yml: -------------------------------------------------------------------------------- 1 | menu: 2 | guide: 指南 3 | api: API 4 | tutorials: 教程 5 | user: 使用案例 6 | process: 接入流程 7 | fekey: Fekey 8 | 9 | index: 10 | slogan: "高可用的渲染容器" 11 | feature11: "进程管理" 12 | feature12: "内置的进程管理和负载均衡" 13 | feature21: "自定义" 14 | feature31: "强大的插件系统" 15 | feature32: "插件系统可插拔及可扩展随心所欲" 16 | getstart: "开始使用" 17 | readmore: "查看更多" 18 | 19 | header: 20 | translations: "切换语言" 21 | 22 | page: 23 | contents: 目录 24 | back_to_top: 回到顶部 25 | improve: 改进本文 26 | prev: 上一页 27 | next: 下一页 28 | last_updated: 上次更新:%s 29 | 30 | sidebar: 31 | docs: 32 | Intro: 新手指南 33 | What is NodeUI: NodeUI 是什么 34 | Get Start: 快速入门 35 | Basics: 基础功能 36 | Structure: 目录结构 37 | Environment: 运行环境 38 | Config: 配置 39 | Middleware: 中间件 40 | Router: 路由 41 | Controller: Controller 42 | Service: Service 43 | Schedule: 定时任务 44 | Extend: 框架扩展 45 | Custom init: 启动自定义 46 | Development: 本地开发 47 | Unit Testing: 单元测试 48 | Core: 核心功能 49 | Security: 安全 50 | View: 模板渲染 51 | View Plugin: 模板插件开发规范 52 | # Passport: 53 | HttpClient: HttpClient 54 | Logger: 日志 55 | Error Handling: 异常处理 56 | i18n: 国际化 57 | Cluster and IPC: 多进程模型和进程间通讯 58 | Cooke and Session: Cookie 和 Session 59 | Tutorials: 教程 60 | Advanced: 进阶 61 | Cluster Client: 多进程研发模式增强 62 | Framework: 框架开发 63 | Plugin: 插件开发 64 | Progressive: 渐进式开发 65 | Async Function: Async Function 66 | Deployment: 应用部署 67 | # Loader: 68 | Community: 社区 69 | Contributing: 如何贡献 70 | Member Guide: 成员指南 71 | FAQ: 常见问题 72 | Resource: 资源 73 | 74 | FetchServer: 负载均衡 75 | Deploy: 部署问题 76 | Mock: 数据模拟 77 | ServerIsolation: 服务隔离 78 | contributing: 贡献文章 79 | debug: Node调试 80 | wechat: 微信授权 81 | 82 | fekey: 83 | Intro: 新手指南 84 | What is Fekey: fekey 是什么 85 | Fekey Get Start: 快速开始 86 | -------------------------------------------------------------------------------- /themes/navy/source/js/plugins.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | var elements = document.getElementsByClassName('plugin'); 5 | var $count = document.getElementById('plugin-list-count'); 6 | var $input = document.getElementById('plugin-search-input'); 7 | var elementLen = elements.length; 8 | var index = lunr.Index.load(window.SEARCH_INDEX); 9 | 10 | function updateCount(count){ 11 | $count.innerHTML = count + (count === 1 ? ' item' : ' items'); 12 | } 13 | 14 | function addClass(elem, className){ 15 | var classList = elem.classList; 16 | 17 | if (!classList.contains(className)){ 18 | classList.add(className); 19 | } 20 | } 21 | 22 | function removeClass(elem, className){ 23 | var classList = elem.classList; 24 | 25 | if (classList.contains(className)){ 26 | classList.remove(className); 27 | } 28 | } 29 | 30 | function search(value){ 31 | var result = index.search(value); 32 | var len = result.length; 33 | var selected = {}; 34 | var i = 0; 35 | 36 | for (i = 0; i < len; i++){ 37 | selected[result[i].ref] = true; 38 | } 39 | 40 | for (i = 0; i < elementLen; i++){ 41 | if (selected[i]){ 42 | addClass(elements[i], 'on'); 43 | } else { 44 | removeClass(elements[i], 'on'); 45 | } 46 | } 47 | 48 | updateCount(len); 49 | } 50 | 51 | function displayAll(){ 52 | for (var i = 0; i < elementLen; i++){ 53 | addClass(elements[i], 'on'); 54 | } 55 | 56 | updateCount(elements.length); 57 | } 58 | 59 | function hashchange(){ 60 | var hash = location.hash.substring(1); 61 | $input.value = hash; 62 | 63 | if (hash){ 64 | search(hash); 65 | } else { 66 | displayAll(); 67 | } 68 | } 69 | 70 | $input.addEventListener('input', function(){ 71 | var value = this.value; 72 | 73 | if (!value) return displayAll(); 74 | search(value); 75 | }); 76 | 77 | window.addEventListener('hashchange', hashchange); 78 | hashchange(); 79 | })(); -------------------------------------------------------------------------------- /themes/docs/source/images/feature1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page 1 5 | Created with Sketch Beta. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/header.styl: -------------------------------------------------------------------------------- 1 | header-padding-normal = 10px 2 | header-padding-max = 30px 3 | logo-size = 50px 4 | 5 | #header 6 | position: relative 7 | padding: header-padding-normal 0 8 | @media print 9 | display: none 10 | 11 | #header-inner 12 | display: flex 13 | flex-flow: row nowrap 14 | align-items: center 15 | @media mq-mobile 16 | justify-content: center 17 | 18 | #logo-wrap 19 | flex: 0 logo-size 20 | 21 | #logo 22 | text-decoration: none 23 | color: #fff 24 | float: left 25 | padding: 14.5px 15px 26 | font-size: 19px 27 | line-height: 21px 28 | height: logo-size 29 | display: block 30 | 31 | #main-nav 32 | display: none 33 | flex: 1 auto 34 | padding-left: 20px 35 | @media mq-normal 36 | display: block 37 | 38 | .main-nav-link 39 | color: #fff 40 | text-decoration: none 41 | line-height: logo-size 42 | opacity: 0.7 43 | transition: 0.2s 44 | font-family: font-title 45 | display: inline-block 46 | padding: 0 15px 47 | &:hover 48 | opacity: 1 49 | color: color-link-hover 50 | 51 | #search-input-wrap 52 | display: none 53 | padding-left: 6px 54 | padding-bottom: 8px 55 | border-bottom: 1px solid color-gray 56 | &.on 57 | display: inline-block 58 | 59 | #search-input-icon 60 | color: #fff 61 | padding-right: 0.5em 62 | display: inline-block 63 | opacity: 0.7 64 | 65 | #search-input 66 | background: none 67 | font-size: inherit 68 | font-family: font-title 69 | color: #fff 70 | outline: none 71 | -webkit-appearance: none 72 | 73 | #lang-select-wrap 74 | display: none 75 | position: relative 76 | @media mq-normal 77 | display: block 78 | 79 | #lang-select-label 80 | color: #fff 81 | opacity: 0.7 82 | font-family: font-title 83 | line-height: logo-size 84 | span 85 | padding-left: 8px 86 | i 87 | opacity: 0.7 88 | 89 | #lang-select 90 | opacity: 0 91 | position: absolute 92 | top: 0 93 | left: 0 94 | width: 100% 95 | height: 100% 96 | -webkit-appearance: menulist-button 97 | font-size: inherit 98 | -------------------------------------------------------------------------------- /themes/docs/source/css/vendor/highlight-github.less: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .highlight { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #666; 12 | background: #f8f8f8; 13 | margin: 0; 14 | padding: 0; 15 | background: transparent; 16 | 17 | pre { 18 | margin-bottom: 0; 19 | word-break: normal; 20 | } 21 | 22 | table, tbody, tr, td { 23 | display: block; 24 | } 25 | 26 | table tr { 27 | border: 0; 28 | } 29 | 30 | .code { 31 | padding: 0; 32 | border: none; 33 | } 34 | 35 | .comment, 36 | .quote { 37 | color: #c1c1c1; 38 | font-style: italic; 39 | } 40 | 41 | .keyword, 42 | .selector-tag, 43 | .subst { 44 | color: #333; 45 | font-weight: bold; 46 | } 47 | 48 | .number, 49 | .literal, 50 | .variable, 51 | .template-variable, 52 | .tag .attr { 53 | color: #b34314; 54 | } 55 | 56 | .string, 57 | .doctag { 58 | color: #2d9e2d; 59 | } 60 | 61 | .title, 62 | .section, 63 | .selector-id { 64 | color: #d43737; 65 | font-weight: bold; 66 | } 67 | 68 | .subst { 69 | font-weight: normal; 70 | } 71 | 72 | .type, 73 | .class .title { 74 | color: #5575d4; 75 | font-weight: bold; 76 | } 77 | 78 | .tag, 79 | .name, 80 | .attribute { 81 | color: #929292; 82 | font-weight: normal; 83 | } 84 | 85 | .regexp, 86 | .link { 87 | color: #009926; 88 | } 89 | 90 | .symbol, 91 | .bullet { 92 | color: #990073; 93 | } 94 | 95 | .built_in, 96 | .builtin-name { 97 | color: #21b3e4; 98 | } 99 | 100 | .meta { 101 | color: #999; 102 | font-weight: bold; 103 | } 104 | 105 | .deletion { 106 | background: #fdd; 107 | } 108 | 109 | .addition { 110 | background: #dfd; 111 | } 112 | 113 | .emphasis { 114 | font-style: italic; 115 | } 116 | 117 | .strong { 118 | font-weight: bold; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /themes/docs/source/css/partial/mobile.less: -------------------------------------------------------------------------------- 1 | .mobile-menu { 2 | display: none; 3 | } 4 | 5 | @media screen and (max-width: 1004px) { 6 | .nav { 7 | ul.nav-item { 8 | display: none; 9 | } 10 | header { 11 | width: 90%; 12 | } 13 | .nav-logo{ 14 | padding-top: 2px; 15 | } 16 | .mobile-trigger { 17 | display: inline-block; 18 | top: 21px; 19 | right: 20px; 20 | position: absolute; 21 | z-index: 3; 22 | li { 23 | display: block; 24 | background: #6b6b6b; 25 | width: 22px; 26 | height: 3px; 27 | margin-bottom: 4px; 28 | } 29 | } 30 | } 31 | .banner .banner-logo{ 32 | padding-right: 25%; 33 | margin-top: -100px; 34 | padding-bottom: 100px; 35 | } 36 | .banner .banner-info{ 37 | width: 80%; 38 | margin: 0 auto; 39 | h1{ 40 | font-size: 40px; 41 | } 42 | } 43 | 44 | .index-aside aside { 45 | display: block; 46 | } 47 | 48 | aside { 49 | display: block; 50 | padding: 0 20px; 51 | width: 140px; 52 | right: -200px; 53 | border-left: 1px solid #E6E6E6; 54 | transition: right 1s; 55 | overflow-y: scroll; 56 | 57 | .mobile-menu { 58 | padding-top: 30px; 59 | display: block; 60 | ul { 61 | margin-bottom: 30px; 62 | li a { 63 | color: #000000; 64 | } 65 | } 66 | } 67 | 68 | dl { 69 | padding-top: 0; 70 | } 71 | } 72 | 73 | aside.mobile-show { 74 | right: 0px; 75 | transition: right 1s; 76 | } 77 | 78 | .page-main { 79 | &.post { 80 | aside { 81 | display: block; 82 | z-index: 1000; 83 | 84 | } 85 | } 86 | } 87 | 88 | .page-main article { 89 | float: none; 90 | width: 100%; 91 | width: 88%; 92 | margin: 0 auto; 93 | padding:20px; 94 | } 95 | 96 | .footer { 97 | position: inherit; 98 | width: auto; 99 | padding: 0 20px; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /themes/docs/scripts/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const renderer = require('../lib/renderer'); 5 | 6 | /* global hexo */ 7 | 8 | hexo.extend.renderer.register('md', 'html', renderer, true); 9 | 10 | // 左侧导航 11 | hexo.extend.helper.register('guide_toc', function() { 12 | const type = this.page.canonical_path.split('/')[0]; 13 | const sidebar = this.site.data.sidebar[type]; 14 | var prefix = 'sidebar.' + type + '.'; 15 | // const toc = this.site.data.guide_toc; 16 | const toc = sidebar; 17 | let menu = '
    '; 18 | for (let title in toc) { 19 | const subMenu = toc[title]; 20 | title = getI18nText(this.__, title, prefix); 21 | menu += `
    ${title}
      `; 22 | for (let subTitle in subMenu) { 23 | const curPath = this.page.lang + subMenu[subTitle]; 24 | const url = '/' + curPath; 25 | const itemClass = curPath === this.path ? 'cur' : ''; 26 | subTitle = getI18nText(this.__, subTitle, prefix); 27 | // add current class 注意 basename是可能重复的 28 | menu += `
    • ${subTitle}
    • `; 29 | } 30 | menu += '
    '; 31 | } 32 | 33 | menu += '
    '; 34 | return menu; 35 | }); 36 | 37 | hexo.extend.helper.register('menu_link', function() { 38 | const menus = this.site.data.menu; 39 | let links = ''; 40 | for (const menu in menus) { 41 | let link = menus[menu]; 42 | const content = getI18nText(this.__, menu, 'menu.'); 43 | let curPath = this.page.lang + link; 44 | // 兼容没有 index.html 的情况 45 | if(!~curPath.indexOf('.html')) { 46 | curPath += 'index.html' 47 | } 48 | const itemClass = curPath === this.path ? 'cur' : ''; 49 | if (this.page.lang !== 'en' && !/^http/.test(link)) { 50 | link = '/' + this.page.lang + link; 51 | } 52 | links += `
  • ${content}
  • `; 53 | } 54 | 55 | return links; 56 | }); 57 | 58 | // 返回首页 59 | hexo.extend.helper.register('index_link', function(url) { 60 | if (!url) { 61 | url = '/'; 62 | } 63 | if (this.page.lang !== 'en') { 64 | return `/${this.page.lang}${url}`; 65 | } 66 | return url; 67 | }); 68 | 69 | function getI18nText(gettext, text, prefix) { 70 | const key = prefix + text; 71 | const tmp = gettext(key); 72 | return tmp === key ? text : tmp; 73 | } 74 | -------------------------------------------------------------------------------- /source/en/faq.md: -------------------------------------------------------------------------------- 1 | title: FAQ 2 | --- 3 | 4 | If you have questions that is not contained below, please check [Egg issues](https://github.com/eggjs/egg/issues). 5 | 6 | ## Why my config don't work ? 7 | 8 | Framework [Config](./basics/config.md) settings is powerfull, support different environments and different places(framework, plugins, app). 9 | 10 | When you got some trouble, and want to find out what is the final config using at runtime, you can checkout `run/application_config.json` and `run/agent_config.json`. 11 | 12 | ## Why not choose PM2 as process management tool? 13 | 14 | 1. PM2 itself is too complex to issue problems if any. 15 | 2. Deep optimization could be difficlut to achieve if choosing PM2. 16 | 3. Pattern like one leader process communicating with remote services, along with serveral follower processes delegating request to it ([Cluster](./core/cluster-and-ipc.md)), is a rigid demand for reducing connections and data exchange load, espeically when facing applications in very large scale. egg originates from Ant Financial Group and Alibaba Group, we start with applications in that scale at first, so we take these goals into consideration. All of these goals above could be hard to achieve with PM2. 17 | 18 | Process management is very important. It defines the way we write code, meanwhile relates to deep runtime optimizations. So we think it's better included in framework itself. 19 | 20 | **How to start application with PM2?** 21 | 22 | Although PM2 is not recommanded, you can use it anyway. 23 | 24 | Firstly, put a start file in the root directory of your project: 25 | 26 | ```js 27 | // server.js 28 | const egg = require('egg'); 29 | 30 | const workers = Number(process.argv[2] || require('os').cpus().length); 31 | egg.startCluster({ 32 | workers, 33 | baseDir: __dirname, 34 | }); 35 | ``` 36 | 37 | We can start application with PM2 like this: 38 | 39 | ```bash 40 | pm2 start server.js 41 | ``` 42 | 43 | ## How to resolve csrf error? 44 | 45 | There are two kinds of common csrf errors: 46 | 47 | - `missing csrf token` 48 | - `invalid csrf token` 49 | 50 | By default [egg-security](https://github.com/eggjs/egg-security/) plugin built in Egg requires CSRF validation against all 'unsafe' request such as `POST`, `PUT`, `DELETE` requests. 51 | 52 | The error will disappear in the presence of correct csrf token in request. For more implentation details, see [./core/security.md#csrf]. 53 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/highlight.styl: -------------------------------------------------------------------------------- 1 | // https://github.com/chriskempson/tomorrow-theme 2 | highlight-background = #fff 3 | highlight-current-line = #efefef 4 | highlight-selection = #d6d6d6 5 | highlight-foreground = #4d4d4c 6 | highlight-comment = #8e908c 7 | highlight-red = #c82829 8 | highlight-orange = #f5871f 9 | highlight-yellow = #eab700 10 | highlight-green = #718c00 11 | highlight-aqua = #3e999f 12 | highlight-blue = #4271ae 13 | highlight-purple = #8959a8 14 | 15 | pre, code 16 | font-family: font-mono 17 | color: highlight-foreground 18 | background: #eee 19 | font-size: 0.95em 20 | 21 | code 22 | padding: 0 5px 23 | 24 | pre 25 | padding: 10px 15px 26 | line-height: 22px 27 | code 28 | border: none 29 | display: block 30 | padding: 0 31 | 32 | .highlight 33 | background: #eee 34 | padding: 10px 15px 35 | color: highlight-foreground 36 | overflow: auto 37 | margin: 0 38 | table 39 | margin: 0 !important 40 | border: 0 41 | th, td 42 | padding: 0 43 | figcaption 44 | clearfix() 45 | margin: -5px 0 5px 46 | font-size: 0.9em 47 | color: color-gray 48 | a 49 | float: right 50 | pre 51 | padding: 0 52 | border: none 53 | background: none 54 | .line 55 | height: 22px 56 | 57 | pre 58 | .comment 59 | .title 60 | color: highlight-comment 61 | .variable 62 | .attribute 63 | .tag 64 | .regexp 65 | .ruby .constant 66 | .xml .tag .title 67 | .xml .pi 68 | .xml .doctype 69 | .html .doctype 70 | .css .id 71 | .css .class 72 | .css .pseudo 73 | color: highlight-red 74 | .number 75 | .preprocessor 76 | .built_in 77 | .literal 78 | .params 79 | .constant 80 | color: highlight-orange 81 | .class 82 | .ruby .class .title 83 | .css .rules .attribute 84 | color: highlight-green 85 | .string 86 | .value 87 | .inheritance 88 | .header 89 | .ruby .symbol 90 | .xml .cdata 91 | color: highlight-green 92 | .css .hexcolor 93 | color: highlight-aqua 94 | .function 95 | .python .decorator 96 | .python .title 97 | .ruby .function .title 98 | .ruby .title .keyword 99 | .perl .sub 100 | .javascript .title 101 | .coffeescript .title 102 | color: highlight-blue 103 | .keyword 104 | .javascript .function 105 | color: highlight-purple -------------------------------------------------------------------------------- /themes/docs/source/images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch Beta. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /source/zh-cn/docs/advanced/fetch-server.md: -------------------------------------------------------------------------------- 1 | title: NodeUI与PHP服务通信负载均衡策略 2 | --- 3 | 4 | ### 1. roundrobin 5 | 6 | ``` 7 | RoundRobinBalance.prototype.fetchServer = function (balanceContext) { 8 | var servers = balanceContext.reqIDCServers; 9 | if (servers.length === 1) { 10 | return servers[0]; 11 | } 12 | balanceContext.lastRoundRobinID = balanceContext.lastRoundRobinID || 0; 13 | balanceContext.lastRoundRobinID++; 14 | if (balanceContext.lastRoundRobinID < 0 || balanceContext.lastRoundRobinID >= servers.length) { 15 | balanceContext.lastRoundRobinID = 0; 16 | } 17 | logger.trace( 18 | ['RoundRobinBalance fetchServer RoundRobinID=', balanceContext.lastRoundRobinID, ' ServiceID=', 19 | balanceContext.serviceID 20 | ].join('') 21 | ); 22 | return servers[balanceContext.lastRoundRobinID]; 23 | }; 24 | ``` 25 | 26 | ### 2. random 27 | 28 | 29 | ``` 30 | RandomBalance.prototype.fetchServer = function (balanceContext) { 31 | var servers = balanceContext.reqIDCServers; 32 | if (servers.length === 1) { 33 | return servers[0]; 34 | } 35 | // Math.random takes 250ms on first call 36 | var index = Math.floor(Math.random() * servers.length); 37 | logger.trace('RandomBalance fetchServer index=' + index + ' ServiceID=' + balanceContext.serviceID); 38 | // TODO add server filter 39 | return servers[index]; 40 | }; 41 | 42 | ``` 43 | 44 | ### 3. hashring 45 | 46 | ``` 47 | HashringBalance.prototype.fetchServer = function (balanceContext, conf, prevBackend) { 48 | if (conf.balanceKey === undefined || conf.balanceKey === null) { 49 | throw new Error('balanceKey is needed when using consistent hashing'); 50 | } 51 | var servers = balanceContext.reqIDCServers; 52 | if (servers.length === 1) { 53 | return servers[0]; 54 | } 55 | if (!balanceContext.hashring) { 56 | balanceContext.hashring = this.createHashring(balanceContext.reqIDCServers); 57 | } 58 | var ringIndex = bs(balanceContext.hashring, { 59 | index: null, 60 | value: this.generateHash(conf.balanceKey) 61 | }, function (a, b) { 62 | return a.value - b.value; 63 | }); 64 | if (ringIndex < 0) { 65 | ringIndex = -ringIndex - 1; 66 | } 67 | ringIndex = Math.min(ringIndex, balanceContext.hashring.length - 1); 68 | var index = balanceContext.hashring[ringIndex].index; 69 | logger.trace('RandomBalance fetchServer index=' + index + ' ServiceID=' + balanceContext.serviceID); 70 | return servers[index]; 71 | }; 72 | 73 | ``` 74 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/plugins.styl: -------------------------------------------------------------------------------- 1 | #plugin-list-header 2 | clearfix() 3 | margin: 40px 0 4 | 5 | #plugin-list-title 6 | font-family: font-title 7 | font-size: 36px 8 | font-weight: 300 9 | line-height: 1 10 | float: left 11 | 12 | #plugin-list-count 13 | color: color-gray 14 | padding-top: 1em 15 | text-align: right 16 | @media mq-normal 17 | float: right 18 | line-height: 40px 19 | padding-top: 0 20 | padding-right: 15px 21 | 22 | #plugin-search-input 23 | font-size: 16px 24 | font-family: inherit 25 | -webkit-appearance: none 26 | border: 1px solid color-border 27 | padding: 10px 10px 28 | width: 100% 29 | margin-top: 25px 30 | @media mq-normal 31 | float: right 32 | width: 50% 33 | margin-top: 0 34 | 35 | #plugin-list 36 | margin: 40px -20px 37 | display: flex 38 | flex-flow: column 39 | @media mq-tablet 40 | flex-flow: row wrap 41 | 42 | .plugin 43 | display: none 44 | padding: 20px 45 | @media mq-tablet 46 | flex: 0 0 50% 47 | @media mq-normal 48 | flex: 0 0 (100 / 3)% 49 | &.on 50 | display: block 51 | 52 | .plugin-name 53 | font-family: font-title 54 | font-weight: bold 55 | color: color-link 56 | font-size: 20px 57 | text-decoration: none 58 | line-height: 1 59 | &:hover 60 | color: color-link-hover 61 | 62 | .plugin-desc 63 | line-height: line-height 64 | margin: 1em 0 65 | 66 | .plugin-tag-list 67 | clearfix() 68 | line-height: 1.3 69 | 70 | .plugin-tag 71 | color: color-gray 72 | font-size: 0.9em 73 | text-decoration: none 74 | float: left 75 | margin-right: 10px 76 | &:hover 77 | color: color-link-hover 78 | &:before 79 | content: "#" 80 | 81 | .plugin-screenshot 82 | margin-bottom: 15px 83 | position: relative 84 | padding-top: (10 / 16 * 100)% // 16:10 ratio 85 | height: 0 86 | overflow: hidden 87 | 88 | .plugin-screenshot-img 89 | position: absolute 90 | top: 0 91 | left: 0 92 | width: 100% 93 | height: auto 94 | 95 | .plugin-preview-link 96 | position: absolute 97 | top: 0 98 | left: 0 99 | width: 100% 100 | height: 100% 101 | background: rgba(0, 0, 0, 0.7) 102 | color: #fff 103 | text-align: center 104 | opacity: 0 105 | transition: 0.15s 106 | &:hover 107 | opacity: 1 108 | .fa 109 | opacity: 1 110 | transform: scale(1) 111 | .fa 112 | position: absolute 113 | top: 0 114 | left: 0 115 | bottom: 0 116 | right: 0 117 | margin: auto 118 | font-size: 50px 119 | width: @font-size 120 | height: @font-size 121 | opacity: 0 122 | transform: scale(6) 123 | transition: 0.2s 124 | transition-delay: 0.15s -------------------------------------------------------------------------------- /themes/navy/layout/index.swig: -------------------------------------------------------------------------------- 1 | 12 |
    13 |
    14 |
    15 |
      16 |
    • 17 |
      18 |
      19 | 20 |
      21 |

      超快速度

      22 |

      Node.js 所带来的超快生成速度,让上百个页面在几秒内瞬间完成渲染。

      23 |
      24 |
    • 25 |
    • 26 |
      27 |
      28 | 29 |
      30 |

      支持 Markdown

      31 |

      Hexo 支持 GitHub Flavored Markdown 的所有功能,甚至可以整合 Octopress 的大多数插件。

      32 |
      33 |
    • 34 |
    • 35 |
      36 |
      37 | 38 |
      39 |

      一键部署

      40 |

      只需一条指令即可部署到 GitHub Pages, Heroku 或其他网站。

      41 |
      42 |
    • 43 |
    • 44 |
      45 |
      46 | 47 |
      48 |

      丰富的插件

      49 |

      Hexo 拥有强大的插件系统,安装插件可以让 Hexo 支持 Jade, CoffeeScript。

      50 |
      51 |
    • 52 |
    53 |
      54 |
    • npm install fekey -g
    • 55 |
    • fekey init
    • 56 |
    • fekey release
    • 57 |
    • fekey server
    • 58 |
    59 | 62 |
    63 |
    64 |
    -------------------------------------------------------------------------------- /source/zh-cn/docs/advanced/server-isoloton.md: -------------------------------------------------------------------------------- 1 | title: 主要工作 2 | --- 3 | 4 | 通过PM2拆分服务,确保不同服务相互不受影响。 5 | 6 | ### 1. 改造现有`pm2.json`,支持多app启动 7 | 8 | 根据当前公有云Node集群现状(机器均为24核),拆分为两个独立服务: 9 | 10 | - `nuomi`: 承载糯米组件流量,端口为`8197`,实例数为14 11 | - `h5`: 承载所有h5模块渲染流量,端口为`8198`,实例数为10 12 | 13 | ``` 14 | { 15 | "apps": [{ 16 | "exec_interpreter": "node", 17 | "name": "nuomi", 18 | "exec_mode": "cluster_mode", 19 | "instances": "14", 20 | "max_memory_restart": "500M", 21 | "merge_logs": false, 22 | "script": "app.js", 23 | "ignoreWatch": ["pm2", "log", "node_modules"], 24 | "env": { 25 | "NODE_ENV": "production", 26 | "PM2_GRACEFUL_TIMEOUT": 1000, 27 | "PORT": 8197, 28 | "DEBUG": true 29 | }, 30 | "env_dev": { 31 | "NODE_ENV": "development", 32 | "DEBUG": true 33 | }, 34 | "env_test": { 35 | "NODE_ENV": "qa" 36 | } 37 | }, { 38 | "exec_interpreter": "node", 39 | "name": "h5", 40 | "exec_mode": "cluster_mode", 41 | "instances": "10", 42 | "max_memory_restart": "500M", 43 | "merge_logs": false, 44 | "script": "app.js", 45 | "ignoreWatch": ["pm2", "log", "node_modules"], 46 | "env": { 47 | "NODE_ENV": "production", 48 | "PM2_GRACEFUL_TIMEOUT": 1000, 49 | "PORT": 8198, 50 | "DEBUG": true 51 | }, 52 | "env_dev": { 53 | "NODE_ENV": "development", 54 | "DEBUG": true 55 | }, 56 | "env_test": { 57 | "NODE_ENV": "qa" 58 | } 59 | }] 60 | } 61 | 62 | ``` 63 | 64 | ### 2. 改造启动脚本,支持业务APP独立重启 65 | 66 | nuomi_restart.sh 67 | h5_restart.sh 68 | 69 | 命令改造: 70 | 71 | bin/control start // 开启所有服务 72 | bin/control stop appname // 关闭某个服务(h5、nuomi) 73 | bin/control delete appname // 删除某个服务(h5、nuomi) 74 | bin/control restart appname // 重启某个服务 75 | bin/control reload appname // 0宕机重启,后续上线重启采用reload方案 76 | 77 | ![reload](http://younth.coding.me/static/nodeui/reload.jpeg) 78 | 79 | ## 上线步骤 80 | 81 | ### 1. 上线NodeUI服务 82 | 83 | - 上线前先确定线上的服务进程名称 84 | 85 | - 涉及底层上线,上线前需要先stop/delete掉老的进程,为确保服务稳定,采用先stop,然后上线新的隔离方案,回归正常后,delete老的服务进程。 86 | 87 | - 需要review方案,或者直接OP操作删除老的进程。 88 | - 增加上线模块 89 | - 绑定上线重启脚本 90 | 91 | 92 | 93 | ### 2. 上线ng rewrite 端口 94 | 95 | - 配置新的vip服务 96 | - 修改rewrite 97 | 98 | ``` 99 | /home/work/odp_cater/webserver/conf/vhost/ 100 | ``` 101 | 102 | ## 重点关注 103 | 104 | - 组件业务 105 | - h5业务 106 | - 日志(pm2+业务,关注日志是否会错乱) 107 | - 服务稳定(Node进程状态) 108 | 109 | ## 回滚方案 110 | 111 | 由于目前公有云回滚可能有坑,回滚过程进程应该不会被杀掉,可能有残留进程,需要杀掉。所以最佳回归方式是**覆盖上线**。涉及的模块: 112 | 113 | - fly 114 | - runtime 115 | -------------------------------------------------------------------------------- /themes/navy/layout/partial/head.swig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% if page.title %}{{ page.title }} | {% endif %}{{ config.title }} 4 | 5 | 6 | 7 | 8 | 9 | {% if page.layout == 'page' or page.layout == 'index' %} 10 | {% for lang in site.data.languages %} 11 | 12 | {% endfor %} 13 | {% endif %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {{ css('css/navy') }} 33 | 34 | 35 | 36 | 37 | 38 | {{ feed_tag('atom.xml') }} 39 | 40 | {{ open_graph({ 41 | fb_admins: config.fb_admins, 42 | twitter_site: config.twitter 43 | }) }} 44 | 45 | {{ partial('google_analytics') }} 46 | 47 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/index.styl: -------------------------------------------------------------------------------- 1 | #banner 2 | color: rgba(255, 255, 255, 0.8) 3 | text-align: center 4 | 5 | #banner-title 6 | padding-top: 20px 7 | font-size: 40px 8 | line-height: 1.15 9 | font-weight: 300 10 | font-family: font-title 11 | @media mq-normal 12 | padding-top: 100px 13 | font-size: 50px 14 | 15 | #banner-start 16 | text-align: center 17 | padding: 40px 0 18 | @media mq-normal 19 | padding: 60px 0 20 | font-size: 18px 21 | 22 | #banner-start-command 23 | background: lighten(color-navy, 10%) 24 | font-family: font-mono 25 | display: inline-block 26 | padding: 15px 20px 27 | &:before 28 | content: "$" 29 | opacity: 0.5 30 | padding-right: 10px 31 | 32 | #banner-start-link 33 | color: #fff 34 | background: color-link 35 | display: inline-block 36 | padding: 15px 37 | text-decoration: none 38 | transition: 0.2s 39 | &:hover 40 | background: color-link-hover 41 | 42 | #banner-share 43 | display: none 44 | padding-bottom: 60px 45 | @media mq-normal 46 | display: block 47 | 48 | #intro-feature-list 49 | padding-top: 20px 50 | display: flex 51 | flex-flow: column 52 | @media mq-normal 53 | flex-flow: row wrap 54 | 55 | .intro-feature-wrap 56 | padding-top: 20px 57 | @media mq-normal 58 | flex: 0 0 50% 59 | padding-top: 50px 60 | 61 | .intro-feature 62 | position: relative 63 | text-align: center 64 | @media mq-normal 65 | text-align: left 66 | padding-left: 70px 67 | 68 | .intro-feature-icon 69 | color: color-link 70 | font-size: 36px 71 | padding-bottom: 26px 72 | text-align: center 73 | @media mq-normal 74 | position: absolute 75 | top: 0 76 | left: 20px 77 | font-size: 24px 78 | width: @font-size 79 | 80 | .intro-feature-title 81 | color: color-link 82 | font-family: font-title 83 | font-size: 24px 84 | 85 | .intro-feature-desc 86 | margin: line-height 0 87 | line-height: line-height 88 | 89 | #intro-cmd-wrap 90 | max-width: 700px 91 | background: #eee 92 | padding: 15px 0 93 | margin: 25px gutter-width * -1 0 94 | @media mq-normal 95 | margin: 50px auto 0 96 | 97 | .intro-cmd-item 98 | font-size: 16px 99 | font-family: font-mono 100 | line-height: 2 101 | padding: 0 30px 102 | &:before 103 | content: "$" 104 | color: color-link 105 | padding-right: 15px 106 | 107 | #intro-get-started-wrap 108 | text-align: center 109 | 110 | #intro-get-started-link 111 | font-size: 18px 112 | font-family: font-title 113 | display: inline-block 114 | color: color-link 115 | text-decoration: none 116 | margin: 40px 0 117 | border: 3px solid 118 | border-color: lighten(color-link, 20%) 119 | padding: 12px 24px 120 | position: relative 121 | transition: 0.2s 122 | &:hover 123 | background: @border-color 124 | color: #fff -------------------------------------------------------------------------------- /themes/docs/source/css/partial/nav.less: -------------------------------------------------------------------------------- 1 | .nav { 2 | background: #f9f9f9; 3 | height: 56px; 4 | border-bottom: 1px solid rgba(230, 230, 230, 0.99); 5 | z-index:2; 6 | width: 100%; 7 | position:fixed; 8 | top:0; 9 | header { 10 | /*shift way to clear float because of the overflow hidden will hide the algolia*/ 11 | &:after { 12 | display: block; 13 | clear: both; 14 | content: '\20'; 15 | height: 0; 16 | } 17 | padding: 12px 0 13px; 18 | max-width: @max_width; 19 | margin: 0 auto; 20 | .ds-dropdown-menu { 21 | max-height: 450px; 22 | overflow: auto; 23 | /* hidden the small triangle prompt*/ 24 | &:before { 25 | background: none; 26 | } 27 | } 28 | 29 | .search-query { 30 | height: 32px; 31 | line-height: 32px; 32 | box-sizing: border-box; 33 | border: 1px solid #e6e6e6; 34 | border-radius: 15px; 35 | outline: none; 36 | padding: 0 15px 0 32px; 37 | background: #fff url(../images/search.png) 8px 5px no-repeat; 38 | background-size: 20px; 39 | } 40 | } 41 | 42 | ul.nav-item { 43 | height: 32px; 44 | float: left; 45 | line-height: 32px; 46 | padding-left: 10px; 47 | li { 48 | display: inline-block; 49 | margin-left: 40px; 50 | } 51 | 52 | a { 53 | display: inline-block; 54 | color: #3C3C3C; 55 | letter-spacing:0.5px; 56 | font-weight: 500; 57 | &:hover{ 58 | color:#22ab28; 59 | transition: 0.6s all; 60 | } 61 | &.cur { 62 | color: #22ab28; 63 | } 64 | } 65 | } 66 | 67 | iframe { 68 | vertical-align: -5px; 69 | } 70 | 71 | .mobile-trigger { 72 | display: none; 73 | } 74 | } 75 | 76 | .translations { 77 | display: inline-block; 78 | ul.nav-item{ 79 | height: 70px; 80 | padding-left: 0px; 81 | } 82 | } 83 | .translations:hover .dropdown-content{ 84 | display: block; 85 | } 86 | .arrow{ 87 | display: inline-block; 88 | vertical-align: middle; 89 | margin-top: -1px; 90 | margin-left: 6px; 91 | margin-right: -14px; 92 | width: 0; 93 | height: 0; 94 | border-left:4px solid transparent; 95 | border-right: 4px solid transparent; 96 | border-radius: 1px; 97 | border-top: 5px solid #3C3C3C; 98 | } 99 | .nav-link { 100 | cursor:pointer; 101 | 102 | } 103 | .dropdown-content { 104 | display: none; 105 | position: absolute; 106 | background-color: #fff; 107 | padding: 10px 0; 108 | border: 1px solid #E6E6E6; 109 | border-bottom-color: #E6E6E6; 110 | text-align: left; 111 | border-radius: 4px; 112 | li { 113 | display: inherit; 114 | margin: 0px 20px; 115 | } 116 | } 117 | 118 | .nav-logo { 119 | margin: 0; 120 | display: inline-block; 121 | float: left; 122 | padding-top: 2px; 123 | color: #e24444; 124 | font-size: 30px; 125 | img { 126 | width: 44px; 127 | margin-top: -10px; 128 | } 129 | span { 130 | transform: translate(4px, -13px); 131 | display: inline-block; 132 | color: #121512; 133 | font-size: 28px; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /themes/docs/source/images/feature2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page 1 5 | Created with Sketch Beta. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /themes/navy/source/css/_partial/mobile_nav.styl: -------------------------------------------------------------------------------- 1 | toggle-width = 25px 2 | toggle-height = toggle-width * 0.8 3 | toggle-line = 2px 4 | transition-duration = 0.4s 5 | lang-select-height = 40px 6 | 7 | #mobile-nav 8 | position: fixed 9 | top: 0 10 | width: mobile-nav-width 11 | left: @width * -1 12 | height: 100% 13 | background: color-navy 14 | transition: transition-duration 15 | font-family: font-title 16 | .mobile-nav-on & 17 | transform: translateX(100%) 18 | 19 | #mobile-nav-inner 20 | overflow-y: auto 21 | padding: 10px 0 22 | position: absolute 23 | top: 0 24 | bottom: lang-select-height 25 | left: 0 26 | right: 0 27 | -webkit-overflow-scrolling: touch 28 | 29 | #mobile-nav-toggle 30 | position: absolute 31 | top: 0 32 | bottom: 0 33 | left: gutter-width 34 | width: toggle-width 35 | height: toggle-height 36 | margin: auto 37 | opacity: 0.5 38 | cursor: pointer 39 | transition: 0.2s 40 | &:active, .mobile-nav-on & 41 | opacity: 1 42 | @media mq-normal 43 | display: none 44 | 45 | .mobile-nav-toggle-bar 46 | background: #fff 47 | position: absolute 48 | left: 0 49 | width: 100% 50 | height: toggle-line 51 | transition: transition-duration 52 | transform-origin: 0 53 | border-radius: toggle-line 54 | &:first-child 55 | top: 0 56 | .mobile-nav-on & 57 | transform: rotate(45deg) 58 | &:nth-child(2) 59 | top: (toggle-height - toggle-line) * 0.5 60 | .mobile-nav-on & 61 | opacity: 0 62 | &:last-child 63 | top: toggle-height - toggle-line 64 | .mobile-nav-on & 65 | transform: rotate(-45deg) 66 | 67 | .mobile-nav-link 68 | color: #fff 69 | text-decoration: none 70 | display: block 71 | padding: 10px 15px 72 | line-height: 1 73 | white-space: nowrap 74 | overflow: hidden 75 | text-overflow: ellipsis 76 | 77 | .mobile-nav-title 78 | color: color-link 79 | font-weight: bold 80 | padding: 10px 15px 81 | line-height: 1 82 | display: block 83 | border-top: 1px solid #444 84 | margin-top: 10px 85 | white-space: nowrap 86 | overflow: hidden 87 | text-overflow: ellipsis 88 | 89 | #mobile-lang-select-wrap 90 | position: absolute 91 | bottom: 0 92 | left: 0 93 | width: 100% 94 | background: color-navy 95 | border-top: 1px solid #444 96 | 97 | #mobile-lang-select-label 98 | line-height: lang-select-height 99 | color: #fff 100 | padding: 10px 15px 101 | i 102 | opacity: 0.7 103 | span 104 | padding-left: 8px 105 | 106 | #mobile-lang-select 107 | -webkit-appearance: menulist-button 108 | opacity: 0 109 | position: absolute 110 | top: 0 111 | left: 0 112 | width: 100% 113 | height: 100% 114 | 115 | #container 116 | transition: transition-duration 117 | height: 100% 118 | // overflow: auto 119 | -webkit-overflow-scrolling: touch 120 | .mobile-nav-on & 121 | transform: translateX(mobile-nav-width) 122 | overflow: hidden 123 | 124 | #mobile-nav-dimmer 125 | position: absolute 126 | top: 0 127 | left: 100% 128 | width: 100% 129 | height: 100% 130 | background: #000 131 | opacity: 0 132 | transition: opacity transition-duration, transform 0s transition-duration 133 | .mobile-nav-on & 134 | opacity: 0.7 135 | transform: translateX(-100%) 136 | transition: opacity transition-duration 137 | -------------------------------------------------------------------------------- /source/zh-cn/docs/basics/mock.md: -------------------------------------------------------------------------------- 1 | title: NodeUI数据模拟中心 2 | --- 3 | 4 | 数据mock主要分为前端接口的mock(client request)及向后请求的数据mock(server request)。 5 | 6 | 其中,前端接口mock表现为 ajax请求。向后请求Mock主要是指nodeui向后请求php接口的mock,这种数据一般用来渲染到模板或者直接接口输出。 7 | 8 | 所有的mock均支持热重启,即修改代码不需要重启nodeui,立即生效。 9 | 10 | ### 目录规范 11 | 12 | ``` 13 | mock 14 | ├─ server.conf // 配置中心 15 | ├─ common // 公共接口目录 16 | │ ├─ dynamic.js // 动态数据 17 | │ ├─ sample.json // 静态json数据 18 | ├─ ral // nodeui向php请求接口模拟 19 | │ ├─ hongbao-getmobilebyopenid.js // 微信授权根据openid获取用户信息接口 20 | │ ├─ hongbao-updatemobilebyopenid.js // 更新用户信息接口 21 | │ ├─ huodong-2016usergrowstoryindex.js // 业务php接口模拟 22 | ├─ dumall // 业务接口 23 | │ ├─ center.js // 小度商城个人中心 24 | │ ├─ del.json // 删除卡片接口 25 | ... 26 | ``` 27 | 28 | ### 前端接口的使用 29 | 30 | 前端接口的mock主要在`server.conf`里面进行配置 31 | 32 | #### server.conf 配置语法 33 | 34 | 指令名称 正则规则 目标文件 35 | 36 | - `指令名称` 支持 rewrite 、 redirect 和 proxy。 37 | - `正则规则` 用来命中需要作假的请求路径 38 | - `目标文件` 设置转发的目标地址,需要配置一个可请求的 url 地址。 39 | 40 | #### mock 静态假数据 41 | 42 | 43 | ``` 44 | rewrite ^\/api\/user$ /mock/sample.json 45 | 46 | // sample.json内容 47 | 48 | { 49 | "error": 0, 50 | "message": "ok", 51 | "data": { 52 | "username": "younth", 53 | "uid": 1, 54 | "age": 25, 55 | "company": "waimai" 56 | } 57 | } 58 | ``` 59 | 60 | #### mock 动态假数据 61 | 62 | > node 服务器可以通过 js 的方式提供动态假数据。,动态数据本质是 express 的 route. 63 | 64 | `rewrite ^\/api\/dynamic\/time$ /mock/dynamic.js` 65 | 66 | ```js 67 | // dynamic.js内容 68 | module.exports = function(req, res, next) { 69 | 70 | res.write('Hello world '); 71 | 72 | // set custom header. 73 | // res.setHeader('xxxx', 'xxx'); 74 | 75 | res.end('The time is ' + Date.now()); 76 | }; 77 | 78 | // 更复杂的,可以直接引用其他模块,发送请求 79 | 80 | 81 | var http = require('http'); 82 | var url = require('url'); 83 | var util = require('util'); 84 | var querystring = require('querystring'); 85 | 86 | // 通过nodejs来抓取线上的结果。这样就完成了动态获取线上数据的功能 87 | 88 | module.exports = function(request, response, next) { 89 | 90 | var method = request.method; 91 | ... 92 | 93 | }; 94 | 95 | ``` 96 | 97 | #### proxy 到其他服务的 api 地址 98 | 99 | ```bash 100 | // 支持正则分组 101 | proxy ^\/wmall\/privilege\/(.*)$ http://10.19.161.92:8059/wmall/privilege/$1 102 | ``` 103 | 104 | ### ral 请求的mock 105 | 106 | 主要是Node向下游服务(PHP)请求的数据mock,基于ral请求的数据模拟。 107 | 108 | #### 如何使用 109 | 110 | ##### 1. 根据path 建立mock文件 111 | 112 | 文件命名规则是 *请求的path用-符号连接* 113 | 114 | /huodong/gamebase -> huodong-gamebase.js 115 | 116 | path与文件名的映射关系必须按照上面的要求,否则无法mock。 117 | 118 | ##### 2. 开启mock 119 | 120 | 比如我们有这样的一个请求: 121 | 122 | ```js 123 | getData: function(req, tools, params) { 124 | var options = { 125 | data: params || {}, 126 | path: '/huodong/gamebase', 127 | reqType: 'promise' 128 | }; 129 | return tools.commonBusiness.pierce(req, 'SHOPUI', options); 130 | } 131 | ``` 132 | mock文件夹下面建立一个 `huodong-gamebase.js`,在请求的参数里面增加 `enableMock: true`开启mock 133 | 134 | ```js 135 | getData: function(req, tools, params) { 136 | var options = { 137 | data: params || {}, 138 | path: '/huodong/gamebase', 139 | reqType: 'promise', 140 | enableMock: true,//开启Mock 141 | }; 142 | return tools.commonBusiness.pierce(req, 'SHOPUI', options); 143 | } 144 | ``` 145 | 这样就完成了nodeui向php请求的数据mock 146 | 147 | ## 测试链接 148 | 149 | - ral请求mock: http://127.0.0.1:8197/fly/h5/demo 150 | - 普通请求mock(rewrite): http://127.0.0.1:8197/api/user 151 | - 动态数据mock(rewrite): http://127.0.0.1:8197/api/dynamic/time 152 | - api proxy mock: http://127.0.0.1:8197/wmall/privilege/center 153 | - 重定向(redirect): http://127.0.0.1:8197/api/redirect 154 | -------------------------------------------------------------------------------- /themes/docs/source/css/page/index.less: -------------------------------------------------------------------------------- 1 | .btn { 2 | display: inline-block; 3 | height: 38px; 4 | width: 120px; 5 | border: 1px solid #fff; 6 | border-radius: 19px; 7 | color: #fff; 8 | line-height: 38px; 9 | letter-spacing: 0.5px; 10 | text-align: center; 11 | font-weight: normal; 12 | margin-right: 10px; 13 | } 14 | 15 | .btn-primary { 16 | background: #22ab28; 17 | border-color: #209425; 18 | &:hover{ 19 | color: #fff; 20 | background: #42bd48; 21 | border-color: #0e5f12; 22 | transition: all 0.3s; 23 | } 24 | } 25 | .btn-secondary{ 26 | border: 1px solid #22ab28; 27 | border-radius: 100px; 28 | color: #22ab28; 29 | &:hover{ 30 | background: #22ab28; 31 | color: #fff; 32 | transition: all 0.6s; 33 | } 34 | } 35 | .index { 36 | text-align: center; 37 | } 38 | 39 | .index-bg-dark { 40 | background: @bg_light; 41 | color: #dbdde6; 42 | } 43 | 44 | .index-bg-light { 45 | background: @bg_light; 46 | } 47 | 48 | .block { 49 | padding: 100px 0; 50 | } 51 | 52 | .banner { 53 | max-width: @max_width; 54 | margin:100px auto; 55 | h1{ 56 | font-size: 46px; 57 | font-weight: 200; 58 | letter-spacing: 1.5px; 59 | margin-bottom: 10px; 60 | } 61 | .banner-info { 62 | width: 60%; 63 | h1 { 64 | text-align: left; 65 | } 66 | p{ 67 | text-align: left; 68 | } 69 | } 70 | .banner-logo { 71 | float: right; 72 | padding-right: 13%; 73 | margin-top: -60px; 74 | img{ 75 | width: 120%; 76 | } 77 | } 78 | 79 | .banner-button { 80 | padding-top: 50px; 81 | } 82 | } 83 | 84 | .version { 85 | background: #F6F8F8; 86 | height: 60px; 87 | line-height: 60px; 88 | box-shadow: 0px 1px 0px 0px rgba(225,225,225,0.50); 89 | span { 90 | padding: 0 30px; 91 | color: #71747B; 92 | } 93 | strong { 94 | color: #131926; 95 | font-weight: bold; 96 | } 97 | } 98 | 99 | .info { 100 | h3 { 101 | font-weight: 500; 102 | color: #333333; 103 | font-size: 24px; 104 | margin-bottom: 20px; 105 | } 106 | ul { 107 | padding-top: 60px; 108 | } 109 | li { 110 | vertical-align: top; 111 | display: inline-block; 112 | width: 270px; 113 | padding: 0 20px; 114 | margin-bottom: 70px; 115 | font-size: 16px; 116 | } 117 | .info-img { 118 | height: 100px; 119 | } 120 | } 121 | 122 | 123 | .guide-code { 124 | font-size: 20px; 125 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 126 | font-weight: 200; 127 | color: #FFFFFF; 128 | text-align: left; 129 | padding: 40px 0; 130 | 131 | ul { 132 | background: #1F2532; 133 | max-width: 650px; 134 | margin: 0 auto; 135 | padding: 40px; 136 | } 137 | 138 | li { 139 | list-style: none; 140 | line-height: 60px; 141 | } 142 | 143 | strong { 144 | color: #d4d4d4; 145 | margin-right: 30px; 146 | -webkit-touch-callout: none; 147 | -webkit-user-select: none; 148 | -khtml-user-select: none; 149 | -moz-user-select: none; 150 | -ms-user-select: none; 151 | user-select: none; 152 | } 153 | } 154 | 155 | .animated { 156 | -webkit-animation-duration: 1s; 157 | animation-duration: 1s; 158 | -webkit-animation-fill-mode: both; 159 | animation-fill-mode: both; 160 | } 161 | 162 | .fadeInUp { 163 | -webkit-animation-name: fadeInUp; 164 | animation-name: fadeInUp; 165 | } 166 | 167 | @-webkit-keyframes fadeInUp { 168 | from { 169 | opacity: 0; 170 | -webkit-transform: translate3d(0, 50px, 0); 171 | transform: translate3d(0, 50px, 0); 172 | } 173 | 174 | to { 175 | opacity: 1; 176 | -webkit-transform: none; 177 | transform: none; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /themes/navy/source/js/scrollingelement.js: -------------------------------------------------------------------------------- 1 | /*! https://mths.be/scrollingelement v1.5.2 by @diegoperini & @mathias | MIT license */ 2 | if (!('scrollingElement' in document)) (function() { 3 | 4 | function computeStyle(element) { 5 | if (window.getComputedStyle) { 6 | // Support Firefox < 4 which throws on a single parameter. 7 | return getComputedStyle(element, null); 8 | } 9 | // Support Internet Explorer < 9. 10 | return element.currentStyle; 11 | } 12 | 13 | function isBodyElement(element) { 14 | // The `instanceof` check gives the correct result for e.g. `body` in a 15 | // non-HTML namespace. 16 | if (window.HTMLBodyElement) { 17 | return element instanceof HTMLBodyElement; 18 | } 19 | // Fall back to a `tagName` check for old browsers. 20 | return /body/i.test(element.tagName); 21 | } 22 | 23 | function getNextBodyElement(frameset) { 24 | // We use this function to be correct per spec in case `document.body` is 25 | // a `frameset` but there exists a later `body`. Since `document.body` is 26 | // a `frameset`, we know the root is an `html`, and there was no `body` 27 | // before the `frameset`, so we just need to look at siblings after the 28 | // `frameset`. 29 | var current = frameset; 30 | while (current = current.nextSibling) { 31 | if (current.nodeType == 1 && isBodyElement(current)) { 32 | return current; 33 | } 34 | } 35 | // No `body` found. 36 | return null; 37 | } 38 | 39 | // Note: standards mode / quirks mode can be toggled at runtime via 40 | // `document.write`. 41 | var isCompliantCached; 42 | var isCompliant = function() { 43 | var isStandardsMode = /^CSS1/.test(document.compatMode); 44 | if (!isStandardsMode) { 45 | // In quirks mode, the result is equivalent to the non-compliant 46 | // standards mode behavior. 47 | return false; 48 | } 49 | if (isCompliantCached === void 0) { 50 | // When called for the first time, check whether the browser is 51 | // standard-compliant, and cache the result. 52 | var iframe = document.createElement('iframe'); 53 | iframe.style.height = '1px'; 54 | (document.body || document.documentElement || document).appendChild(iframe); 55 | var doc = iframe.contentWindow.document; 56 | doc.write('
    x
    '); 57 | doc.close(); 58 | isCompliantCached = doc.documentElement.scrollHeight > doc.body.scrollHeight; 59 | iframe.parentNode.removeChild(iframe); 60 | } 61 | return isCompliantCached; 62 | }; 63 | 64 | function isRendered(style) { 65 | return style.display != 'none' && !(style.visibility == 'collapse' && 66 | /^table-(.+-group|row|column)$/.test(style.display)); 67 | } 68 | 69 | function isScrollable(body) { 70 | // A `body` element is scrollable if `body` and `html` both have 71 | // non-`visible` overflow and are both being rendered. 72 | var bodyStyle = computeStyle(body); 73 | var htmlStyle = computeStyle(document.documentElement); 74 | return bodyStyle.overflow != 'visible' && htmlStyle.overflow != 'visible' && 75 | isRendered(bodyStyle) && isRendered(htmlStyle); 76 | } 77 | 78 | var scrollingElement = function() { 79 | if (isCompliant()) { 80 | return document.documentElement; 81 | } 82 | var body = document.body; 83 | // Note: `document.body` could be a `frameset` element, or `null`. 84 | // `tagName` is uppercase in HTML, but lowercase in XML. 85 | var isFrameset = body && !/body/i.test(body.tagName); 86 | body = isFrameset ? getNextBodyElement(body) : body; 87 | // If `body` is itself scrollable, it is not the `scrollingElement`. 88 | return body && isScrollable(body) ? null : body; 89 | }; 90 | 91 | if (Object.defineProperty) { 92 | // Support modern browsers that lack a native implementation. 93 | Object.defineProperty(document, 'scrollingElement', { 94 | 'get': scrollingElement 95 | }); 96 | } else if (document.__defineGetter__) { 97 | // Support Firefox ≤ 3.6.9, Safari ≤ 4.1.3. 98 | document.__defineGetter__('scrollingElement', scrollingElement); 99 | } else { 100 | // IE ≤ 4 lacks `attachEvent`, so it only gets this one assignment. IE ≤ 7 101 | // gets it too, but the value is updated later (see `propertychange`). 102 | document.scrollingElement = scrollingElement(); 103 | document.attachEvent && document.attachEvent('onpropertychange', function() { 104 | // This is for IE ≤ 7 only. 105 | // A `propertychange` event fires when `` is parsed because 106 | // `document.activeElement` then changes. 107 | if (window.event.propertyName == 'activeElement') { 108 | document.scrollingElement = scrollingElement(); 109 | } 110 | }); 111 | } 112 | }()); 113 | -------------------------------------------------------------------------------- /source/zh-cn/docs/core/view.md: -------------------------------------------------------------------------------- 1 | title: View 模板渲染 2 | --- 3 | 4 | 绝大多数情况,我们都需要读取数据后渲染模板,然后呈现给用户。故我们需要引入对应的模板引擎。 5 | 6 | 我们通过扩展 swig 后端模板引擎,来添加对资源的加载能力。 7 | 8 | ### 基础结构 9 | 10 | 一个基础的后端模板应该类似 11 | 12 | ```html 13 | 14 | {% html framework="home:static/js/mod.js" %} 15 | {% head %} 16 | Hello World 17 | {% endhead %} 18 | {% body %} 19 | {% endbody %} 20 | {% endhtml %} 21 | ``` 22 | 可以将这种基础结构设置为母版页 `layout.tpl` 这样就不需要重复的编写 `html` `head` `body` 标签。 23 | 24 | 其中 `html` 标签的 `framework` 属性是一个特殊属性,用于指定模块化加载类库 `mod.js` 所在的路径。 25 | 26 | ### 引用非模块化资源 27 | 28 | 如果希望引入非模块化资源,比如一些第三方库类似 `jquery` , `zepto` 等等,可以直接通过 `require` 标签进行引用,也可以直接编写 `` HTML标签进行引用。 29 | 30 | ```html 31 | 32 | {% html framework="home:static/js/mod.js" %} 33 | {% head %} 34 | Hello World 35 | {% require "home:static/lib/jquery.js" %} 36 | 37 | {% endhead %} 38 | {% body %} 39 | {% endbody %} 40 | {% endhtml %} 41 | ``` 42 | 43 | 两种引用方式都可以生效,但是更加推荐使用 `require` 标签,因此这种依赖声明模式是运行时声明的,你可以通过 `if` `endif`标签来实现后端动态化的资源加载。此外使用 `require` 加载的资源,可以被 fis 的静态资源管理层统一管理,而 `