├── .github
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── assets-with-roadhog
├── .webpackrc
├── README.md
├── app
│ ├── assets
│ │ ├── .eslintrc
│ │ ├── assets
│ │ │ └── yay.jpg
│ │ ├── components
│ │ │ ├── MainLayout
│ │ │ │ ├── Header.jsx
│ │ │ │ ├── MainLayout.css
│ │ │ │ └── MainLayout.jsx
│ │ │ └── Users
│ │ │ │ ├── UserModal.jsx
│ │ │ │ ├── Users.css
│ │ │ │ └── Users.jsx
│ │ ├── constants.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── models
│ │ │ └── users.js
│ │ ├── router.jsx
│ │ ├── routes
│ │ │ ├── IndexPage.css
│ │ │ ├── IndexPage.jsx
│ │ │ ├── Users.css
│ │ │ └── Users.jsx
│ │ ├── services
│ │ │ └── users.js
│ │ └── utils
│ │ │ └── request.js
│ ├── controller
│ │ └── home.js
│ └── router.js
├── config
│ ├── config.default.js
│ ├── config.prod.js
│ └── plugin.js
├── package.json
└── test
│ └── app
│ └── controller
│ └── home.test.js
├── assets-with-umi
├── .autod.conf.js
├── .env
├── README.md
├── app
│ ├── controller
│ │ └── home.js
│ ├── router.js
│ ├── view
│ │ └── index.html
│ └── web
│ │ ├── .eslintrc
│ │ ├── config
│ │ ├── config.js
│ │ ├── config.local.js
│ │ └── config.prod.js
│ │ ├── layouts
│ │ ├── index.jsx
│ │ └── index.module.less
│ │ └── pages
│ │ ├── discover
│ │ ├── index.jsx
│ │ └── index.module.less
│ │ ├── home
│ │ ├── index.jsx
│ │ └── index.module.less
│ │ ├── index.js
│ │ ├── order
│ │ ├── index.jsx
│ │ └── index.module.less
│ │ ├── profile
│ │ ├── index.jsx
│ │ └── index.module.less
│ │ └── shop
│ │ ├── index.jsx
│ │ └── index.module.less
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── test
│ └── app
│ └── controller
│ └── home.test.js
├── bin
├── base.js
├── list.js
└── test.js
├── bodyParser
├── REAME.md
├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── home.test.js
├── cnode-api-async
└── README.md
├── cnode-api
├── README.md
├── README.zh-CN.md
├── app
│ ├── controller
│ │ └── topics.js
│ ├── middleware
│ │ └── error_handler.js
│ ├── router.js
│ └── service
│ │ └── topics.js
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── test
│ └── app
│ ├── controller
│ └── topics.test.js
│ └── service
│ └── topics.test.js
├── cookie-session
├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── index.test.js
├── cookie
├── app
│ ├── controller
│ │ └── cookie.js
│ └── router.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── index.test.js
├── custom-env
├── README.md
├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
├── config
│ ├── config.default.js
│ ├── config.prod.js
│ └── config.sit.js
├── package.json
└── test
│ └── app
│ └── controller
│ └── home.test.js
├── download
├── app
│ ├── controller
│ │ └── index.js
│ ├── public
│ │ └── hello.txt
│ └── router.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── index.test.js
├── example.js
├── framework
├── README.md
├── app
│ ├── app
│ │ ├── controller
│ │ │ └── home.js
│ │ ├── router.js
│ │ └── view
│ │ │ └── home.tpl
│ ├── package.json
│ └── test
│ │ └── app
│ │ └── controller
│ │ └── home.test.js
└── yadan
│ ├── app
│ ├── extend
│ │ ├── application.js
│ │ └── context.js
│ └── service
│ │ └── test.js
│ ├── config
│ ├── config.default.js
│ └── plugin.js
│ ├── index.js
│ ├── lib
│ ├── agent.js
│ └── application.js
│ ├── package.json
│ └── test
│ └── lib
│ └── framework.test.js
├── hackernews-async-ts-di
├── .autod.conf.js
├── .gitignore
├── .vscode
│ └── settings.json
├── README.md
├── app
│ ├── controller
│ │ ├── index.d.ts
│ │ └── news.ts
│ ├── extend
│ │ └── filter.ts
│ ├── public
│ │ ├── css
│ │ │ └── news.css
│ │ └── favicon.png
│ ├── router.ts
│ ├── service
│ │ └── HackerNews.ts
│ └── view
│ │ ├── layout
│ │ └── layout.tpl
│ │ └── news
│ │ ├── detail.tpl
│ │ ├── item.tpl
│ │ ├── list.tpl
│ │ └── user.tpl
├── config
│ ├── config.ts
│ ├── defaultConfig.ts
│ └── plugin.ts
├── package.json
├── test
│ └── app
│ │ ├── controller
│ │ └── news.test.ts
│ │ └── service
│ │ └── HackerNews.test.ts
├── tsconfig.json
└── tslint.json
├── hackernews-async-ts
├── .eslintrc
├── .gitignore
├── README.md
├── app
│ ├── controller
│ │ └── news.ts
│ ├── extend
│ │ └── filter.ts
│ ├── public
│ │ ├── css
│ │ │ └── news.css
│ │ └── favicon.png
│ ├── router.ts
│ ├── service
│ │ └── News.ts
│ └── view
│ │ ├── layout
│ │ └── layout.tpl
│ │ └── news
│ │ ├── detail.tpl
│ │ ├── item.tpl
│ │ ├── list.tpl
│ │ └── user.tpl
├── config
│ ├── config.default.ts
│ ├── config.local.ts
│ ├── config.prod.ts
│ └── plugin.ts
├── package.json
├── test
│ └── app
│ │ ├── controller
│ │ └── news.test.ts
│ │ └── service
│ │ └── News.test.ts
└── tsconfig.json
├── hackernews-async
└── README.md
├── hackernews-datahub
├── .autod.conf.js
├── README.md
├── app
│ ├── controller
│ │ ├── api.js
│ │ └── news.js
│ ├── extend
│ │ └── filter.js
│ ├── public
│ │ ├── css
│ │ │ └── news.css
│ │ └── favicon.png
│ ├── router.js
│ ├── service
│ │ └── HackerNews.js
│ └── view
│ │ ├── layout
│ │ └── layout.tpl
│ │ └── news
│ │ ├── item.tpl
│ │ └── list.tpl
├── config
│ ├── config.default.js
│ └── plugin.js
├── data
│ ├── hackernews.json
│ └── hackernews
│ │ ├── hackernews_ALL_topstories.json.json
│ │ └── hackernews_ALL_topstories.json
│ │ ├── scene
│ │ ├── default.json
│ │ ├── empty.json
│ │ ├── list20.json
│ │ └── list5.json
│ │ └── schema
│ │ ├── request.json
│ │ └── response.json
├── macaca-datahub.config.js
├── package.json
└── test
│ ├── e2e
│ ├── datahub.test.js
│ ├── helper.js
│ └── mocha.opts
│ └── unittest
│ └── app
│ ├── controller
│ └── news.test.js
│ └── service
│ └── HackerNews.test.js
├── hackernews
├── .eslintrc
├── README.md
├── app
│ ├── controller
│ │ └── news.js
│ ├── extend
│ │ └── filter.js
│ ├── public
│ │ ├── css
│ │ │ └── news.css
│ │ └── favicon.png
│ ├── router.js
│ ├── service
│ │ └── HackerNews.js
│ └── view
│ │ ├── layout
│ │ └── layout.tpl
│ │ └── news
│ │ ├── detail.tpl
│ │ ├── item.tpl
│ │ ├── list.tpl
│ │ └── user.tpl
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── test
│ └── app
│ ├── controller
│ └── news.test.js
│ └── service
│ └── HackerNews.test.js
├── hello-tegg
├── .eslintignore
├── .eslintrc
├── .gitignore
├── app
│ ├── biz
│ │ ├── HelloService.ts
│ │ └── package.json
│ ├── controller
│ │ └── HelloController.ts
│ └── middleware
│ │ └── trace_method.ts
├── config
│ ├── config.default.ts
│ └── plugin.ts
├── package.json
├── test
│ ├── biz
│ │ └── HelloService.test.ts
│ └── controller
│ │ └── HelloController.test.ts
└── tsconfig.json
├── helloworld
├── app
│ ├── controller
│ │ ├── foo.js
│ │ └── home.js
│ └── router.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── index.test.js
├── httpclient
├── README.md
├── app.js
├── app
│ ├── controller
│ │ └── httpclient.js
│ └── router.js
├── config
│ └── config.default.js
└── package.json
├── ipc
├── README.md
├── agent.js
├── app.js
├── app
│ ├── controller
│ │ └── api.js
│ ├── router.js
│ ├── schedule
│ │ ├── force_refresh.js
│ │ └── pull_refresh.js
│ └── service
│ │ └── source.js
├── lib
│ └── subscriber.js
└── package.json
├── middleware
├── app
│ └── middleware
│ │ └── hello.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── index.test.js
├── multipart-file-mode
├── .gitignore
├── app
│ ├── controller
│ │ ├── ajax.js
│ │ ├── form.js
│ │ ├── home.js
│ │ └── multiple.js
│ ├── router.js
│ └── view
│ │ ├── index.html
│ │ ├── layout.html
│ │ └── page
│ │ ├── ajax.html
│ │ ├── form.html
│ │ ├── multiple.html
│ │ └── multiple_result.html
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── test
│ ├── index.test.js
│ ├── kfc.jpeg
│ └── mc.jpeg
├── multipart
├── .gitignore
├── app
│ ├── controller
│ │ ├── ajax.js
│ │ ├── buffer.js
│ │ ├── form.js
│ │ ├── home.js
│ │ └── multiple.js
│ ├── router.js
│ └── view
│ │ ├── index.html
│ │ ├── layout.html
│ │ └── page
│ │ ├── ajax.html
│ │ ├── buffer.html
│ │ ├── form.html
│ │ ├── multiple.html
│ │ └── multiple_result.html
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── test
│ ├── index.test.js
│ ├── kfc.jpeg
│ └── mc.jpeg
├── package.json
├── passport
├── .gitignore
├── README.md
├── app
│ ├── controller
│ │ ├── home.js
│ │ └── user.js
│ └── router.js
├── config
│ ├── config.default.js
│ └── plugin.js
└── package.json
├── progressive
├── step1
│ ├── app
│ │ ├── controller
│ │ │ └── home.js
│ │ ├── extend
│ │ │ └── context.js
│ │ └── router.js
│ ├── config
│ │ └── config.default.js
│ ├── package.json
│ └── test
│ │ └── index.test.js
├── step2
│ ├── app
│ │ ├── controller
│ │ │ └── home.js
│ │ └── router.js
│ ├── config
│ │ ├── config.default.js
│ │ └── plugin.js
│ ├── lib
│ │ └── plugin
│ │ │ └── egg-ua
│ │ │ ├── app
│ │ │ └── extend
│ │ │ │ └── context.js
│ │ │ └── package.json
│ ├── package.json
│ └── test
│ │ └── index.test.js
├── step3
│ ├── egg-ua
│ │ ├── app
│ │ │ └── extend
│ │ │ │ └── context.js
│ │ ├── package.json
│ │ └── test
│ │ │ ├── fixtures
│ │ │ └── test-app
│ │ │ │ ├── app
│ │ │ │ └── router.js
│ │ │ │ ├── config
│ │ │ │ └── config.default.js
│ │ │ │ └── package.json
│ │ │ └── ua.test.js
│ └── example-app
│ │ ├── app
│ │ ├── controller
│ │ │ └── home.js
│ │ └── router.js
│ │ ├── config
│ │ ├── config.default.js
│ │ └── plugin.js
│ │ ├── package.json
│ │ └── test
│ │ └── index.test.js
└── step4
│ ├── egg-ua
│ ├── app
│ │ └── extend
│ │ │ └── context.js
│ ├── package.json
│ └── test
│ │ ├── fixtures
│ │ └── test-app
│ │ │ ├── app
│ │ │ └── router.js
│ │ │ ├── config
│ │ │ └── config.default.js
│ │ │ └── package.json
│ │ └── ua.test.js
│ ├── example-app
│ ├── app
│ │ ├── controller
│ │ │ └── home.js
│ │ └── router.js
│ ├── config
│ │ └── config.default.js
│ ├── package.json
│ └── test
│ │ └── index.test.js
│ └── example-framework
│ ├── config
│ ├── config.default.js
│ └── plugin.js
│ ├── index.js
│ ├── lib
│ ├── agent.js
│ └── application.js
│ ├── package.json
│ └── test
│ ├── fixtures
│ └── test-app
│ │ ├── app
│ │ └── router.js
│ │ ├── config
│ │ └── config.default.js
│ │ └── package.json
│ └── framework.test.js
├── redefine-controller
├── app
│ ├── controller
│ │ └── api.js
│ ├── core
│ │ └── controller.js
│ └── router.js
├── config
│ └── config.default.js
├── package.json
└── test
│ └── controller
│ └── api.test.js
├── schedule
├── app
│ └── schedule
│ │ ├── all_cron.js
│ │ ├── all_interval.js
│ │ ├── worker_cron.js
│ │ └── worker_interval.js
├── package.json
└── test
│ └── index.test.js
├── sequelize-ts
├── .gitignore
├── .sequelizerc
├── README.md
├── README.zh-CN.md
├── app
│ ├── controller
│ │ ├── post.ts
│ │ └── user.ts
│ ├── extend
│ │ └── helper.ts
│ ├── model
│ │ ├── post.ts
│ │ └── user.ts
│ ├── router.ts
│ └── service
│ │ ├── post.ts
│ │ └── user.ts
├── config
│ ├── config.default.ts
│ ├── config.unittest.ts
│ └── plugin.ts
├── database
│ ├── config.json
│ └── migrations
│ │ ├── 20180813112934-user.js
│ │ └── 20180813112942-post.js
├── package.json
├── test
│ ├── app
│ │ └── controller
│ │ │ ├── post.test.ts
│ │ │ └── user.test.ts
│ ├── factories.ts
│ ├── mocha.opts
│ └── setup.ts
└── tsconfig.json
├── sequelize
├── .autod.conf.js
├── .sequelizerc
├── README.md
├── README.zh-CN.md
├── app
│ ├── controller
│ │ ├── post.js
│ │ └── user.js
│ ├── extend
│ │ └── helper.js
│ ├── model
│ │ ├── post.js
│ │ └── user.js
│ ├── router.js
│ └── service
│ │ ├── post.js
│ │ └── user.js
├── config
│ ├── config.default.js
│ ├── config.unittest.js
│ └── plugin.js
├── database
│ ├── config.json
│ └── migrations
│ │ ├── 20180813112934-user.js
│ │ └── 20180813112942-post.js
├── package.json
└── test
│ ├── .setup.js
│ ├── app
│ ├── controller
│ │ ├── post.test.js
│ │ └── user.test.js
│ └── service
│ │ └── post.test.js
│ └── factories.js
├── sofa-rpc
├── .autod.conf.js
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── README.md
├── README.zh-CN.md
├── app
│ ├── controller
│ │ └── home.js
│ ├── router.js
│ └── rpc
│ │ └── ProtoService.js
├── appveyor.yml
├── config
│ ├── config.default.js
│ └── proxy.js
├── package.json
├── proto
│ └── ProtoService.proto
└── test
│ ├── app
│ └── controller
│ │ └── home.test.js
│ └── server.test.js
├── static
├── app
│ ├── controller
│ │ └── home.js
│ ├── public
│ │ ├── foo.js
│ │ ├── hi.txt
│ │ └── 蛋蛋Web框架.txt
│ └── router.js
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── test
│ └── index.test.js
├── todomvc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── README.md
├── app.js
├── app
│ ├── controller
│ │ ├── home.js
│ │ └── todo.js
│ ├── middleware
│ │ └── response_time.js
│ ├── model
│ │ └── todo.js
│ ├── public
│ │ └── main.js
│ ├── router.js
│ ├── service
│ │ └── todo.js
│ └── view
│ │ └── home.tpl
├── config
│ ├── config.default.js
│ ├── config.unittest.js
│ ├── database
│ │ └── init.js
│ └── plugin.js
├── jsconfig.json
├── package.json
├── test
│ └── app
│ │ └── controller
│ │ └── home.test.js
└── todomvc.png
├── unittest-jest
├── README.md
├── __tests__
│ ├── controller
│ │ └── home.test.js
│ └── index.test.js
├── app
│ ├── controller
│ │ └── home.js
│ ├── extend
│ │ └── application.js
│ └── router.js
├── config
│ └── config.default.js
└── package.json
├── unittest
├── README.md
├── app.js
├── app
│ ├── controller
│ │ └── home.js
│ ├── extend
│ │ ├── application.js
│ │ ├── context.js
│ │ ├── helper.js
│ │ ├── request.js
│ │ └── response.js
│ ├── router.js
│ └── service
│ │ └── user.js
├── config
│ └── config.default.js
├── package.json
└── test
│ ├── controller
│ └── home.test.js
│ ├── extend
│ ├── application.test.js
│ ├── context.test.js
│ ├── helper.test.js
│ ├── request.test.js
│ └── response.test.js
│ ├── hello.test.js
│ └── service
│ └── user.test.js
└── view-nunjucks
├── app
├── controller
│ └── home.js
├── public
│ ├── css
│ │ ├── home.css
│ │ └── layout.css
│ └── js
│ │ └── home.js
├── router.js
└── view
│ ├── component
│ └── nav.html
│ ├── home.html
│ └── layout.html
├── config
├── config.default.js
└── plugin.js
├── package.json
├── test
└── index.test.js
└── uitest
├── helper.js
├── homepage.test.js
└── mocha.opts
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | ##### Checklist
12 |
13 |
14 | - [ ] `npm test` passes
15 | - [ ] tests and/or benchmarks are included
16 | - [ ] documentation is changed or added
17 | - [ ] commit message follows commit guidelines
18 |
19 | ##### Affected core subsystem(s)
20 |
21 |
22 |
23 | ##### Description of change
24 |
25 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 |
7 | pull_request:
8 | branches: [ master ]
9 |
10 | workflow_dispatch: {}
11 |
12 | jobs:
13 | Job:
14 | name: Node.js
15 | uses: artusjs/github-actions/.github/workflows/node-test.yml@master
16 | with:
17 | os: 'ubuntu-latest'
18 | version: '14, 16, 18'
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
3 | *.log
4 | npm-debug.log
5 | .logs
6 | logs
7 | *.sw*
8 | run
9 | *-run
10 | .idea
11 | .DS_Store
12 | .tmp
13 | *.log.*
14 | cnode-api-async/*.yml
15 | !static/app/public
16 | assets-with-roadhog/config/manifest.json
17 | assets-with-umi/config/manifest.json
18 | .umi
19 | .umi-production
20 | dist
21 | screenshots
22 | reports
23 | .history
24 | yarn.lock
25 | package-lock.json
26 | .nyc_output/
27 | **/proxy_class
28 | **/apiMeta.json
29 | **/pom.xml
30 | sofa-rpc/src
31 | sofa-rpc/target
32 |
--------------------------------------------------------------------------------
/assets-with-roadhog/.webpackrc:
--------------------------------------------------------------------------------
1 | {
2 | "entry": "app/assets/*.js",
3 | "theme": {
4 | "@primary-color": "#dc6aac",
5 | "@link-color": "#dc6aac",
6 | "@border-radius-base": "2px",
7 | "@font-size-base": "16px",
8 | "@line-height-base": "1.2"
9 | },
10 | "extraBabelPlugins": [
11 | [ "import", { "libraryName": "antd", "style": true } ]
12 | ],
13 | "env": {
14 | "development": {
15 | "extraBabelPlugins": [
16 | "dva-hmr"
17 | ]
18 | }
19 | },
20 | "outputPath": "app/public",
21 | "hash": true,
22 | "manifest": {
23 | "fileName": "../../config/manifest.json"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/assets-with-roadhog/README.md:
--------------------------------------------------------------------------------
1 | # Example for building frontend app with [roadhog](https://github.com/sorrycc/roadhog)
2 |
3 | ## Development
4 |
5 | ```bash
6 | $ npm i
7 | $ npm run dev
8 | $ open http://localhost:7001/
9 | ```
10 |
11 | ### Deployment
12 |
13 | Build assets with roadhog that will be generated to `app/public` which served by egg.
14 |
15 | And `manifest.json` will be generated to `config`
16 |
17 | ```bash
18 | $ npm run build
19 | ```
20 |
21 | Start server
22 |
23 | ```bash
24 | $ npm start
25 | ```
26 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "egg/react"
3 | }
4 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/assets/yay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggjs/examples/5ea83ef36dede99ae057adfb6972c5086d8d2e4c/assets-with-roadhog/app/assets/assets/yay.jpg
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/components/MainLayout/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Menu, Icon } from 'antd';
3 | import { Link } from 'dva/router';
4 |
5 | function Header({ location }) {
6 | return (
7 |
25 | );
26 | }
27 |
28 | export default Header;
29 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/components/MainLayout/MainLayout.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | display: flex;
4 | flex-direction: column;
5 | height: 100%;
6 | }
7 |
8 | .content {
9 | flex: 1;
10 | display: flex;
11 | }
12 |
13 | .main {
14 | padding: 0 8px;
15 | flex: 1 0 auto;
16 | }
17 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/components/MainLayout/MainLayout.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './MainLayout.css';
3 | import Header from './Header';
4 |
5 | function MainLayout({ children, location }) {
6 | return (
7 |
8 |
9 |
10 |
11 | {children}
12 |
13 |
14 |
15 | );
16 | }
17 |
18 | export default MainLayout;
19 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/components/Users/Users.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | }
4 |
5 | .create {
6 | margin-bottom: 1.5em;
7 | }
8 |
9 | .operation a {
10 | margin: 0 .5em;
11 | }
12 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/constants.js:
--------------------------------------------------------------------------------
1 |
2 | export const PAGE_SIZE = 3;
3 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/index.css:
--------------------------------------------------------------------------------
1 |
2 | html, body, :global(#root) {
3 | height: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/index.js:
--------------------------------------------------------------------------------
1 | import dva from 'dva';
2 | import createHistory from 'history/createBrowserHistory';
3 | import createLoading from 'dva-loading';
4 | import { message } from 'antd';
5 | import router from './router';
6 |
7 | import './index.css';
8 |
9 | const ERROR_MSG_DURATION = 3; // 3 秒
10 |
11 | // 1. Initialize
12 | const app = dva({
13 | history: createHistory(),
14 | onError(e) {
15 | message.error(e.message, ERROR_MSG_DURATION);
16 | },
17 | });
18 |
19 | // 2. Plugins
20 | app.use(createLoading());
21 |
22 | // 3. Model
23 | // Moved to router.js
24 |
25 | // 4. Router
26 | app.router(router);
27 |
28 | // 5. Start
29 | app.start('#root');
30 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/router.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Router, Switch, Route } from 'dva/router';
3 | import dynamic from 'dva/dynamic';
4 |
5 | function RouterConfig({ history, app }) {
6 | const IndexPage = dynamic({
7 | app,
8 | component: () => import('./routes/IndexPage'),
9 | });
10 |
11 | const Users = dynamic({
12 | app,
13 | models: () => [
14 | import('./models/users'),
15 | ],
16 | component: () => import('./routes/Users'),
17 | });
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | export default RouterConfig;
30 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/routes/IndexPage.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | font-family: Georgia, sans-serif;
4 | margin-top: 3em;
5 | text-align: center;
6 | }
7 |
8 | .title {
9 | font-size: 2.5rem;
10 | font-weight: normal;
11 | letter-spacing: -1px;
12 | }
13 |
14 | .welcome {
15 | height: 328px;
16 | background: url(../assets/yay.jpg) no-repeat center 0;
17 | background-size: 388px 328px;
18 | }
19 |
20 | .list {
21 | font-size: 1.2em;
22 | margin-top: 1.8em;
23 | list-style: none;
24 | line-height: 1.5em;
25 | }
26 |
27 | .list code {
28 | background: #f7f7f7;
29 | }
30 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/routes/IndexPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'dva';
3 | import styles from './IndexPage.css';
4 | import MainLayout from '../components/MainLayout/MainLayout';
5 |
6 | function IndexPage({ location }) {
7 | return (
8 |
9 |
10 |
Yay! Welcome to dva!
11 |
12 |
13 | - To get started, edit
src/index.js
and save to reload.
14 | - Getting Started
15 |
16 |
17 |
18 | );
19 | }
20 |
21 | IndexPage.propTypes = {
22 | };
23 |
24 | export default connect()(IndexPage);
25 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/routes/Users.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | width: 900px;
4 | margin: 3em auto 0;
5 | }
6 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/routes/Users.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'dva';
3 | import styles from './Users.css';
4 | import UsersComponent from '../components/Users/Users';
5 | import MainLayout from '../components/MainLayout/MainLayout';
6 |
7 | function Users({ location }) {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export default connect()(Users);
18 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/services/users.js:
--------------------------------------------------------------------------------
1 | import request from '../utils/request';
2 | import { PAGE_SIZE } from '../constants';
3 |
4 | export function fetch({ page }) {
5 | return request(`/api/users?_page=${page}&_limit=${PAGE_SIZE}`);
6 | }
7 |
8 | export function remove(id) {
9 | return request(`/api/users/${id}`, {
10 | method: 'DELETE',
11 | });
12 | }
13 |
14 | export function patch(id, values) {
15 | return request(`/api/users/${id}`, {
16 | method: 'PATCH',
17 | body: JSON.stringify(values),
18 | });
19 | }
20 |
21 | export function create(values) {
22 | return request('/api/users', {
23 | method: 'POST',
24 | body: JSON.stringify(values),
25 | });
26 | }
27 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/assets/utils/request.js:
--------------------------------------------------------------------------------
1 | import fetch from 'dva/fetch';
2 |
3 | function checkStatus(response) {
4 | if (response.status >= 200 && response.status < 300) {
5 | return response;
6 | }
7 |
8 | const error = new Error(response.statusText);
9 | error.response = response;
10 | throw error;
11 | }
12 |
13 | /**
14 | * Requests a URL, returning a promise.
15 | *
16 | * @param {string} url The URL we want to request
17 | * @param {object} [options] The options we want to pass to "fetch"
18 | * @return {object} An object containing either "data" or "err"
19 | */
20 | async function request(url, options) {
21 | const response = await fetch(url, options);
22 |
23 | checkStatus(response);
24 |
25 | const data = await response.json();
26 |
27 | const ret = {
28 | data,
29 | headers: {},
30 | };
31 |
32 | if (response.headers.get('x-total-count')) {
33 | ret.headers['x-total-count'] = response.headers.get('x-total-count');
34 | }
35 |
36 | return ret;
37 | }
38 |
39 | export default request;
40 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async index() {
7 | await this.ctx.render('index.js');
8 | }
9 |
10 | async api() {
11 | const ctx = this.ctx;
12 |
13 | const url = 'http://jsonplaceholder.typicode.com' + ctx.path.replace(/^\/api/, '') + '?' + ctx.querystring;
14 |
15 | const res = await this.ctx.curl(url, {
16 | method: this.ctx.method,
17 | });
18 | ctx.body = res.data;
19 | ctx.status = res.status;
20 | }
21 | }
22 |
23 | module.exports = HomeController;
24 |
--------------------------------------------------------------------------------
/assets-with-roadhog/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | const { router, controller } = app;
8 | router.all('/api/*', controller.home.api);
9 | router.get('*', controller.home.index);
10 | };
11 |
--------------------------------------------------------------------------------
/assets-with-roadhog/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | module.exports = appInfo => {
6 | const config = exports = {};
7 |
8 | // use for cookie sign key, should change to your own and keep security
9 | config.keys = appInfo.name + '_1513765449219_5858';
10 |
11 | // add your config here
12 | config.middleware = [];
13 |
14 | config.view = {
15 | root: path.join(appInfo.baseDir, 'app/assets'),
16 | mapping: {
17 | '.js': 'assets',
18 | },
19 | };
20 |
21 | config.assets = {
22 | publicPath: '/public/',
23 | devServer: {
24 | debug: false,
25 | command: 'roadhog dev',
26 | port: 8000,
27 | env: {
28 | BROWSER: 'none',
29 | ESLINT: 'none',
30 | SOCKET_SERVER: 'http://127.0.0.1:8000',
31 | PUBLIC_PATH: 'http://127.0.0.1:8000',
32 | },
33 | },
34 | };
35 |
36 | config.security = {
37 | csrf: false,
38 | };
39 |
40 | return config;
41 | };
42 |
--------------------------------------------------------------------------------
/assets-with-roadhog/config/config.prod.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.assets = {
4 | url: 'http://127.0.0.1:7001',
5 | };
6 |
--------------------------------------------------------------------------------
/assets-with-roadhog/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // had enabled by egg
4 | // exports.static = true;
5 |
6 | exports.assets = {
7 | enable: true,
8 | package: 'egg-view-assets',
9 | };
10 |
11 | exports.nunjucks = {
12 | enable: true,
13 | package: 'egg-view-nunjucks',
14 | };
15 |
--------------------------------------------------------------------------------
/assets-with-roadhog/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mock = require('egg-mock');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 | let app;
7 | before(() => {
8 | mock.env('local');
9 | app = mock.app();
10 | return app.ready();
11 | });
12 | after(() => app.close());
13 |
14 | afterEach(mock.restore);
15 |
16 | it('should GET /', async function() {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(/http:\/\/127.0.0.1:8000\/index.js/)
20 | .expect(200);
21 | });
22 |
23 | });
24 |
--------------------------------------------------------------------------------
/assets-with-umi/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'ues strict';
2 |
3 | module.exports = {
4 | write: true,
5 | plugin: 'autod-egg',
6 | prefix: '^',
7 | devprefix: '^',
8 | exclude: [
9 | 'test/fixtures',
10 | 'examples',
11 | 'docs',
12 | 'run',
13 | 'app/web/pages/.umi',
14 | 'app/web/pages/.umi-production',
15 | ],
16 | devdep: [
17 | 'egg-bin',
18 | 'eslint',
19 | 'eslint-config-egg',
20 | 'antd-mobile',
21 | 'umi-plugin-react',
22 | 'umi-plugin-ecma5-validator',
23 | ],
24 | dep: [
25 | 'egg',
26 | 'egg-scripts',
27 | ],
28 | semver: [
29 | ],
30 | test: 'scripts',
31 | };
32 |
--------------------------------------------------------------------------------
/assets-with-umi/.env:
--------------------------------------------------------------------------------
1 | APP_ROOT=app/web
2 | HTML=none
--------------------------------------------------------------------------------
/assets-with-umi/README.md:
--------------------------------------------------------------------------------
1 | # Example for building frontend app with [umi](https://github.com/umijs/umi)
2 |
3 | ## Development
4 |
5 | ```bash
6 | $ npm i
7 | $ npm run dev
8 | $ open http://localhost:7001/
9 | ```
10 |
11 | ### Deployment
12 |
13 | Build assets with umi that will be generated to `app/public` which served by egg.
14 |
15 | And `manifest.json` will be generated to `config`
16 |
17 | ```bash
18 | $ npm run build
19 | ```
20 |
21 | Start server
22 |
23 | ```bash
24 | $ npm start
25 | ```
26 |
--------------------------------------------------------------------------------
/assets-with-umi/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async index() {
7 | await this.ctx.render('index.html');
8 | }
9 |
10 | async api() {
11 | const ctx = this.ctx;
12 |
13 | const url = 'https://h5.ele.me' + ctx.path.replace(/^\/api/, '') + '?' + ctx.querystring;
14 |
15 | console.log(url);
16 | const res = await this.ctx.curl(url, {
17 | method: this.ctx.method,
18 | });
19 | ctx.body = res.data;
20 | ctx.status = res.status;
21 | }
22 | }
23 |
24 | module.exports = HomeController;
25 |
--------------------------------------------------------------------------------
/assets-with-umi/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | const { router, controller } = app;
8 | router.all('/restapi/*', controller.home.api);
9 | router.get('*', controller.home.index);
10 | };
11 |
--------------------------------------------------------------------------------
/assets-with-umi/app/view/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {% if ctx.app.config.env !== 'local' -%}
12 | {{ helper.assets.getStyle('vendors.css') | safe }}
13 | {%- endif %}
14 |
15 |
16 |
17 |
18 |
19 |
23 | {{ helper.assets.getScript('umi.js') | safe }}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "egg/react"
3 | }
4 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/config/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: [
3 | [
4 | 'umi-plugin-react',
5 | {
6 | hd: true,
7 | antd: true,
8 | dynamicImport: {
9 | webpackChunkName: true,
10 | },
11 | },
12 | ],
13 | ],
14 | runtimePublicPath: true,
15 | disableCSSModules: true,
16 | cssModulesWithAffix: true,
17 | };
18 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/config/config.local.js:
--------------------------------------------------------------------------------
1 | export default {
2 | proxy: {
3 | '/restapi': {
4 | target: 'http://127.0.0.1:7001/',
5 | changeOrigin: true,
6 | },
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/config/config.prod.js:
--------------------------------------------------------------------------------
1 | export default {
2 | hash: true,
3 | publicPath: '',
4 | outputPath: '../public',
5 | manifest: {
6 | fileName: '../../config/manifest.json',
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/layouts/index.module.less:
--------------------------------------------------------------------------------
1 | :global {
2 | // FIXME: antd-mobile bug, carousel
3 | .slider-decorator-0 {
4 | bottom: -40px !important;
5 | }
6 |
7 | .am-list-body {
8 | border: none;
9 | }
10 | }
11 |
12 | .contentTab {
13 | margin-bottom: 1.1rem;
14 | }
15 |
16 | .content {
17 | margin: 0;
18 | }
19 |
20 | .tabbar {
21 | position: fixed;
22 | bottom: 0;
23 | width: 100%;
24 | box-shadow: 0 -0.03rem 0.15rem rgba(0, 0, 0, .1);
25 | padding-top: 15px;
26 | background: #fff;
27 | }
28 |
29 | .tab {
30 | display: flex;
31 | flex-direction: column;
32 | align-items: center;
33 |
34 | .icon {
35 | width: 35px;
36 | height: 35px;
37 | }
38 |
39 | .title {
40 | color: #666;
41 | font-size: 24px;
42 | font-weight: 300;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/pages/discover/index.jsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import router from 'umi/router';
3 | import { NavBar, Icon, Grid } from 'antd-mobile';
4 | import styles from './index.module.less';
5 |
6 | export default class extends React.Component {
7 | renderItem = data => {
8 | return (
9 | {data.title}
10 | );
11 | }
12 |
13 | render() {
14 | const items = [
15 | { title: '金币商城' },
16 | { title: '有红包快抢' },
17 | { title: '必吃爆料' },
18 | { title: '推荐有奖' },
19 | { title: '周边优惠' },
20 | { title: '百元红包' },
21 | ];
22 |
23 | return (
24 |
25 |
router.goBack()}
27 | mode="dark"
28 | icon={}
29 | >发现
30 |
31 |
为你推荐
32 |
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/pages/discover/index.module.less:
--------------------------------------------------------------------------------
1 | .recommend {
2 | margin: .2rem 0;
3 | padding: .2rem;
4 | background: #fff;
5 | }
6 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/pages/index.js:
--------------------------------------------------------------------------------
1 | import Home from './home/index';
2 | export default Home;
3 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/pages/order/index.jsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import router from 'umi/router';
3 | import { NavBar, Icon, Button } from 'antd-mobile';
4 | import styles from './index.module.less';
5 |
6 | export default class extends React.Component {
7 | renderItem = data => {
8 | return (
9 | {data.title}
10 | );
11 | }
12 |
13 | render() {
14 | return (
15 |
16 |
router.goBack()}
18 | mode="dark"
19 | icon={}
20 | >订单
21 |
22 |

23 |
登录后查看外卖订单
24 |
25 |
26 |
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/pages/order/index.module.less:
--------------------------------------------------------------------------------
1 | .noLogin {
2 | display: flex;
3 | flex-direction: column;
4 | width: 100%;
5 | justify-content: center;
6 | align-items: center;
7 | margin-top: 2.4rem;
8 | font-size: .32rem;
9 | color: #666;
10 |
11 | h3 {
12 | font-weight: 400;
13 | }
14 |
15 | img {
16 | width: 4rem;
17 | }
18 |
19 | :global {
20 | .am-button {
21 | padding: 0 .5rem;
22 | background: #56d176;
23 | color: #fff;
24 | border-radius: 0;
25 | font-weight: 300;
26 | font-size: .26rem;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/assets-with-umi/app/web/pages/profile/index.module.less:
--------------------------------------------------------------------------------
1 | .banner {
2 | :global {
3 | .am-list-item,
4 | .am-navbar {
5 | background-image: linear-gradient(90deg, #0af, #0085ff);
6 | }
7 | }
8 |
9 | .info,
10 | .subInfo {
11 | color: #fff;
12 | font-weight: 300;
13 | }
14 |
15 | .subInfo {
16 | font-size: .24rem;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/assets-with-umi/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = exports = {};
5 |
6 | // use for cookie sign key, should change to your own and keep security
7 | config.keys = appInfo.name + '_1513765449219_5858';
8 |
9 | // add your config here
10 | config.middleware = [];
11 |
12 | config.view = {
13 | mapping: {
14 | '.html': 'nunjucks',
15 | },
16 | };
17 |
18 | config.assets = {
19 | publicPath: '/public/',
20 | devServer: {
21 | debug: true,
22 | command: 'umi dev',
23 | port: 8000,
24 | env: {
25 | APP_ROOT: process.cwd() + '/app/web',
26 | BROWSER: 'none',
27 | ESLINT: 'none',
28 | SOCKET_SERVER: 'http://127.0.0.1:8000',
29 | PUBLIC_PATH: 'http://127.0.0.1:8000',
30 | },
31 | },
32 | };
33 |
34 | config.security = {
35 | csrf: false,
36 | };
37 |
38 | return config;
39 | };
40 |
--------------------------------------------------------------------------------
/assets-with-umi/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // had enabled by egg
4 | // exports.static = true;
5 |
6 | exports.assets = {
7 | enable: true,
8 | package: 'egg-view-assets',
9 | };
10 |
11 | exports.nunjucks = {
12 | enable: true,
13 | package: 'egg-view-nunjucks',
14 | };
15 |
--------------------------------------------------------------------------------
/assets-with-umi/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mock = require('egg-mock');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 | let app;
7 | before(() => {
8 | mock.env('local');
9 | app = mock.app();
10 | return app.ready();
11 | });
12 | after(() => app.close());
13 |
14 | afterEach(mock.restore);
15 |
16 | it('should GET /', async function() {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(/http:\/\/127.0.0.1:8000\/umi.js/)
20 | .expect(200);
21 | });
22 |
23 | });
24 |
--------------------------------------------------------------------------------
/bin/list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Command = require('./base');
4 |
5 | class List extends Command {
6 | async run() {
7 | const cache = new Set();
8 | const dirs = await this.getExamples();
9 | for (let dir of dirs) {
10 | dir = dir.split('/')[0];
11 | if (cache.has(dir)) continue;
12 | cache.add(dir);
13 | console.info('- [%s](https://github.com/eggjs/examples/tree/master/%s)', dir, dir);
14 | }
15 | }
16 | }
17 |
18 | module.exports = List;
19 |
--------------------------------------------------------------------------------
/bodyParser/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 | const { xml2js } = require('xml-js');
5 |
6 | class HomeController extends Controller {
7 | async body() {
8 | const { ctx } = this;
9 |
10 | ctx.body = {
11 | type: ctx.get('content-type'),
12 | body: ctx.request.body,
13 | };
14 | }
15 |
16 | async xml() {
17 | const { ctx } = this;
18 |
19 | const xmlContent = xml2js(ctx.request.body);
20 | const body = xmlContent.elements[0].attributes;
21 |
22 | ctx.body = {
23 | type: ctx.get('content-type'),
24 | body,
25 | };
26 | }
27 | }
28 |
29 | module.exports = HomeController;
30 |
--------------------------------------------------------------------------------
/bodyParser/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 |
6 | router.post('/api/body', controller.home.body);
7 | router.post('/api/xml', controller.home.xml);
8 | };
9 |
--------------------------------------------------------------------------------
/bodyParser/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = '123456';
4 |
5 | exports.bodyParser = {
6 | enableTypes: [ 'json', 'form', 'text' ],
7 | extendTypes: {
8 | json: 'application/custom-json',
9 | text: [ 'application/xml' ],
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/bodyParser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bodyParser",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "egg": "^2",
6 | "xml-js": "^1.6.9"
7 | },
8 | "devDependencies": {
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "scripts": {
13 | "dev": "egg-bin dev",
14 | "test": "egg-bin test",
15 | "cov": "egg-bin cov"
16 | },
17 | "private": true
18 | }
19 |
--------------------------------------------------------------------------------
/cnode-api-async/README.md:
--------------------------------------------------------------------------------
1 | See [cnode-api](https://github.com/eggjs/examples/tree/master/cnode-api)
2 |
--------------------------------------------------------------------------------
/cnode-api/README.md:
--------------------------------------------------------------------------------
1 | # cnode-api
2 |
3 | ## QuickStart
4 |
5 |
6 |
7 | see [egg docs][egg] for more detail.
8 |
9 | ### Development
10 | ```shell
11 | $ npm install
12 | $ npm run dev
13 | $ open http://localhost:7001/news
14 | ```
15 |
16 | ### Deploy
17 |
18 | Use `EGG_SERVER_ENV=prod` to enable prod mode
19 |
20 | ```shell
21 | $ EGG_SERVER_ENV=prod npm start
22 | ```
23 |
24 | ### npm scripts
25 |
26 | - Use `npm run lint` to check code style.
27 | - Use `npm test` to run unit test.
28 | - Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
29 |
30 |
31 | [egg]: https://eggjs.org
32 |
--------------------------------------------------------------------------------
/cnode-api/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # cnode-api
2 |
3 | ## 快速入门
4 |
5 |
6 |
7 | 如需进一步了解,参见 [egg 文档][egg]。
8 |
9 | ### 本地开发
10 | ```bash
11 | $ npm install
12 | $ npm run dev
13 | $ open http://localhost:7001/news
14 | ```
15 |
16 | ### 部署
17 |
18 | 线上正式环境用 `EGG_SERVER_ENV=prod` 来启动。
19 |
20 | ```bash
21 | $ EGG_SERVER_ENV=prod npm start
22 | ```
23 |
24 | ### 单元测试
25 | - [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。
26 | - 断言库非常推荐使用 [power-assert]。
27 | - 具体参见 [egg 文档 -单元测试](https://eggjs.org/zh-cn/core/unittest)。
28 |
29 | ### 内置指令
30 |
31 | - 使用 `npm run lint` 来做代码风格检查。
32 | - 使用 `npm test` 来执行单元测试。
33 | - 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod) 。
34 |
35 |
36 | [egg]: https://eggjs.org
37 |
--------------------------------------------------------------------------------
/cnode-api/app/middleware/error_handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = (option, app) => {
4 | return async function(ctx, next) {
5 | try {
6 | await next();
7 | } catch (err) {
8 | // 所有的异常都在 app 上触发一个 error 事件,框架会记录一条错误日志
9 | app.emit('error', err, this);
10 | const status = err.status || 500;
11 | // 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
12 | const error = status === 500 && app.config.env === 'prod'
13 | ? 'Internal Server Error'
14 | : err.message;
15 | // 从 error 对象上读出各个属性,设置到响应中
16 | ctx.body = { error };
17 | if (status === 422) {
18 | ctx.body.detail = err.errors;
19 | }
20 | ctx.status = status;
21 | }
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/cnode-api/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.resources('topics', '/api/v2/topics', 'topics');
5 | };
6 |
--------------------------------------------------------------------------------
/cnode-api/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = {};
5 |
6 | // should change to your own
7 | config.keys = appInfo.name + '_1490750627161_5967';
8 |
9 | config.middleware = [ 'errorHandler' ];
10 |
11 | return config;
12 | };
13 |
--------------------------------------------------------------------------------
/cnode-api/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.validate = {
4 | enable: true,
5 | package: 'egg-validate',
6 | };
7 |
--------------------------------------------------------------------------------
/cnode-api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cnode-api-async",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^1.10.1",
8 | "egg-validate": "^1.0.0"
9 | },
10 | "devDependencies": {
11 | "egg-bin": "^4.3.5",
12 | "egg-mock": "^3.13.1"
13 | },
14 | "engines": {
15 | "node": ">=8.9.0"
16 | },
17 | "scripts": {
18 | "start": "eggctl start",
19 | "dev": "egg-bin dev",
20 | "test": "npm run test-local",
21 | "test-local": "egg-bin test",
22 | "cov": "egg-bin cov",
23 | "lint": "eslint .",
24 | "ci": "npm run lint && npm run cov",
25 | "autod": "autod"
26 | },
27 | "ci": {
28 | "version": "8"
29 | },
30 | "license": "MIT"
31 | }
32 |
--------------------------------------------------------------------------------
/cookie-session/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 |
7 | async setSession() {
8 | const ctx = this.ctx;
9 |
10 | ctx.session.count = (ctx.session.count || 0) + 1;
11 | ctx.body = `${ctx.session.count} times, now: ${Date()}`;
12 | }
13 |
14 | }
15 |
16 | module.exports = HomeController;
17 |
--------------------------------------------------------------------------------
/cookie-session/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', app.controller.home.setSession);
5 | };
6 |
--------------------------------------------------------------------------------
/cookie-session/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my cooo00ooooool keys';
4 | exports.security = {
5 | csrf: false,
6 | ctoken: false,
7 | };
8 |
--------------------------------------------------------------------------------
/cookie-session/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cookie-session-example",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "dev": "egg-bin dev",
12 | "test": "egg-bin test",
13 | "cov": "egg-bin cov"
14 | },
15 | "private": true
16 | }
17 |
--------------------------------------------------------------------------------
/cookie-session/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('example cookie_session test', () => {
7 | let app;
8 | let cookie;
9 |
10 | before(() => {
11 | app = mm.app();
12 | return app.ready();
13 | });
14 |
15 | after(() => app.close());
16 |
17 | it('should GET / first time', () => {
18 | return app.httpRequest()
19 | .get('/')
20 | .expect(200)
21 | .expect(/^1 times/)
22 | .expect('Set-Cookie', /^EGG_SESS=[^;]+; path=\/; expires=[^;]+; httponly$/)
23 | .expect(res => {
24 | cookie = res.headers['set-cookie'][0].split(';')[0];
25 | });
26 | });
27 |
28 | it('should GET / second time', () => {
29 | return app.httpRequest()
30 | .get('/')
31 | .set('Cookie', cookie)
32 | .expect(200)
33 | .expect(/^2 times/)
34 | // session.count change
35 | .expect('Set-Cookie', /^EGG_SESS=[^;]+; path=\/; expires=[^;]+; httponly$/);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/cookie/app/controller/cookie.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class CookieController extends Controller {
6 |
7 | async home() {
8 | const ctx = this.ctx;
9 |
10 | if (ctx.cookies.get('remember')) {
11 | ctx.body = 'Remembered :). Click to forget!.
';
12 | return;
13 | }
14 |
15 | ctx.body = ``;
18 | }
19 |
20 | async forget() {
21 | const ctx = this.ctx;
22 |
23 | ctx.cookies.set('remember', null);
24 | ctx.redirect('/');
25 | }
26 |
27 | async remember() {
28 | const ctx = this.ctx;
29 |
30 | const minute = 60000;
31 | if (ctx.request.body.remember) {
32 | ctx.cookies.set('remember', 1, { maxAge: minute });
33 | }
34 | ctx.redirect('/');
35 | }
36 |
37 | }
38 |
39 | module.exports = CookieController;
40 |
--------------------------------------------------------------------------------
/cookie/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', app.controller.cookie.home);
5 | app.router.get('/forget', app.controller.cookie.forget);
6 | app.router.post('/remember', app.controller.cookie.remember);
7 | };
8 |
--------------------------------------------------------------------------------
/cookie/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my cooo00ooooool keys';
4 | exports.security = {
5 | csrf: false,
6 | ctoken: false,
7 | };
8 |
--------------------------------------------------------------------------------
/cookie/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cookie-example",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "dev": "egg-bin dev",
12 | "test": "egg-bin test",
13 | "cov": "egg-bin cov"
14 | },
15 | "private": true
16 | }
17 |
--------------------------------------------------------------------------------
/custom-env/README.md:
--------------------------------------------------------------------------------
1 | # custom environment
2 |
3 | Egg will load different config file in different env, in this example we create `config.default.js`, `config.sit.js` and `config.prod.js`.
4 |
5 | Egg will load `config.sit.js` when lanched by `EGG_SERVER_ENV=sit npm run dev`. You can get see the response
6 |
7 | ```bash
8 | $ curl http://127.0.0.1:7001
9 | {"env":"sit","config":"sit keys"}%
10 | ```
11 |
--------------------------------------------------------------------------------
/custom-env/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class EnvController extends Controller {
6 | async getEnv() {
7 | const ctx = this.ctx;
8 |
9 | ctx.body = {
10 | env: ctx.app.config.env,
11 | config: ctx.app.config.keys,
12 | };
13 | }
14 | }
15 |
16 | module.exports = EnvController;
17 |
--------------------------------------------------------------------------------
/custom-env/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', app.controller.home.getEnv);
5 | };
6 |
--------------------------------------------------------------------------------
/custom-env/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | keys: 'default keys',
5 | };
6 |
--------------------------------------------------------------------------------
/custom-env/config/config.prod.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | keys: 'prod keys',
5 | };
6 |
--------------------------------------------------------------------------------
/custom-env/config/config.sit.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | keys: 'sit keys',
5 | };
6 |
--------------------------------------------------------------------------------
/custom-env/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-env",
3 | "version": "1.0.0",
4 | "description": "custom environment",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^1.10.1"
8 | },
9 | "devDependencies": {
10 | "egg-bin": "^4.3.5",
11 | "egg-mock": "^3.13.1"
12 | },
13 | "engines": {
14 | "node": ">=8.9.0"
15 | },
16 | "scripts": {
17 | "start": "node index.js",
18 | "dev": "egg-bin dev",
19 | "test": "egg-bin test",
20 | "autod": "autod"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/download/app/controller/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const Controller = require('egg').Controller;
6 |
7 | class IndexController extends Controller {
8 | async index() {
9 | this.ctx.body = [
10 | 'download',
11 | '
',
12 | 'download image',
13 | ].join('');
14 | }
15 |
16 | async download() {
17 | const filePath = path.resolve(this.app.config.static.dir, 'hello.txt');
18 | this.ctx.attachment('hello.txt');
19 | this.ctx.set('Content-Type', 'application/octet-stream');
20 | this.ctx.body = fs.createReadStream(filePath);
21 | }
22 |
23 | async downloadImage() {
24 | const url = 'http://cdn2.ettoday.net/images/1200/1200526.jpg';
25 | const res = await this.ctx.curl(url, {
26 | streaming: true,
27 | });
28 |
29 | this.ctx.type = 'jpg';
30 | this.ctx.body = res.res;
31 | }
32 | }
33 |
34 | module.exports = IndexController;
35 |
--------------------------------------------------------------------------------
/download/app/public/hello.txt:
--------------------------------------------------------------------------------
1 | hello, egg
--------------------------------------------------------------------------------
/download/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', app.controller.index.index);
5 | app.router.get('/download', app.controller.index.download);
6 | app.router.get('/download-image', app.controller.index.downloadImage);
7 | };
8 |
--------------------------------------------------------------------------------
/download/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my secret keys';
4 |
--------------------------------------------------------------------------------
/download/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "download",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1",
9 | "supertest": "^3.0.0"
10 | },
11 | "scripts": {
12 | "dev": "egg-bin dev",
13 | "test": "egg-bin test",
14 | "lint": "eslint app config test *.js",
15 | "cov": "egg-bin cov"
16 | },
17 | "private": true
18 | }
19 |
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | const path = require('path');
6 | const Command = require('common-bin');
7 |
8 | class Example extends Command {
9 | constructor(rawArgs) {
10 | super(rawArgs);
11 |
12 | this.load(path.join(__dirname, 'bin'));
13 | }
14 | }
15 |
16 | new Example().start();
17 |
--------------------------------------------------------------------------------
/framework/README.md:
--------------------------------------------------------------------------------
1 | # Framework Example
2 |
3 | This example contains [app] and [framework]
4 |
5 | ## Quick Start
6 |
7 | Start an application using custom framework called yadan
8 |
9 | ```bash
10 | $ cd app
11 | $ npm install
12 | $ npm link ../yadan
13 | $ npm run dev
14 | ```
15 |
16 | Yadan is a framework, it should be published to npm normally. With this example, you just `npm link` it.
17 |
18 | ## Run Test
19 |
20 | Application
21 |
22 | ```bash
23 | $ cd app
24 | $ npm test
25 | ```
26 |
27 | Framework
28 |
29 | ```bash
30 | $ cd yadan
31 | $ npm test
32 | ```
33 |
34 | ## Questions & Suggestions
35 |
36 | Please open an issue [here](https://github.com/eggjs/egg/issues).
37 |
38 | [app]: https://github.com/eggjs/examples/tree/master/framework/app
39 | [framework]: https://github.com/eggjs/examples/tree/master/framework/yadan
40 |
--------------------------------------------------------------------------------
/framework/app/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('yadan').Controller;
4 |
5 | class HomeController extends Controller {
6 | async render() {
7 | const ctx = this.ctx;
8 |
9 | // use service defined in framework
10 | const data = await ctx.service.test.get(123);
11 | await ctx.render('home.tpl', data);
12 | }
13 | }
14 |
15 | module.exports = HomeController;
16 |
--------------------------------------------------------------------------------
/framework/app/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', app.controller.home.render);
5 | };
6 |
--------------------------------------------------------------------------------
/framework/app/app/view/home.tpl:
--------------------------------------------------------------------------------
1 | hi, {{ name }}
--------------------------------------------------------------------------------
/framework/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "framework-example",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "yadan": "../yadan"
6 | },
7 | "devDependencies": {
8 | "egg-bin": "^4.3.5",
9 | "egg-mock": "^3.13.1"
10 | },
11 | "scripts": {
12 | "dev": "egg-bin dev",
13 | "test": "egg-bin test"
14 | },
15 | "egg": {
16 | "framework": "yadan"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/framework/app/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mock = require('egg-mock');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 |
7 | let app;
8 | before(() => {
9 | app = mock.app();
10 | return app.ready();
11 | });
12 |
13 | it('should GET /', () => {
14 | return app.httpRequest()
15 | .get('/')
16 | .expect(200)
17 | .expect('hi, framework-example_123456');
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/framework/yadan/app/extend/application.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 |
5 | };
6 |
--------------------------------------------------------------------------------
/framework/yadan/app/extend/context.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 |
5 | };
6 |
--------------------------------------------------------------------------------
/framework/yadan/app/service/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Service = require('egg').Service;
4 |
5 | /**
6 | * Test Service
7 | */
8 | class Test extends Service {
9 | constructor(ctx) {
10 | super(ctx);
11 | this.config = this.app.config.test;
12 | }
13 |
14 | async get(id) {
15 | return { id, name: this.config.key };
16 | }
17 | }
18 |
19 | module.exports = Test;
20 |
--------------------------------------------------------------------------------
/framework/yadan/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = {};
5 |
6 | config.keys = 'keys';
7 |
8 | /**
9 | * some description
10 | * @member Config#test
11 | * @property {String} key - some description
12 | */
13 | config.test = {
14 | key: appInfo.name + '_123456',
15 | };
16 |
17 | config.view = {
18 | defaultViewEngine: 'nunjucks',
19 | };
20 |
21 | return config;
22 | };
23 |
--------------------------------------------------------------------------------
/framework/yadan/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // add you build-in plugin here, example:
4 | exports.nunjucks = {
5 | enable: true,
6 | package: 'egg-view-nunjucks',
7 | };
8 |
--------------------------------------------------------------------------------
/framework/yadan/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Application = require('./lib/application');
4 | const Agent = require('./lib/agent');
5 | const egg = require('egg');
6 |
7 | // clone egg API
8 | Object.assign(exports, egg);
9 |
10 | // override Application and Agent
11 | exports.Application = Application;
12 | exports.Agent = Agent;
13 |
--------------------------------------------------------------------------------
/framework/yadan/lib/agent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const egg = require('egg');
5 | const EGG_PATH = Symbol.for('egg#eggPath');
6 |
7 | class YadanAgent extends egg.Agent {
8 | get [EGG_PATH]() {
9 | return path.dirname(__dirname);
10 | }
11 | }
12 |
13 | module.exports = YadanAgent;
14 |
--------------------------------------------------------------------------------
/framework/yadan/lib/application.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const egg = require('egg');
5 | const EGG_PATH = Symbol.for('egg#eggPath');
6 |
7 | class YadanApplication extends egg.Application {
8 | get [EGG_PATH]() {
9 | return path.dirname(__dirname);
10 | }
11 | }
12 |
13 | module.exports = YadanApplication;
14 |
--------------------------------------------------------------------------------
/framework/yadan/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yadan",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "egg": "^1.10.1",
6 | "egg-view-nunjucks": "^2.1.4"
7 | },
8 | "devDependencies": {
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "engines": {
13 | "node": ">=8.9.0"
14 | },
15 | "scripts": {
16 | "test": "egg-bin test"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/framework/yadan/test/lib/framework.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const assert = require('assert');
5 |
6 | const mm = require('egg-mock');
7 |
8 | describe('test/lib/framework.test.js', () => {
9 | let app;
10 | before(() => {
11 | app = mm.app({
12 | baseDir: path.join(__dirname, '../../../app'),
13 | customEgg: true,
14 | });
15 | return app.ready();
16 | });
17 | after(() => app.close());
18 | afterEach(mm.restore);
19 |
20 | it('should GET /', () => {
21 | return app.httpRequest()
22 | .get('/')
23 | .expect('hi, framework-example_123456')
24 | .expect(200);
25 | });
26 |
27 | it('should load config', () => {
28 | assert(app.config.test.key === 'framework-example_123456');
29 | });
30 |
31 | it('should load service', function* () {
32 | const ctx = app.mockContext();
33 | const data = yield ctx.service.test.get(123);
34 | assert.deepEqual(data, {
35 | id: 123,
36 | name: 'framework-example_123456',
37 | });
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'ues strict';
2 |
3 | module.exports = {
4 | write: true,
5 | plugin: 'autod-egg',
6 | prefix: '^',
7 | devprefix: '^',
8 | exclude: [
9 | 'test/fixtures',
10 | ],
11 | dep: [
12 | 'egg',
13 | ],
14 | devdep: [
15 | 'autod',
16 | 'autod-egg',
17 | 'egg-bin',
18 | ],
19 | keep: [
20 | 'tslib',
21 | 'typescript',
22 | ],
23 | semver: [
24 | ],
25 | test: 'scripts',
26 | };
27 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | "USE_GITIGNORE": true,
4 | "**/*.js": {
5 | "when": "$(basename).ts"
6 | },
7 | "**/*.map": true,
8 | "run": true,
9 | "logs": true,
10 | "out": true,
11 | "node_modules": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/README.md:
--------------------------------------------------------------------------------
1 | # egg-example-hackernews-async
2 |
3 | [Hacker News](https://news.ycombinator.com/) showcase using async/await for egg
4 |
5 | ## QuickStart
6 |
7 | ### Development
8 | ```shell
9 | $ npm install
10 | $ npm run tsc:w
11 | $ npm run dev
12 | $ open http://localhost:7001/
13 | ```
14 |
15 | ### Deploy
16 |
17 | Use `EGG_SERVER_ENV=prod` to enable prod mode
18 |
19 | ```shell
20 | $ EGG_SERVER_ENV=prod npm start
21 | ```
22 |
23 | ### Npm Scripts
24 |
25 | - Use `npm run autod` to auto detect dependencies upgrade
26 | - Use `npm run lint` to check code style
27 | - Use `npm test` to run unit test
28 |
29 | ### Requirement
30 |
31 | Please ensure your node version is `>=7.6.0` for async await support without flag. If your node version is `>=7.0.0 < 7.6.0`, you can run npm scripts with harmony flag
32 |
33 | ```shell
34 | # start server
35 | npm run dev -- --harmony-async-await
36 | # run test cases
37 | npm run test-local -- --harmony-async-await
38 | ```
39 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/controller/index.d.ts:
--------------------------------------------------------------------------------
1 | import NewsController from './news';
2 | declare module 'egg' {
3 | export interface IController {
4 | news: NewsController;
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/extend/filter.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as moment from 'moment';
4 |
5 | exports.relativeTime = (time) => moment(new Date(time * 1000)).fromNow();
6 |
7 | exports.domain = (url) => url && url.split('/')[2];
8 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/router.ts:
--------------------------------------------------------------------------------
1 | import { Application } from 'egg';
2 |
3 | export default (app: Application) => {
4 | const controller = app.controller;
5 | app.redirect('/', '/news');
6 | app.router.get('/news', controller.news.list);
7 | app.router.get('/news/item/:id', controller.news.detail);
8 | app.router.get('/news/user/:id', controller.news.user);
9 | };
10 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/view/layout/layout.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {% block title %}egg - HackerNews{% endblock %}
9 |
10 |
11 |
12 |
19 | {% block content %}{% endblock %}
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/view/news/detail.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 |
6 | {% include "./item.tpl" %}
7 |
8 | {% if comments.length > 0%}
9 |
23 | {% else %}
24 |
No comments yet.
25 | {% endif %}
26 |
27 | {% endblock %}
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/view/news/item.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/view/news/list.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 | {% for item in list %}
6 | {% set index = ((page-1) * pageSize + loop.index) %}
7 | {% include "./item.tpl" %}
8 | {% endfor %}
9 |
10 |
11 | {% if page > 1 %}
12 |
< prev
13 | {% endif %}
14 |
more...
15 |
16 |
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/app/view/news/user.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 | {% block title %}
3 | Profile: {{ user.id }} | egg - HackerNews
4 | {% endblock %}
5 | {% block content %}
6 |
23 | {% endblock %}
--------------------------------------------------------------------------------
/hackernews-async-ts-di/config/config.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import { EggAppConfig } from 'egg';
3 | import * as fs from 'fs';
4 | import * as path from 'path';
5 | import 'source-map-support/register';
6 | import defaultConfig from './defaultConfig';
7 |
8 | export default (appInfo: EggAppConfig) => {
9 | const config: any = {};
10 |
11 | // should change to your own
12 | config.keys = appInfo.name + '123456';
13 |
14 | config.siteFile = {
15 | '/favicon.ico': fs.readFileSync(path.join(appInfo.baseDir, 'app/public/favicon.png')),
16 | };
17 |
18 | config.view = {
19 | defaultViewEngine: 'nunjucks',
20 | mapping: {
21 | '.tpl': 'nunjucks',
22 | },
23 | };
24 |
25 | return { ...config, ...defaultConfig };
26 | };
27 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/config/defaultConfig.ts:
--------------------------------------------------------------------------------
1 | export class DefaultConfig {
2 | news = {
3 | pageSize: 30,
4 | serverUrl: 'https://hacker-news.firebaseio.com/v0',
5 | };
6 | };
7 |
8 | export default new DefaultConfig();
9 |
10 | declare module 'egg' {
11 | export interface Application {
12 | config: EggAppConfig & DefaultConfig;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/config/plugin.ts:
--------------------------------------------------------------------------------
1 | exports.static = true;
2 |
3 | exports.nunjucks = {
4 | enable: true,
5 | package: 'egg-view-nunjucks',
6 | };
7 |
8 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/test/app/service/HackerNews.test.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as assert from 'assert';
4 | import { Context } from 'egg';
5 | import { getComponent } from 'egg-di';
6 | import mm from 'egg-mock';
7 | import { HackerNews } from '../../../app/service/HackerNews';
8 |
9 | describe('test/app/service/HackerNews.test.js', () => {
10 | const app = mm.app();
11 | let ctx: Context;
12 | let hackerNews: HackerNews;
13 |
14 | before(async () => {
15 | await app.ready();
16 | ctx = app.mockContext();
17 | hackerNews = getComponent(HackerNews, ctx);
18 | });
19 |
20 | after(() => app.close());
21 | afterEach(mm.restore);
22 |
23 | it('getTopStories', async () => {
24 | const list = await hackerNews.getTopStories();
25 | assert(list.length === 30);
26 | });
27 |
28 | it('getItem', async () => {
29 | const item = await hackerNews.getItem(1);
30 | assert(item.id && item.title && item.url);
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "compilerOptions": {
4 | "target": "es2017",
5 | "module": "commonjs",
6 | "noImplicitAny": false,
7 | "experimentalDecorators": true,
8 | "emitDecoratorMetadata": true,
9 | "charset": "utf8",
10 | "allowJs": false,
11 | "pretty": true,
12 | "noEmitOnError": false,
13 | "noUnusedLocals": true,
14 | "noUnusedParameters": true,
15 | "allowUnreachableCode": false,
16 | "allowUnusedLabels": false,
17 | "noFallthroughCasesInSwitch": true,
18 | "skipLibCheck": true,
19 | "skipDefaultLibCheck": true,
20 | "inlineSourceMap": true,
21 | "importHelpers": true
22 | },
23 | "include": [
24 | "app/**/*",
25 | "config/**/*",
26 | "test/**/*.ts"
27 | ],
28 | "exclude": [
29 | "app/public",
30 | "app/views"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/hackernews-async-ts-di/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:latest",
3 | "rules": {
4 | "quotemark": [
5 | true,
6 | "single",
7 | "jsx-double"
8 | ],
9 | "no-console": [
10 | true,
11 | "dir",
12 | "log",
13 | "error",
14 | "warn"
15 | ],
16 | "space-before-function-paren": false,
17 | "interface-name": [
18 | true,
19 | "never-prefix"
20 | ],
21 | "adjacent-overload-signatures": true,
22 | "member-access": [
23 | false
24 | ],
25 | "member-ordering": [
26 | true,
27 | {
28 | "order": "fields-first"
29 | }
30 | ],
31 | "object-literal-sort-keys": false,
32 | "max-classes-per-file": [
33 | true,
34 | 10
35 | ],
36 | "variable-name": [
37 | true,
38 | "allow-leading-underscore"
39 | ],
40 | "align": [true, "statements"]
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/hackernews-async-ts/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "eslint-config-egg/typescript"
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/hackernews-async-ts/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | node_modules/
4 | coverage/
5 | .idea/
6 | run/
7 | logs/
8 | .DS_Store
9 | .vscode
10 | *.swp
11 | *.lock
12 | *.js
13 |
14 | app/**/*.js
15 | test/**/*.js
16 | config/**/*.js
17 | app/**/*.map
18 | test/**/*.map
19 | config/**/*.map
--------------------------------------------------------------------------------
/hackernews-async-ts/README.md:
--------------------------------------------------------------------------------
1 | # hackernews-async-ts
2 |
3 | [Hacker News](https://news.ycombinator.com/) showcase using typescript && egg
4 |
5 | ## QuickStart
6 |
7 | ### Development
8 |
9 | ```bash
10 | $ npm i
11 | $ npm run dev
12 | $ open http://localhost:7001/
13 | ```
14 |
15 | Don't tsc compile at development mode, if you had run `tsc` then you need to `npm run clean` before `npm run dev`.
16 |
17 | ### Deploy
18 |
19 | ```bash
20 | $ npm run tsc
21 | $ npm start
22 | ```
23 |
24 | ### Npm Scripts
25 |
26 | - Use `npm run lint` to check code style
27 | - Use `npm test` to run unit test
28 | - se `npm run clean` to clean compiled js at development mode once
29 |
30 | ### Requirement
31 |
32 | - Node.js 16.x
33 | - Typescript 4.x
34 |
--------------------------------------------------------------------------------
/hackernews-async-ts/app/extend/filter.ts:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 |
3 | export function relativeTime(time) {
4 | return moment(new Date(time * 1000)).fromNow();
5 | }
6 |
7 | export function domain(url) {
8 | return url && url.split('/')[2];
9 | }
10 |
--------------------------------------------------------------------------------
/hackernews-async-ts/app/router.ts:
--------------------------------------------------------------------------------
1 | import { Application } from 'egg';
2 |
3 | export default (app: Application) => {
4 | const { controller, router } = app;
5 |
6 | router.redirect('/', '/news');
7 | router.get('/news', controller.news.list);
8 | router.get('/news/item/:id', controller.news.detail);
9 | router.get('/news/user/:id', controller.news.user);
10 | };
11 |
--------------------------------------------------------------------------------
/hackernews-async-ts/app/view/layout/layout.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {% block title %}egg - HackerNews{% endblock %}
9 |
10 |
11 |
12 |
19 | {% block content %}{% endblock %}
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/hackernews-async-ts/app/view/news/detail.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 |
6 | {% include "./item.tpl" %}
7 |
8 | {% if comments.length > 0%}
9 |
23 | {% else %}
24 |
No comments yet.
25 | {% endif %}
26 |
27 | {% endblock %}
--------------------------------------------------------------------------------
/hackernews-async-ts/app/view/news/item.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hackernews-async-ts/app/view/news/list.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 | {% for item in list %}
6 | {% set index = ((page-1) * pageSize + loop.index) %}
7 | {% include "./item.tpl" %}
8 | {% endfor %}
9 |
10 |
11 | {% if page > 1 %}
12 |
< prev
13 | {% endif %}
14 |
more...
15 |
16 |
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/hackernews-async-ts/app/view/news/user.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 | {% block title %}
3 | Profile: {{ user.id }} | egg - HackerNews
4 | {% endblock %}
5 | {% block content %}
6 |
23 | {% endblock %}
--------------------------------------------------------------------------------
/hackernews-async-ts/config/config.local.ts:
--------------------------------------------------------------------------------
1 | import { DefaultConfig } from './config.default';
2 |
3 | export default () => {
4 | const config: DefaultConfig = {};
5 | config.news = {
6 | pageSize: 20,
7 | };
8 | return config;
9 | };
10 |
--------------------------------------------------------------------------------
/hackernews-async-ts/config/config.prod.ts:
--------------------------------------------------------------------------------
1 | import { DefaultConfig } from './config.default';
2 |
3 | export default () => {
4 | const config: DefaultConfig = {};
5 | config.news = {
6 | pageSize: 30,
7 | };
8 | return config;
9 | };
10 |
--------------------------------------------------------------------------------
/hackernews-async-ts/config/plugin.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | nunjucks: {
3 | enable: true,
4 | package: 'egg-view-nunjucks',
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/hackernews-async-ts/test/app/service/News.test.ts:
--------------------------------------------------------------------------------
1 | import { strict as assert } from 'assert';
2 | import { Context } from 'egg';
3 | import { app } from 'egg-mock/bootstrap';
4 |
5 | describe('test/app/service/News.test.js', () => {
6 | let ctx: Context;
7 |
8 | before(() => {
9 | ctx = app.mockContext();
10 | });
11 |
12 | it('getTopStories', async () => {
13 | const list = await ctx.service.news.getTopStories();
14 | assert(list.length === 30);
15 | });
16 |
17 | it('getItem', async () => {
18 | const item = await ctx.service.news.getItem(1);
19 | assert(item.id && item.title && item.url);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/hackernews-async-ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@eggjs/tsconfig",
3 | "compilerOptions": {
4 | "declaration": false
5 | },
6 | "exclude": [
7 | "app/public",
8 | "app/views"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/hackernews-async/README.md:
--------------------------------------------------------------------------------
1 | See [cnode-api](https://github.com/eggjs/examples/tree/master/hackernews)
2 |
--------------------------------------------------------------------------------
/hackernews-datahub/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'ues strict';
2 |
3 | module.exports = {
4 | write: true,
5 | plugin: 'autod-egg',
6 | prefix: '^',
7 | devprefix: '^',
8 | exclude: [
9 | 'test/fixtures',
10 | ],
11 | dep: [
12 | 'egg',
13 | ],
14 | devdep: [
15 | 'autod',
16 | 'autod-egg',
17 | 'eslint',
18 | 'eslint-config-egg',
19 | 'egg-bin',
20 | ],
21 | keep: [
22 | ],
23 | semver: [
24 | ],
25 | test: 'scripts',
26 | };
27 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/controller/api.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class NewsController extends Controller {
6 | async list() {
7 | const { ctx, app } = this;
8 | const pageSize = app.config.news.pageSize;
9 | const page = parseInt(ctx.query.page) || 1;
10 |
11 | const idList = await ctx.service.hackerNews.getTopStories(page);
12 |
13 | ctx.body = {
14 | list: idList,
15 | page, pageSize,
16 | };
17 | }
18 | }
19 |
20 | module.exports = NewsController;
21 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/controller/news.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class NewsController extends Controller {
6 | async list() {
7 | const { ctx, app } = this;
8 | const pageSize = app.config.news.pageSize;
9 | const page = parseInt(ctx.query.page) || 1;
10 |
11 | const idList = await ctx.service.hackerNews.getTopStories(page);
12 | await ctx.render('news/list.tpl', {
13 | list: idList[0],
14 | page, pageSize,
15 | });
16 | }
17 | }
18 |
19 | module.exports = NewsController;
20 |
21 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/extend/filter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const moment = require('moment');
4 |
5 | exports.relativeTime = time => moment(new Date(time * 1000)).fromNow();
6 |
7 | exports.domain = url => url && url.split('/')[2];
8 |
9 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 | app.redirect('/', '/news');
6 | router.get('/news', controller.news.list);
7 | router.get('/api/news', controller.api.list);
8 | };
9 |
10 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/view/layout/layout.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {% block title %}egg - HackerNews{% endblock %}
9 |
10 |
11 |
12 |
19 | {% block content %}{% endblock %}
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/view/news/item.tpl:
--------------------------------------------------------------------------------
1 |
17 |
18 |
--------------------------------------------------------------------------------
/hackernews-datahub/app/view/news/list.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 | {% if list.length === 0 %}
6 |
empty
7 | {% endif %}
8 | {% for item in list %}
9 | {% set index = ((page-1) * pageSize + loop.index) %}
10 | {% include "./item.tpl" %}
11 | {% endfor %}
12 |
13 |
14 | {% if page > 1 %}
15 |
< prev
16 | {% endif %}
17 |
more...
18 |
19 |
20 | {% endblock %}
21 |
22 |
--------------------------------------------------------------------------------
/hackernews-datahub/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const datahubConfig = require('../macaca-datahub.config');
6 |
7 | module.exports = appInfo => {
8 | const config = {};
9 |
10 | // should change to your own
11 | config.keys = appInfo.name + '123456';
12 |
13 | config.siteFile = {
14 | '/favicon.ico': fs.readFileSync(path.join(appInfo.baseDir, 'app/public/favicon.png')),
15 | };
16 |
17 | const mockPort = datahubConfig.port;
18 | const hubName = 'hackernews';
19 |
20 | config.news = {
21 | pageSize: 30,
22 | serverUrl: process.env.MOCK
23 | ? `http://localhost:${mockPort}/data/${hubName}`
24 | : 'https://hacker-news.firebaseio.com/v0',
25 | };
26 |
27 | config.view = {
28 | defaultViewEngine: 'nunjucks',
29 | mapping: {
30 | '.tpl': 'nunjucks',
31 | '.nj': 'nunjucks',
32 | },
33 | };
34 |
35 | return config;
36 | };
37 |
38 |
--------------------------------------------------------------------------------
/hackernews-datahub/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.nunjucks = {
4 | enable: true,
5 | package: 'egg-view-nunjucks',
6 | };
7 |
8 |
--------------------------------------------------------------------------------
/hackernews-datahub/data/hackernews.json:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "hackernews",
3 | "description": "hackernews",
4 | "uniqId": "42ed34a4-723c-4056-a762-08b6a6cff2ae"
5 | }
--------------------------------------------------------------------------------
/hackernews-datahub/data/hackernews/hackernews_ALL_topstories.json.json:
--------------------------------------------------------------------------------
1 | {
2 | "protocol": "http",
3 | "pathname": "topstories.json",
4 | "method": "ALL",
5 | "projectUniqId": "42ed34a4-723c-4056-a762-08b6a6cff2ae",
6 | "description": "get top stories",
7 | "currentScene": "default",
8 | "proxyConfig": {
9 | "proxyList": []
10 | },
11 | "contextConfig": {},
12 | "uniqId": "cb8f0113-4bbc-4f29-97a1-7fc174a2f196"
13 | }
--------------------------------------------------------------------------------
/hackernews-datahub/data/hackernews/hackernews_ALL_topstories.json/scene/empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "sceneName": "empty",
3 | "data": {
4 | "list": [],
5 | "page": 1,
6 | "pageSize": 5
7 | },
8 | "interfaceUniqId": "cb8f0113-4bbc-4f29-97a1-7fc174a2f196",
9 | "uniqId": "f4c98bbd-01a1-42e8-8c49-470f551aaa59"
10 | }
--------------------------------------------------------------------------------
/hackernews-datahub/data/hackernews/hackernews_ALL_topstories.json/schema/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "request",
3 | "data": {
4 | "schemaData": {
5 | "type": "object",
6 | "required": [
7 | "page",
8 | "pageSize"
9 | ],
10 | "properties": {
11 | "page": {
12 | "type": "integer",
13 | "description": "current page"
14 | },
15 | "pageSize": {
16 | "type": "integer",
17 | "description": "page size"
18 | }
19 | }
20 | }
21 | },
22 | "interfaceUniqId": "cb8f0113-4bbc-4f29-97a1-7fc174a2f196",
23 | "uniqId": "5dfc02e0-2b04-4588-ad18-28e3ec4cdd39"
24 | }
--------------------------------------------------------------------------------
/hackernews-datahub/macaca-datahub.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | module.exports = {
6 | mode: 'local',
7 | port: 5678, // must be 5678, same with datahub-nodejs-sdk's default port
8 | store: path.resolve(__dirname, 'data'),
9 | };
10 |
--------------------------------------------------------------------------------
/hackernews-datahub/test/e2e/helper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const wd = require('macaca-wd');
4 |
5 | const {
6 | extendsMixIn,
7 | } = require('macaca-wd/lib/helper');
8 |
9 | extendsMixIn(wd);
10 |
11 | exports.driver = wd.promiseChainRemote({
12 | host: 'localhost',
13 | port: process.env.MACACA_SERVER_PORT || 3456,
14 | });
15 |
16 | exports.BASE_URL = 'http://127.0.0.1:7001/';
17 |
--------------------------------------------------------------------------------
/hackernews-datahub/test/e2e/mocha.opts:
--------------------------------------------------------------------------------
1 | --reporter macaca-reporter
2 | --require babel-register
3 | --recursive
4 | --timeout 60000
5 |
--------------------------------------------------------------------------------
/hackernews-datahub/test/unittest/app/controller/news.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { mock } = require('egg-mock/bootstrap');
4 |
5 | describe('test/app/controller/news.test.js', () => {
6 | let app;
7 | before(async () => {
8 | app = mock.app();
9 | await app.ready();
10 | });
11 |
12 | after(() => app.close());
13 |
14 | afterEach(mock.restore);
15 |
16 | it('should GET /news', async () => {
17 | await app.httpRequest().get('/news').expect(200);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/hackernews-datahub/test/unittest/app/service/HackerNews.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { mock, assert } = require('egg-mock/bootstrap');
4 |
5 | describe('test/unittest/app/service/HackerNews.test.js', () => {
6 | let app;
7 | let ctx;
8 |
9 | before(async () => {
10 | app = mock.app();
11 | await app.ready();
12 | ctx = app.mockContext();
13 | });
14 |
15 | after(() => app.close());
16 | afterEach(mock.restore);
17 |
18 | it('getTopStories', async () => {
19 | const list = await ctx.service.hackerNews.getTopStories();
20 | assert(list.length === 30);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/hackernews/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "eslint-config-egg"
4 | }
5 |
--------------------------------------------------------------------------------
/hackernews/app/extend/filter.js:
--------------------------------------------------------------------------------
1 | const moment = require('moment');
2 |
3 | exports.relativeTime = time => moment(new Date(time * 1000)).fromNow();
4 |
5 | exports.domain = url => url && url.split('/')[2];
6 |
--------------------------------------------------------------------------------
/hackernews/app/router.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const { router, controller } = app;
3 | app.redirect('/', '/news');
4 | router.get('/news', controller.news.list);
5 | router.get('/news/item/:id', controller.news.detail);
6 | router.get('/news/user/:id', controller.news.user);
7 | };
8 |
--------------------------------------------------------------------------------
/hackernews/app/view/layout/layout.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {% block title %}egg - HackerNews{% endblock %}
9 |
10 |
11 |
12 |
19 | {% block content %}{% endblock %}
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/hackernews/app/view/news/detail.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 |
6 | {% include "./item.tpl" %}
7 |
8 | {% if comments.length > 0%}
9 |
23 | {% else %}
24 |
No comments yet.
25 | {% endif %}
26 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/hackernews/app/view/news/item.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hackernews/app/view/news/list.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 |
3 | {% block content %}
4 |
5 | {% for item in list %}
6 | {% set index = ((page-1) * pageSize + loop.index) %}
7 | {% include "./item.tpl" %}
8 | {% endfor %}
9 |
10 |
11 | {% if page > 1 %}
12 |
< prev
13 | {% endif %}
14 |
more...
15 |
16 |
17 | {% endblock %}
--------------------------------------------------------------------------------
/hackernews/app/view/news/user.tpl:
--------------------------------------------------------------------------------
1 | {% extends "../layout/layout.tpl" %}
2 | {% block title %}
3 | Profile: {{ user.id }} | egg - HackerNews
4 | {% endblock %}
5 | {% block content %}
6 |
23 | {% endblock %}
--------------------------------------------------------------------------------
/hackernews/config/config.default.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | module.exports = appInfo => {
5 | const config = {};
6 |
7 | // should change to your own
8 | config.keys = appInfo.name + '123456';
9 |
10 | config.siteFile = {
11 | '/favicon.ico': fs.readFileSync(path.join(appInfo.baseDir, 'app/public/favicon.png')),
12 | };
13 |
14 | config.news = {
15 | pageSize: 30,
16 | serverUrl: 'https://hacker-news.firebaseio.com/v0',
17 | };
18 |
19 | config.view = {
20 | defaultViewEngine: 'nunjucks',
21 | mapping: {
22 | '.tpl': 'nunjucks',
23 | '.nj': 'nunjucks',
24 | },
25 | };
26 |
27 | return config;
28 | };
29 |
--------------------------------------------------------------------------------
/hackernews/config/plugin.js:
--------------------------------------------------------------------------------
1 | exports.nunjucks = {
2 | enable: true,
3 | package: 'egg-view-nunjucks',
4 | };
5 |
6 |
--------------------------------------------------------------------------------
/hackernews/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hackernews",
3 | "version": "1.0.0",
4 | "description": "hackernews showcase using async/await for egg",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^3.11.0",
8 | "egg-view-nunjucks": "^2.3.0",
9 | "moment": "^2.19.2"
10 | },
11 | "devDependencies": {
12 | "cheerio": "^1.0.0-rc.2",
13 | "egg-bin": "^5.9.0",
14 | "egg-mock": "^5.5.0",
15 | "eslint": "^8.31.0",
16 | "eslint-config-egg": "^12.1.0"
17 | },
18 | "engines": {
19 | "node": ">=16.0.0"
20 | },
21 | "scripts": {
22 | "dev": "egg-bin dev",
23 | "test": "npm run test-local",
24 | "test-local": "egg-bin test",
25 | "cov": "egg-bin cov",
26 | "lint": "eslint .",
27 | "ci": "npm run lint && npm run cov"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/hackernews/test/app/controller/news.test.js:
--------------------------------------------------------------------------------
1 | const cheerio = require('cheerio');
2 | const { app, assert } = require('egg-mock/bootstrap');
3 |
4 | describe('test/app/controller/news.test.js', () => {
5 | it('should GET /news', async () => {
6 | const result = await app.httpRequest().get('/news').expect(200);
7 | const $ = cheerio.load(result.text);
8 | const listItem = $('.news-view .item');
9 | assert.equal(listItem.length, app.config.news.pageSize);
10 | });
11 |
12 | it('should GET /news/item/:id', async () => {
13 | await app.httpRequest()
14 | .get('/news/item/1')
15 | .expect(/\/news\/item\/1/) // just a example, use regex to test part of dom string, but should be strong characteristic
16 | .expect(200);
17 | });
18 |
19 | it('should GET /news/user/:id', async () => {
20 | await app.httpRequest()
21 | .get('/news/user/activatedgeek')
22 | .expect(/user:<\/span> activatedgeek/) // just a example, use regex to test part of dom string, but should be strong characteristic
23 | .expect(200);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/hackernews/test/app/service/HackerNews.test.js:
--------------------------------------------------------------------------------
1 | const { app, assert, mock } = require('egg-mock/bootstrap');
2 |
3 | describe('test/app/service/HackerNews.test.js', () => {
4 | afterEach(mock.restore);
5 |
6 | it('getTopStories', async () => {
7 | const ctx = app.mockContext();
8 | const list = await ctx.service.hackerNews.getTopStories();
9 | assert.equal(list.length, 30);
10 | });
11 |
12 | it('getItem', async () => {
13 | const ctx = app.mockContext();
14 | const item = await ctx.service.hackerNews.getItem(1);
15 | assert(item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('url'));
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/hello-tegg/.eslintignore:
--------------------------------------------------------------------------------
1 | typings/
2 |
--------------------------------------------------------------------------------
/hello-tegg/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "eslint-config-egg/typescript"
4 | }
5 |
--------------------------------------------------------------------------------
/hello-tegg/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | node_modules/
4 | coverage/
5 | .idea/
6 | run/
7 | logs/
8 | .DS_Store
9 | .vscode
10 | *.swp
11 | *.lock
12 | *.js
13 |
14 | app/**/*.js
15 | test/**/*.js
16 | config/**/*.js
17 | app/**/*.map
18 | test/**/*.map
19 | config/**/*.map
20 | *.d.ts
21 | *.tsbuildinfo
22 |
--------------------------------------------------------------------------------
/hello-tegg/app/biz/HelloService.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AccessLevel,
3 | SingletonProto,
4 | } from '@eggjs/tegg';
5 |
6 | @SingletonProto({
7 | accessLevel: AccessLevel.PUBLIC,
8 | })
9 | export class HelloService {
10 | async hello(name: string): Promise {
11 | return `hello, ${name}`;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/hello-tegg/app/biz/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "biz-module",
3 | "eggModule": {
4 | "name": "biz"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/hello-tegg/app/controller/HelloController.ts:
--------------------------------------------------------------------------------
1 | import {
2 | HTTPController,
3 | HTTPMethod,
4 | HTTPMethodEnum,
5 | Context,
6 | EggContext,
7 | HTTPQuery,
8 | Middleware,
9 | Inject,
10 | } from '@eggjs/tegg';
11 | import { EggLogger } from 'egg';
12 | import { traceMethod } from 'app/middleware/trace_method';
13 | import { HelloService } from 'app/biz/HelloService';
14 |
15 | @HTTPController()
16 | @Middleware(traceMethod)
17 | export class HelloController {
18 | @Inject()
19 | private readonly helloService: HelloService;
20 |
21 | @Inject()
22 | private readonly logger: EggLogger;
23 |
24 | @HTTPMethod({
25 | method: HTTPMethodEnum.GET,
26 | path: '/hello',
27 | })
28 | async hello(@Context() ctx: EggContext, @HTTPQuery() name: string) {
29 | this.logger.info('access url: %s', ctx.url);
30 |
31 | const message = await this.helloService.hello(name);
32 |
33 | return {
34 | success: true,
35 | data: {
36 | message,
37 | },
38 | };
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/hello-tegg/app/middleware/trace_method.ts:
--------------------------------------------------------------------------------
1 | import { EggContext, Next } from '@eggjs/tegg';
2 |
3 | export async function traceMethod(ctx: EggContext, next: Next) {
4 | await next();
5 | ctx.body.data.message += ` (${ctx.method})`;
6 | }
7 |
--------------------------------------------------------------------------------
/hello-tegg/config/config.default.ts:
--------------------------------------------------------------------------------
1 | import { EggAppConfig, PowerPartial } from 'egg';
2 |
3 | export default (appInfo: EggAppConfig) => {
4 | const config = {} as PowerPartial;
5 |
6 | // override config from framework / plugin
7 | config.keys = appInfo.name + '123456';
8 |
9 | return config;
10 | };
11 |
--------------------------------------------------------------------------------
/hello-tegg/config/plugin.ts:
--------------------------------------------------------------------------------
1 | import { EggPlugin } from 'egg';
2 |
3 | const plugin: EggPlugin = {
4 | tegg: {
5 | enable: true,
6 | package: '@eggjs/tegg-plugin',
7 | },
8 | teggConfig: {
9 | enable: true,
10 | package: '@eggjs/tegg-config',
11 | },
12 | teggController: {
13 | enable: true,
14 | package: '@eggjs/tegg-controller-plugin',
15 | },
16 | };
17 |
18 | export default plugin;
19 |
--------------------------------------------------------------------------------
/hello-tegg/test/biz/HelloService.test.ts:
--------------------------------------------------------------------------------
1 | import { Context } from 'egg';
2 | import assert from 'assert';
3 | import { app } from 'egg-mock/bootstrap';
4 | import { HelloService } from '../../app/biz/HelloService';
5 |
6 | describe('test/biz/HelloService.test.ts', () => {
7 | let ctx: Context;
8 | let helloService: HelloService;
9 |
10 | beforeEach(async () => {
11 | ctx = await app.mockModuleContext();
12 | helloService = await ctx.getEggObject(HelloService);
13 | });
14 |
15 | afterEach(async () => {
16 | await app.destroyModuleContext(ctx);
17 | });
18 |
19 | it('should work', async () => {
20 | const msg = await helloService.hello('killa');
21 | assert(msg === 'hello, killa');
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/hello-tegg/test/controller/HelloController.test.ts:
--------------------------------------------------------------------------------
1 | import { app } from 'egg-mock/bootstrap';
2 | import assert from 'assert';
3 |
4 | describe('test/controller/HelloController.test.ts', () => {
5 | it('should work', async () => {
6 | await app.httpRequest()
7 | .get('/hello?name=killa')
8 | .expect(200)
9 | .expect(res => {
10 | assert.deepStrictEqual(res.body, {
11 | success: true,
12 | data: {
13 | message: 'hello, killa (GET)',
14 | },
15 | });
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/hello-tegg/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@eggjs/tsconfig",
3 | "compilerOptions": {
4 | "baseUrl": "./"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/helloworld/app/controller/foo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class FooController extends Controller {
6 | async render() {
7 | const ctx = this.ctx;
8 |
9 | ctx.body = 'Hello foo';
10 | }
11 | }
12 |
13 | module.exports = FooController;
14 |
--------------------------------------------------------------------------------
/helloworld/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async render() {
7 | const ctx = this.ctx;
8 |
9 | ctx.body = 'Hello World';
10 | }
11 | }
12 |
13 | module.exports = HomeController;
14 |
--------------------------------------------------------------------------------
/helloworld/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', app.controller.home.render);
5 | app.router.get('/foo', app.controller.foo.render);
6 | };
7 |
--------------------------------------------------------------------------------
/helloworld/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my secret keys';
4 |
--------------------------------------------------------------------------------
/helloworld/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "dev": "egg-bin dev",
12 | "test": "egg-bin test",
13 | "cov": "egg-bin cov"
14 | },
15 | "private": true
16 | }
17 |
--------------------------------------------------------------------------------
/helloworld/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('example helloworld test', () => {
7 | let app;
8 |
9 | before(() => {
10 | app = mm.app();
11 | return app.ready();
12 | });
13 |
14 | after(() => app.close());
15 |
16 | it('should GET / 200', () => {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(200)
20 | .expect('Hello World');
21 | });
22 |
23 | it('should GET /foo', () => {
24 | return app.httpRequest()
25 | .get('/foo')
26 | .expect(200)
27 | .expect('Hello foo');
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/httpclient/README.md:
--------------------------------------------------------------------------------
1 | # httpclient
2 |
3 | Example use on https://github.com/eggjs/egg/blob/master/docs/source/zh-cn/core/httpclient.md
4 |
--------------------------------------------------------------------------------
/httpclient/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.beforeStart(async () => {
5 | // 示例:启动的时候去读取 https://registry.npmjs.com/egg/latest 的版本信息
6 | const result = await app.curl('https://registry.npmjs.com/egg/latest', {
7 | dataType: 'json',
8 | });
9 | app.logger.info('egg latest version: %s', result.data.version);
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/httpclient/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', 'httpclient.home');
5 | app.router.get('/get', 'httpclient.get');
6 | app.router.get('/post', 'httpclient.post');
7 | app.router.get('/put', 'httpclient.put');
8 | app.router.get('/delete', 'httpclient.del');
9 | app.router.get('/form', 'httpclient.form');
10 | app.router.get('/multipart', 'httpclient.multipart');
11 | app.router.get('/files', 'httpclient.files');
12 | app.router.get('/stream', 'httpclient.stream');
13 | app.router.post('/stream', 'httpclient.postStream');
14 | app.router.get('/error', 'httpclient.error');
15 | };
16 |
--------------------------------------------------------------------------------
/httpclient/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.security = {
4 | csrf: false,
5 | };
6 |
--------------------------------------------------------------------------------
/httpclient/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "httpclient-example",
3 | "dependencies": {
4 | "egg": "^1.10.1",
5 | "formstream": "^1.1.0"
6 | },
7 | "devDependencies": {
8 | "egg-bin": "^4.3.5"
9 | },
10 | "scripts": {
11 | "start": "egg-bin dev",
12 | "dev": "egg-bin dev"
13 | },
14 | "private": true
15 | }
16 |
--------------------------------------------------------------------------------
/ipc/README.md:
--------------------------------------------------------------------------------
1 | # IPC
2 |
3 | Suppose we want to cache a remote data source in memory, we implement three different ways to update cache.
4 |
5 | 1. Force all workers update memory cache from remote with a long interval.
6 | 2. Check remote source if it is changed, and then update cache. Check action can be more frequently if the source don't change everytime.
7 | 3. Subscribe the remote source, do update when received data source changed. Need a subscriber.
8 |
9 | We'll combine schedule and IPC to implement these features.
10 |
11 | ## start
12 |
13 | ```bash
14 | $ npm start
15 | ```
16 |
17 | It will start app with two workers when you run this command.
18 |
--------------------------------------------------------------------------------
/ipc/agent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Subscriber = require('./lib/subscriber');
4 |
5 | module.exports = agent => {
6 | agent.logger.info('init subscriber');
7 | const subscriber = new Subscriber();
8 | subscriber.on('changed', () => agent.messenger.sendToApp('refresh', 'push'));
9 | subscriber.on('error', err => agent.logger.error(err));
10 | };
11 |
--------------------------------------------------------------------------------
/ipc/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.beforeStart(async () => {
5 | // ensure memory cache exists before app ready
6 | await app.runSchedule('force_refresh');
7 | });
8 |
9 | const { messenger } = app;
10 |
11 | messenger.on('refresh', by => {
12 | app.logger.info('start update by %s', by);
13 | // create an anonymous context to access service
14 | const ctx = app.createAnonymousContext();
15 | // a convenient way to excute with generator function
16 | // can replaced by `co`
17 | ctx.runInBackground(async () => {
18 | await ctx.service.source.update();
19 | app.lastUpdateBy = by;
20 | });
21 | });
22 | };
23 |
--------------------------------------------------------------------------------
/ipc/app/controller/api.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Api extends Controller {
6 | index() {
7 | const { ctx, service } = this;
8 | ctx.body = {
9 | index: service.source.get('index'),
10 | lastUpdateBy: ctx.app.lastUpdateBy,
11 | };
12 | }
13 | }
14 |
15 | module.exports = Api;
16 |
--------------------------------------------------------------------------------
/ipc/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', 'api.index');
5 | };
6 |
--------------------------------------------------------------------------------
/ipc/app/schedule/force_refresh.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.schedule = {
4 | interval: '10m',
5 | type: 'all', // run in all workers
6 | };
7 |
8 | exports.task = async function(ctx) {
9 | await ctx.service.source.update();
10 | ctx.app.lastUpdateBy = 'force';
11 | };
12 |
--------------------------------------------------------------------------------
/ipc/app/schedule/pull_refresh.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.schedule = {
4 | interval: '10s',
5 | type: 'worker', // only run in one worker
6 | };
7 |
8 | exports.task = async function(ctx) {
9 | const needRefresh = await ctx.service.source.checkUpdate();
10 | if (!needRefresh) return;
11 |
12 | // notify all workers to update memory cache from `file`
13 | ctx.app.messenger.sendToApp('refresh', 'pull');
14 | };
15 |
--------------------------------------------------------------------------------
/ipc/app/service/source.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const sleep = require('mz-modules/sleep');
4 | const Service = require('egg').Service;
5 |
6 | let memoryCache = {};
7 |
8 | class Source extends Service {
9 |
10 | get(key) {
11 | return memoryCache[key];
12 | }
13 |
14 | async checkUpdate() {
15 | // check if remote data source has changed
16 | const updated = await mockCheck();
17 | this.ctx.logger.info('check update response %s', updated);
18 | return updated;
19 | }
20 |
21 | async update() {
22 | // update memory cache from remote
23 | memoryCache = await mockFetch();
24 | this.ctx.logger.info('update memory cache from remote: %j', memoryCache);
25 | }
26 | }
27 |
28 | module.exports = Source;
29 |
30 | let index = 0;
31 | async function mockFetch() {
32 | await sleep(100);
33 | return {
34 | index: index++,
35 | };
36 | }
37 |
38 | async function mockCheck() {
39 | await sleep(100);
40 | return Math.random() > 0.5;
41 | }
42 |
--------------------------------------------------------------------------------
/ipc/lib/subscriber.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EventEmitter = require('events');
4 |
5 | /**
6 | * A mock Subscriber
7 | */
8 | module.exports = class Subscriber extends EventEmitter {
9 | constructor() {
10 | super();
11 |
12 | this._start();
13 | }
14 |
15 | _start() {
16 | const interval = Math.random() * 5000 + 5000;
17 | setTimeout(() => {
18 | this.emit('changed');
19 | this._start();
20 | }, interval);
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/ipc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ipc",
3 | "version": "1.0.0",
4 | "description": "egg ipc example",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^1.10.1",
8 | "mz-modules": "^2.0.0"
9 | },
10 | "devDependencies": {
11 | "egg-bin": "^4.3.5"
12 | },
13 | "engines": {
14 | "node": ">=8.9.0"
15 | },
16 | "scripts": {
17 | "dev": "egg-bin dev",
18 | "lint": "eslint .",
19 | "autod": "autod"
20 | },
21 | "author": "dead-horse",
22 | "license": "MIT"
23 | }
24 |
--------------------------------------------------------------------------------
/middleware/app/middleware/hello.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 |
5 | module.exports = (options, app) => {
6 | return async function(ctx, next) {
7 | assert.deepEqual(options, app.config.hello);
8 | ctx.body = options.text;
9 | await next();
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/middleware/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my super cool keys';
4 |
5 | exports.middleware = [
6 | 'hello',
7 | ];
8 |
9 | exports.hello = {
10 | text: 'Hello World',
11 | };
12 |
--------------------------------------------------------------------------------
/middleware/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "middleware-example",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "dev": "egg-bin dev",
12 | "test": "egg-bin test",
13 | "cov": "egg-bin cov"
14 | },
15 | "private": true
16 | }
17 |
--------------------------------------------------------------------------------
/middleware/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('example middleware test', () => {
7 | let app;
8 |
9 | before(() => {
10 | app = mm.app();
11 | return app.ready();
12 | });
13 |
14 | after(() => app.close());
15 |
16 | it('should GET / 200', () => {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(200)
20 | .expect(app.config.hello.text);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/multipart-file-mode/.gitignore:
--------------------------------------------------------------------------------
1 | upload_dirs
2 | !upload_dirs/keepit
3 | app/public
4 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/controller/ajax.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const { pipeline } = require('stream/promises');
4 | const Controller = require('egg').Controller;
5 |
6 | module.exports = class extends Controller {
7 | async show() {
8 | await this.ctx.render('page/ajax.html');
9 | }
10 |
11 | async upload() {
12 | const { ctx } = this;
13 | const file = ctx.request.files[0];
14 | if (!file) return ctx.throw(404);
15 |
16 | const filename = encodeURIComponent(ctx.request.body.name) + path.extname(file.filename).toLowerCase();
17 | const targetPath = path.join(this.config.baseDir, 'app/public', filename);
18 | const source = fs.createReadStream(file.filepath);
19 | const target = fs.createWriteStream(targetPath);
20 |
21 | try {
22 | await pipeline(source, target);
23 | ctx.logger.warn('save %s to %s', file.filepath, targetPath);
24 | } finally {
25 | // delete those request tmp files
26 | await ctx.cleanupRequestFiles();
27 | }
28 |
29 | ctx.body = { url: '/public/' + filename };
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/controller/form.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const { pipeline } = require('stream/promises');
4 | const Controller = require('egg').Controller;
5 |
6 | module.exports = class extends Controller {
7 | async show() {
8 | await this.ctx.render('page/form.html');
9 | }
10 |
11 | async upload() {
12 | const { ctx } = this;
13 | const file = ctx.request.files[0];
14 | if (!file) return ctx.throw(404);
15 |
16 | const filename = encodeURIComponent(ctx.request.body.name) + path.extname(file.filename).toLowerCase();
17 | const targetPath = path.join(this.config.baseDir, 'app/public', filename);
18 | const source = fs.createReadStream(file.filepath);
19 | const target = fs.createWriteStream(targetPath);
20 |
21 | try {
22 | await pipeline(source, target);
23 | ctx.logger.warn('save %s to %s', file.filepath, targetPath);
24 | } finally {
25 | // delete those request tmp files
26 | await ctx.cleanupRequestFiles();
27 | }
28 |
29 | ctx.redirect('/public/' + filename);
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/controller/home.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller;
2 |
3 | module.exports = class extends Controller {
4 | async render() {
5 | await this.ctx.render('index.html');
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/router.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | app.router.get('/', 'home.render');
3 |
4 | app.router.get('/ajax', app.controller.ajax.show);
5 | app.router.post('/ajax', app.controller.ajax.upload);
6 |
7 | app.router.get('/form', app.controller.form.show);
8 | app.router.post('/form', app.controller.form.upload);
9 |
10 | app.router.get('/multiple-file', app.controller.multiple.show);
11 | app.router.post('/multiple-file', app.controller.multiple.upload);
12 | };
13 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/view/index.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 | Upload
4 |
9 | {% endblock %}
10 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {% block content %}
8 | {% endblock %}
9 |
10 |
11 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/view/page/form.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% block content %}
4 | Upload Image
5 |
12 | {% endblock %}
13 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/view/page/multiple.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 | Upload Image
4 |
14 | {% endblock %}
15 |
--------------------------------------------------------------------------------
/multipart-file-mode/app/view/page/multiple_result.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 | Upload Result
4 |
5 | {% for field in fields %}
6 | - {{ field.key }}: {{ field.value }}
7 | {% endfor %}
8 |
9 | {% for file in files %}
10 | - {{ file.filename }}
11 | {% endfor %}
12 |
13 | {% endblock %}
14 |
--------------------------------------------------------------------------------
/multipart-file-mode/config/config.default.js:
--------------------------------------------------------------------------------
1 | exports.keys = 'my keys';
2 |
3 | exports.view = {
4 | defaultViewEngine: 'nunjucks',
5 | };
6 |
7 | exports.multipart = {
8 | mode: 'file',
9 | };
10 |
--------------------------------------------------------------------------------
/multipart-file-mode/config/plugin.js:
--------------------------------------------------------------------------------
1 | exports.nunjucks = {
2 | enable: true,
3 | package: 'egg-view-nunjucks',
4 | };
5 |
--------------------------------------------------------------------------------
/multipart-file-mode/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multipart-file-mode-example",
3 | "dependencies": {
4 | "egg": "^3.11.0",
5 | "egg-view-nunjucks": "^2.3.0"
6 | },
7 | "devDependencies": {
8 | "egg-bin": "^5.9.0",
9 | "egg-mock": "^5.5.0"
10 | },
11 | "scripts": {
12 | "dev": "egg-bin dev",
13 | "test": "egg-bin test",
14 | "cov": "egg-bin cov"
15 | },
16 | "private": true
17 | }
18 |
--------------------------------------------------------------------------------
/multipart-file-mode/test/kfc.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggjs/examples/5ea83ef36dede99ae057adfb6972c5086d8d2e4c/multipart-file-mode/test/kfc.jpeg
--------------------------------------------------------------------------------
/multipart-file-mode/test/mc.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggjs/examples/5ea83ef36dede99ae057adfb6972c5086d8d2e4c/multipart-file-mode/test/mc.jpeg
--------------------------------------------------------------------------------
/multipart/.gitignore:
--------------------------------------------------------------------------------
1 | upload_dirs
2 | !upload_dirs/keepit
3 | app/public
4 |
--------------------------------------------------------------------------------
/multipart/app/controller/ajax.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const { pipeline } = require('stream/promises');
4 | const Controller = require('egg').Controller;
5 |
6 | class UploadAjaxController extends Controller {
7 | async show() {
8 | await this.ctx.render('page/ajax.html');
9 | }
10 |
11 | async upload() {
12 | const stream = await this.ctx.getFileStream();
13 | const filename = encodeURIComponent(stream.fields.name) + path.extname(stream.filename).toLowerCase();
14 | const target = path.join(this.config.baseDir, 'app/public', filename);
15 | const writeStream = fs.createWriteStream(target);
16 | await pipeline(stream, writeStream);
17 |
18 | this.ctx.body = { url: '/public/' + filename };
19 | }
20 | }
21 |
22 | module.exports = UploadAjaxController;
23 |
--------------------------------------------------------------------------------
/multipart/app/controller/buffer.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const Controller = require('egg').Controller;
4 | const toArray = require('stream-to-array');
5 | const sendToWormhole = require('stream-wormhole');
6 |
7 | class UploadBufferController extends Controller {
8 | async show() {
9 | await this.ctx.render('page/buffer.html');
10 | }
11 |
12 | async upload() {
13 | const stream = await this.ctx.getFileStream();
14 | let buf;
15 | try {
16 | const parts = await toArray(stream);
17 | buf = Buffer.concat(parts);
18 | } catch (err) {
19 | await sendToWormhole(stream);
20 | throw err;
21 | }
22 |
23 | const filename = encodeURIComponent(stream.fields.name) + path.extname(stream.filename).toLowerCase();
24 | const target = path.join(this.config.baseDir, 'app/public', filename);
25 | await fs.writeFile(target, buf);
26 |
27 | this.ctx.redirect('/public/' + filename);
28 | }
29 | }
30 |
31 | module.exports = UploadBufferController;
32 |
--------------------------------------------------------------------------------
/multipart/app/controller/form.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const { pipeline } = require('stream/promises');
4 | const Controller = require('egg').Controller;
5 |
6 | class UploadFormController extends Controller {
7 | async show() {
8 | await this.ctx.render('page/form.html');
9 | }
10 |
11 | async upload() {
12 | const stream = await this.ctx.getFileStream();
13 | const filename = encodeURIComponent(stream.fields.name) + path.extname(stream.filename).toLowerCase();
14 | const target = path.join(this.config.baseDir, 'app/public', filename);
15 | const writeStream = fs.createWriteStream(target);
16 | await pipeline(stream, writeStream);
17 | this.ctx.redirect('/public/' + filename);
18 | }
19 | }
20 |
21 | module.exports = UploadFormController;
22 |
--------------------------------------------------------------------------------
/multipart/app/controller/home.js:
--------------------------------------------------------------------------------
1 | const Controller = require('egg').Controller;
2 |
3 | class HomeController extends Controller {
4 |
5 | async render() {
6 | await this.ctx.render('index.html');
7 | }
8 |
9 | }
10 |
11 | module.exports = HomeController;
12 |
--------------------------------------------------------------------------------
/multipart/app/controller/multiple.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const { pipeline } = require('stream/promises');
4 | const Controller = require('egg').Controller;
5 |
6 | class UploadMultipleController extends Controller {
7 | async show() {
8 | await this.ctx.render('page/multiple.html');
9 | }
10 |
11 | async upload() {
12 | const parts = this.ctx.multipart({ autoFields: true });
13 | const files = [];
14 |
15 | let stream;
16 | while ((stream = await parts()) != null) {
17 | const filename = stream.filename.toLowerCase();
18 | const target = path.join(this.config.baseDir, 'app/public', filename);
19 | const writeStream = fs.createWriteStream(target);
20 | await pipeline(stream, writeStream);
21 | files.push(filename);
22 | }
23 |
24 | await this.ctx.render('page/multiple_result.html', {
25 | fields: Object.keys(parts.field).map(key => ({ key, value: parts.field[key] })),
26 | files,
27 | });
28 | }
29 | }
30 |
31 | module.exports = UploadMultipleController;
32 |
--------------------------------------------------------------------------------
/multipart/app/router.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | app.router.get('/', 'home.render');
3 |
4 | app.router.get('/ajax', app.controller.ajax.show);
5 | app.router.post('/ajax', app.controller.ajax.upload);
6 |
7 | app.router.get('/form', app.controller.form.show);
8 | app.router.post('/form', app.controller.form.upload);
9 |
10 | app.router.get('/multiple-file', app.controller.multiple.show);
11 | app.router.post('/multiple-file', app.controller.multiple.upload);
12 |
13 | app.router.get('/buffer', app.controller.buffer.show);
14 | app.router.post('/buffer', app.controller.buffer.upload);
15 | };
16 |
--------------------------------------------------------------------------------
/multipart/app/view/index.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 | Upload
4 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/multipart/app/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {% block content %}
8 | {% endblock %}
9 |
10 |
11 |
--------------------------------------------------------------------------------
/multipart/app/view/page/buffer.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% block content %}
4 | Upload Image
5 |
12 | {% endblock %}
13 |
--------------------------------------------------------------------------------
/multipart/app/view/page/form.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% block content %}
4 | Upload Image
5 |
12 | {% endblock %}
13 |
--------------------------------------------------------------------------------
/multipart/app/view/page/multiple.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 | Upload Image
4 |
14 | {% endblock %}
15 |
--------------------------------------------------------------------------------
/multipart/app/view/page/multiple_result.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 | Upload Result
4 |
5 | {% for field in fields %}
6 | - {{ field.key }}: {{ field.value }}
7 | {% endfor %}
8 |
9 | {% for file in files %}
10 | - {{ file }}
11 | {% endfor %}
12 |
13 | {% endblock %}
14 |
--------------------------------------------------------------------------------
/multipart/config/config.default.js:
--------------------------------------------------------------------------------
1 | exports.keys = 'my keys';
2 |
3 | exports.view = {
4 | defaultViewEngine: 'nunjucks',
5 | };
6 |
--------------------------------------------------------------------------------
/multipart/config/plugin.js:
--------------------------------------------------------------------------------
1 | exports.nunjucks = {
2 | enable: true,
3 | package: 'egg-view-nunjucks',
4 | };
5 |
--------------------------------------------------------------------------------
/multipart/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multipart-example",
3 | "dependencies": {
4 | "egg": "^3.11.0",
5 | "egg-view-nunjucks": "^2.3.0",
6 | "stream-to-array": "^2.3.0",
7 | "stream-wormhole": "^1.0.4"
8 | },
9 | "devDependencies": {
10 | "egg-bin": "^5.9.0",
11 | "egg-mock": "^5.5.0"
12 | },
13 | "scripts": {
14 | "dev": "egg-bin dev",
15 | "test": "egg-bin test",
16 | "cov": "egg-bin cov"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/multipart/test/kfc.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggjs/examples/5ea83ef36dede99ae057adfb6972c5086d8d2e4c/multipart/test/kfc.jpeg
--------------------------------------------------------------------------------
/multipart/test/mc.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggjs/examples/5ea83ef36dede99ae057adfb6972c5086d8d2e4c/multipart/test/mc.jpeg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egg-examples",
3 | "version": "1.0.0",
4 | "description": "Application examples for egg",
5 | "keywords": [
6 | "application",
7 | "egg"
8 | ],
9 | "devDependencies": {
10 | "chalk": "^1.1.3",
11 | "common-bin": "^2.7.1",
12 | "globby": "^6.1.0",
13 | "npminstall": "^6.6.2",
14 | "runscript": "^1.5.3",
15 | "semver": "^5.3.0"
16 | },
17 | "scripts": {
18 | "lint": "echo 'ignore'",
19 | "test": "./example.js test",
20 | "test-cn": "./example.js test -c",
21 | "ci": "npm run lint && npm test",
22 | "list": "./example.js list"
23 | },
24 | "homepage": "https://github.com/eggjs/examples",
25 | "repository": {
26 | "type": "git",
27 | "url": "https://github.com/eggjs/examples.git"
28 | },
29 | "bugs": {
30 | "url": "https://github.com/eggjs/egg/issues"
31 | },
32 | "engines": {
33 | "node": ">= 14.17.0"
34 | },
35 | "license": "MIT",
36 | "private": true
37 | }
38 |
--------------------------------------------------------------------------------
/passport/.gitignore:
--------------------------------------------------------------------------------
1 | config/config.local.js
2 |
--------------------------------------------------------------------------------
/passport/README.md:
--------------------------------------------------------------------------------
1 | # egg-passport example
2 |
3 | - Index: http://127.0.0.1:7001/
4 | - Auth Strategies
5 | - Weibo: http://127.0.0.1:7001/passport/weibo
6 | - GitHub: http://127.0.0.1:7001/passport/github
7 | - Bitbucket: http://127.0.0.1:7001/passport/bitbucket
8 | - Twitter: http://127.0.0.1:7001/passport/twitter
9 | - YuQue: http://127.0.0.1:7001/passport/yuque
10 |
--------------------------------------------------------------------------------
/passport/app/controller/user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class UserController extends Controller {
6 | async logout() {
7 | const ctx = this.ctx;
8 |
9 | ctx.logout();
10 | ctx.redirect(ctx.get('referer') || '/');
11 | }
12 | }
13 |
14 | module.exports = UserController;
15 |
--------------------------------------------------------------------------------
/passport/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', 'home.render');
5 | app.router.get('/user', 'home.render');
6 |
7 | app.passport.mount('weibo');
8 | app.passport.mount('github');
9 | app.passport.mount('bitbucket');
10 | app.passport.mount('twitter');
11 | app.passport.mount('yuque');
12 |
13 | app.router.get('/logout', 'user.logout');
14 | };
15 |
--------------------------------------------------------------------------------
/passport/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = '123456';
4 |
5 | // secure keys on https://github.com/eggjs/egg/wiki#secure-env-for-travis-ci
6 | exports.passportWeibo = {
7 | key: 'a',
8 | secret: 'b',
9 | };
10 |
11 | exports.passportGithub = {
12 | key: 'c',
13 | secret: 'd',
14 | };
15 |
16 | exports.passportBitbucket = {
17 | key: 'e',
18 | secret: 'f',
19 | };
20 |
21 | exports.passportTwitter = {
22 | key: 'g',
23 | secret: 'h',
24 | };
25 |
26 | exports.passportYuque = {
27 | key: process.env.EGG_PASSPORT_YUQUE_CLIENT_ID || 'i',
28 | secret: process.env.EGG_PASSPORT_YUQUE_CLIENT_SECRET || 'j',
29 | };
30 |
--------------------------------------------------------------------------------
/passport/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.passport = {
4 | enable: true,
5 | package: 'egg-passport',
6 | };
7 |
8 | exports.passportWeibo = {
9 | enable: true,
10 | package: 'egg-passport-weibo',
11 | };
12 |
13 | exports.passportTwitter = {
14 | enable: true,
15 | package: 'egg-passport-twitter',
16 | };
17 |
18 | exports.passportGithub = {
19 | enable: true,
20 | package: 'egg-passport-github',
21 | };
22 |
23 | exports.passportBitbucket = {
24 | enable: true,
25 | package: 'egg-passport-bitbucket',
26 | };
27 |
28 | exports.passportYuque = {
29 | enable: true,
30 | package: 'egg-passport-yuque',
31 | };
32 |
--------------------------------------------------------------------------------
/passport/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "passport",
3 | "dependencies": {
4 | "egg": "^1.10.1",
5 | "egg-passport": "^1.0.0",
6 | "egg-passport-bitbucket": "^1.0.0",
7 | "egg-passport-github": "^1.0.0",
8 | "egg-passport-twitter": "^1.0.0",
9 | "egg-passport-weibo": "^1.0.0",
10 | "egg-passport-yuque": "^1.0.0"
11 | },
12 | "devDependencies": {
13 | "egg-bin": "^4.3.5"
14 | },
15 | "scripts": {
16 | "dev": "egg-bin dev",
17 | "cov": "egg-bin cov"
18 | },
19 | "private": true
20 | }
21 |
--------------------------------------------------------------------------------
/progressive/step1/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async isIOS() {
7 | this.ctx.body = `isIOS: ${this.ctx.isIOS}`;
8 | }
9 | }
10 |
11 | module.exports = Home;
12 |
--------------------------------------------------------------------------------
/progressive/step1/app/extend/context.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | get isIOS() {
5 | const iosReg = /iphone|ipad|ipod/i;
6 | return iosReg.test(this.get('user-agent'));
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/progressive/step1/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 | router.get('/', controller.home.isIOS);
6 | };
7 |
--------------------------------------------------------------------------------
/progressive/step1/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "progressive",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "egg": "^2.0.0"
7 | },
8 | "devDependencies": {
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "scripts": {
13 | "dev": "egg-bin dev",
14 | "test": "egg-bin test",
15 | "cov": "egg-bin cov"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/progressive/step1/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { app } = require('egg-mock/bootstrap');
5 |
6 | describe('test/index.test.js', () => {
7 |
8 | it('should GET / with iOS', () => {
9 | return app.httpRequest()
10 | .get('/')
11 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
12 | .expect(200)
13 | .expect('isIOS: true');
14 | });
15 |
16 | it('should GET / with non iOS', () => {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(200)
20 | .expect('isIOS: false');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/progressive/step2/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async isIOS() {
7 | this.ctx.body = `isIOS: ${this.ctx.isIOS}`;
8 | }
9 | }
10 |
11 | module.exports = Home;
12 |
--------------------------------------------------------------------------------
/progressive/step2/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 | router.get('/', controller.home.isIOS);
6 | };
7 |
--------------------------------------------------------------------------------
/progressive/step2/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step2/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | exports.ua = {
6 | enable: true,
7 | path: path.join(__dirname, '../lib/plugin/egg-ua'),
8 | };
9 |
--------------------------------------------------------------------------------
/progressive/step2/lib/plugin/egg-ua/app/extend/context.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | get isIOS() {
5 | const iosReg = /iphone|ipad|ipod/i;
6 | return iosReg.test(this.get('user-agent'));
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/progressive/step2/lib/plugin/egg-ua/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "eggPlugin": {
3 | "name": "ua"
4 | }
5 | }
--------------------------------------------------------------------------------
/progressive/step2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "progressive",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "egg": "^2.0.0"
7 | },
8 | "devDependencies": {
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "scripts": {
13 | "dev": "egg-bin dev",
14 | "test": "egg-bin test",
15 | "cov": "egg-bin cov"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/progressive/step2/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { app } = require('egg-mock/bootstrap');
5 |
6 | describe('test/index.test.js', () => {
7 |
8 | it('should GET / with iOS', () => {
9 | return app.httpRequest()
10 | .get('/')
11 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
12 | .expect(200)
13 | .expect('isIOS: true');
14 | });
15 |
16 | it('should GET / with non iOS', () => {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(200)
20 | .expect('isIOS: false');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/progressive/step3/egg-ua/app/extend/context.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | get isIOS() {
5 | const iosReg = /iphone|ipad|ipod/i;
6 | return iosReg.test(this.get('user-agent'));
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/progressive/step3/egg-ua/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egg-ua",
3 | "version": "1.0.0",
4 | "eggPlugin": {
5 | "name": "ua"
6 | },
7 | "devDependencies": {
8 | "egg": "^2.0.0",
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "scripts": {
13 | "dev": "egg-bin dev",
14 | "test": "egg-bin test",
15 | "cov": "egg-bin cov"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/progressive/step3/egg-ua/test/fixtures/test-app/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', async function() {
5 | this.body = `isIOS: ${this.isIOS}`;
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/progressive/step3/egg-ua/test/fixtures/test-app/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step3/egg-ua/test/fixtures/test-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test-app",
3 | "version": "1.0.0"
4 | }
5 |
--------------------------------------------------------------------------------
/progressive/step3/egg-ua/test/ua.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('test/ua.test.js', () => {
7 | let app;
8 |
9 | before(() => {
10 | app = mm.app({
11 | baseDir: 'test-app',
12 | });
13 | return app.ready();
14 | });
15 |
16 | after(() => app.close());
17 | afterEach(mm.restore);
18 |
19 | it('should GET / with iOS', () => {
20 | return app.httpRequest()
21 | .get('/')
22 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
23 | .expect(200)
24 | .expect('isIOS: true');
25 | });
26 |
27 | it('should GET / with non iOS', () => {
28 | return app.httpRequest()
29 | .get('/')
30 | .expect(200)
31 | .expect('isIOS: false');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/progressive/step3/example-app/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async isIOS() {
7 | this.ctx.body = `isIOS: ${this.ctx.isIOS}`;
8 | }
9 | }
10 |
11 | module.exports = Home;
12 |
--------------------------------------------------------------------------------
/progressive/step3/example-app/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 | router.get('/', controller.home.isIOS);
6 | };
7 |
--------------------------------------------------------------------------------
/progressive/step3/example-app/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step3/example-app/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.ua = {
4 | enable: true,
5 | package: 'egg-ua',
6 | };
7 |
--------------------------------------------------------------------------------
/progressive/step3/example-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "progressive",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "egg": "^1.0.0",
7 | "egg-ua": "../egg-ua"
8 | },
9 | "devDependencies": {
10 | "egg-bin": "^4.3.5",
11 | "egg-mock": "^3.13.1"
12 | },
13 | "scripts": {
14 | "dev": "egg-bin dev",
15 | "test": "egg-bin test",
16 | "cov": "egg-bin cov"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/progressive/step3/example-app/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { app } = require('egg-mock/bootstrap');
5 |
6 | describe('test/index.test.js', () => {
7 |
8 | it('should GET / with iOS', () => {
9 | return app.httpRequest()
10 | .get('/')
11 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
12 | .expect(200)
13 | .expect('isIOS: true');
14 | });
15 |
16 | it('should GET / with non iOS', () => {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(200)
20 | .expect('isIOS: false');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/progressive/step4/egg-ua/app/extend/context.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | get isIOS() {
5 | const iosReg = /iphone|ipad|ipod/i;
6 | return iosReg.test(this.get('user-agent'));
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/progressive/step4/egg-ua/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egg-ua",
3 | "version": "1.0.0",
4 | "eggPlugin": {
5 | "name": "ua"
6 | },
7 | "devDependencies": {
8 | "egg": "^1.0.0",
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "scripts": {
13 | "dev": "egg-bin dev",
14 | "test": "egg-bin test",
15 | "cov": "egg-bin cov"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/progressive/step4/egg-ua/test/fixtures/test-app/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', async function() {
5 | this.body = `isIOS: ${this.isIOS}`;
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/progressive/step4/egg-ua/test/fixtures/test-app/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step4/egg-ua/test/fixtures/test-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test-app",
3 | "version": "1.0.0"
4 | }
5 |
--------------------------------------------------------------------------------
/progressive/step4/egg-ua/test/ua.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('test/ua.test.js', () => {
7 | let app;
8 |
9 | before(() => {
10 | app = mm.app({
11 | baseDir: 'test-app',
12 | });
13 | return app.ready();
14 | });
15 |
16 | after(() => app.close());
17 | afterEach(mm.restore);
18 |
19 | it('should GET / with iOS', () => {
20 | return app.httpRequest()
21 | .get('/')
22 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
23 | .expect(200)
24 | .expect('isIOS: true');
25 | });
26 |
27 | it('should GET / with non iOS', () => {
28 | return app.httpRequest()
29 | .get('/')
30 | .expect(200)
31 | .expect('isIOS: false');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/progressive/step4/example-app/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('example-framework').Controller;
4 |
5 | class Home extends Controller {
6 | async isIOS() {
7 | this.ctx.body = `isIOS: ${this.ctx.isIOS}`;
8 | }
9 |
10 | async getFramework() {
11 | this.ctx.body = this.ctx.app.config.framework.name;
12 | }
13 | }
14 |
15 | module.exports = Home;
16 |
--------------------------------------------------------------------------------
/progressive/step4/example-app/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 | router.get('/', controller.home.isIOS);
6 | router.get('/framework', controller.home.getFramework);
7 | };
8 |
--------------------------------------------------------------------------------
/progressive/step4/example-app/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step4/example-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "progressive",
3 | "version": "1.0.0",
4 | "private": true,
5 | "egg": {
6 | "framework": "example-framework"
7 | },
8 | "dependencies": {
9 | "example-framework": "../example-framework"
10 | },
11 | "devDependencies": {
12 | "egg-bin": "^4.3.5",
13 | "egg-mock": "^3.13.1"
14 | },
15 | "scripts": {
16 | "dev": "egg-bin dev",
17 | "test": "egg-bin test",
18 | "cov": "egg-bin cov"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/progressive/step4/example-app/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { app } = require('egg-mock/bootstrap');
5 |
6 | describe('test/index.test.js', () => {
7 |
8 | it('should use custom framework', () => {
9 | return app.httpRequest()
10 | .get('/framework')
11 | .expect(200)
12 | .expect('example-framework');
13 | });
14 |
15 | it('should GET / with iOS', () => {
16 | return app.httpRequest()
17 | .get('/')
18 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
19 | .expect(200)
20 | .expect('isIOS: true');
21 | });
22 |
23 | it('should GET / with non iOS', () => {
24 | return app.httpRequest()
25 | .get('/')
26 | .expect(200)
27 | .expect('isIOS: false');
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.framework = {
4 | name: 'example-framework',
5 | };
6 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.ua = {
4 | enable: true,
5 | package: 'egg-ua',
6 | };
7 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Application = require('./lib/application');
4 | const Agent = require('./lib/agent');
5 | const egg = require('egg');
6 |
7 | // clone egg API
8 | Object.assign(exports, egg);
9 |
10 | // override Application and Agent
11 | exports.Application = Application;
12 | exports.Agent = Agent;
13 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/lib/agent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const egg = require('egg');
5 | const EGG_PATH = Symbol.for('egg#eggPath');
6 |
7 | class Agent extends egg.Agent {
8 | get [EGG_PATH]() {
9 | return path.dirname(__dirname);
10 | }
11 | }
12 |
13 | module.exports = Agent;
14 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/lib/application.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const egg = require('egg');
5 | const EGG_PATH = Symbol.for('egg#eggPath');
6 |
7 | class Application extends egg.Application {
8 | get [EGG_PATH]() {
9 | return path.dirname(__dirname);
10 | }
11 | }
12 |
13 | module.exports = Application;
14 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-framework",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "egg": "^1.0.0",
6 | "egg-ua": "../egg-ua"
7 | },
8 | "devDependencies": {
9 | "egg-bin": "^4.3.5",
10 | "egg-mock": "^3.13.1"
11 | },
12 | "engines": {
13 | "node": ">=8.9.0"
14 | },
15 | "scripts": {
16 | "dev": "egg-bin dev",
17 | "test": "egg-bin test",
18 | "cov": "egg-bin cov"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/test/fixtures/test-app/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', async function() {
5 | this.body = `framework: ${this.app.config.framework.name}, isIOS: ${this.isIOS}`;
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/test/fixtures/test-app/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/test/fixtures/test-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test-app",
3 | "version": "1.0.0"
4 | }
5 |
--------------------------------------------------------------------------------
/progressive/step4/example-framework/test/framework.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { mock } = require('egg-mock/bootstrap');
5 |
6 | describe('test/framework.test.js', () => {
7 | let app;
8 |
9 | before(() => {
10 | app = mock.app({
11 | baseDir: 'test-app',
12 | framework: true,
13 | });
14 | return app.ready();
15 | });
16 |
17 | after(() => app.close());
18 | afterEach(mock.restore);
19 |
20 | it('should GET /', () => {
21 | return app.httpRequest()
22 | .get('/')
23 | .set('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1')
24 | .expect(200)
25 | .expect('framework: example-framework, isIOS: true');
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/redefine-controller/app/controller/api.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('../core/controller');
4 |
5 | class ApiController extends Controller {
6 | async successAction() {
7 | this.success({ foo: 'bar' });
8 | }
9 |
10 | async failAction() {
11 | this.fail('something wrong');
12 | }
13 | }
14 |
15 | module.exports = ApiController;
16 |
--------------------------------------------------------------------------------
/redefine-controller/app/core/controller.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class CustomController extends Controller {
6 | success(result) {
7 | this.ctx.body = {
8 | success: true,
9 | result,
10 | };
11 | }
12 |
13 | fail(message) {
14 | this.ctx.body = {
15 | success: false,
16 | message,
17 | };
18 | }
19 | }
20 |
21 | module.exports = CustomController;
22 |
--------------------------------------------------------------------------------
/redefine-controller/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/success', 'api.successAction');
5 | app.router.get('/fail', 'api.failAction');
6 | };
7 |
--------------------------------------------------------------------------------
/redefine-controller/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'keys';
4 |
--------------------------------------------------------------------------------
/redefine-controller/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "redefine-controller",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "test": "egg-bin test",
12 | "dev": "egg-bin dev"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/redefine-controller/test/controller/api.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('test/controller/api.test.js', () => {
7 | let app;
8 | before(() => {
9 | app = mm.app();
10 | return app.ready();
11 | });
12 |
13 | after(() => app.close());
14 |
15 | it('should get /success ok', () => {
16 | return app.httpRequest()
17 | .get('/success')
18 | .expect(200)
19 | .expect({ success: true, result: { foo: 'bar' } });
20 | });
21 |
22 | it('should get /fail ok', () => {
23 | return app.httpRequest()
24 | .get('/fail')
25 | .expect(200)
26 | .expect({ success: false, message: 'something wrong' });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/schedule/app/schedule/all_cron.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Subscription = require('egg').Subscription;
4 |
5 | const now = new Date();
6 | const start = (now.getSeconds() + 3) % 60;
7 |
8 | class AllCron extends Subscription {
9 | async subscribe() {
10 | this.ctx.logger.info('all&&cron');
11 | }
12 |
13 | static get schedule() {
14 | return {
15 | cron: `${start}/30 * * * * *`,
16 | type: 'all',
17 | };
18 | }
19 | }
20 |
21 | module.exports = AllCron;
22 |
--------------------------------------------------------------------------------
/schedule/app/schedule/all_interval.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Subscription = require('egg').Subscription;
4 |
5 | class AllInterval extends Subscription {
6 | async subscribe() {
7 | this.ctx.logger.info('all&&interval');
8 | }
9 |
10 | static get schedule() {
11 | return {
12 | interval: 3000,
13 | type: 'all',
14 | };
15 | }
16 | }
17 |
18 | module.exports = AllInterval;
19 |
--------------------------------------------------------------------------------
/schedule/app/schedule/worker_cron.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Subscription = require('egg').Subscription;
4 |
5 | const now = new Date();
6 | const start = (now.getSeconds() + 3) % 60;
7 |
8 | class WorkerCron extends Subscription {
9 | async subscribe() {
10 | this.ctx.logger.info('worker&&cron');
11 | }
12 |
13 | static get schedule() {
14 | return {
15 | cron: `${start}/30 * * * * *`,
16 | type: 'worker',
17 | };
18 | }
19 | }
20 |
21 | module.exports = WorkerCron;
22 |
--------------------------------------------------------------------------------
/schedule/app/schedule/worker_interval.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Subscription = require('egg').Subscription;
4 |
5 | class WorkerInterval extends Subscription {
6 | async subscribe() {
7 | this.ctx.logger.info('all&&interval');
8 | }
9 |
10 | static get schedule() {
11 | return {
12 | interval: 3000,
13 | type: 'worker',
14 | };
15 | }
16 | }
17 |
18 | module.exports = WorkerInterval;
19 |
--------------------------------------------------------------------------------
/schedule/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "schedule-example",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "dev": "egg-bin dev",
12 | "test": "egg-bin test",
13 | "cov": "egg-bin cov"
14 | },
15 | "private": true
16 | }
17 |
--------------------------------------------------------------------------------
/schedule/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const mm = require('egg-mock');
6 |
7 | describe.skip('egg schedule example', () => {
8 | it('should schedule run schedule success', async () => {
9 | const baseDir = path.dirname(__dirname);
10 |
11 | const app = mm.cluster({
12 | workers: 2,
13 | });
14 |
15 | await app.ready();
16 | await sleep(3000);
17 | const log = fs.readFileSync(path.join(baseDir, 'logs/schedule-example/schedule-example-web.log'), 'utf8');
18 | console.log(log);
19 | countLine(log, 'all&&cron').should.equal(2);
20 | countLine(log, 'all&&interval').should.equal(2);
21 | countLine(log, 'worker&&cron').should.equal(1);
22 | countLine(log, 'worker&&interval').should.equal(1);
23 |
24 | await app.close();
25 | });
26 | });
27 |
28 | function sleep(time) {
29 | return new Promise(resolve => setTimeout(resolve, time));
30 | }
31 |
32 | function countLine(content, key) {
33 | return content.split('\n').filter(line => line.indexOf(key) >= 0).length;
34 | }
35 |
--------------------------------------------------------------------------------
/sequelize-ts/.gitignore:
--------------------------------------------------------------------------------
1 | typings/
--------------------------------------------------------------------------------
/sequelize-ts/.sequelizerc:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | module.exports = {
6 | config: path.join(__dirname, 'database/config.json'),
7 | 'migrations-path': path.join(__dirname, 'database/migrations'),
8 | 'seeders-path': path.join(__dirname, 'database/seeders'),
9 | };
10 |
--------------------------------------------------------------------------------
/sequelize-ts/app/extend/helper.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | parseInt(str: string | number) {
3 | if (typeof str === 'number') return str;
4 | if (!str) return 0;
5 | return parseInt(str) || 0;
6 | },
7 | }
--------------------------------------------------------------------------------
/sequelize-ts/app/model/post.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { Application } from 'egg';
4 |
5 | export default function(app: Application) {
6 | const { STRING, INTEGER, DATE } = app.Sequelize;
7 |
8 | const Model = app.model.define('post', {
9 | id: {
10 | type: INTEGER,
11 | primaryKey: true,
12 | autoIncrement: true,
13 | },
14 | title: STRING(30),
15 | content: STRING(255),
16 | user_id: INTEGER,
17 | created_at: DATE(6),
18 | updated_at: DATE(6),
19 | });
20 |
21 | return class Post extends Model {
22 | static associate() {
23 | app.model.Post.belongsTo(app.model.User, { as: 'user', foreignKey: 'user_id' });
24 | }
25 |
26 | static async findByIdWithUser(id: number, userId: number) {
27 | return await this.findOne({
28 | where: { id, user_id: userId },
29 | });
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/sequelize-ts/app/model/user.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { Application } from 'egg';
4 |
5 | export default function(app: Application) {
6 | const { STRING, INTEGER, DATE } = app.Sequelize;
7 | const Model = app.model.define('user', {
8 | id: {
9 | type: INTEGER,
10 | primaryKey: true,
11 | autoIncrement: true,
12 | },
13 | name: STRING(30),
14 | age: INTEGER,
15 | created_at: DATE(6),
16 | updated_at: DATE(6),
17 | });
18 |
19 | return class User extends Model {
20 | static associate() {
21 | app.model.User.hasMany(app.model.Post, { as: 'posts' });
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/sequelize-ts/app/router.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { Application } from 'egg';
4 |
5 | export default function(app: Application) {
6 | app.resources('users', '/users', app.controller.user);
7 | app.resources('posts', '/posts', app.controller.post);
8 | }
9 |
--------------------------------------------------------------------------------
/sequelize-ts/config/config.default.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { EggAppConfig, PowerPartial } from 'egg';
4 |
5 | export default function(appInfo: EggAppConfig) {
6 | const config = {} as PowerPartial;
7 |
8 | config.keys = appInfo.name + '123123';
9 |
10 | config.sequelize = {
11 | database: 'egg-sequelize-ts-dev',
12 | };
13 |
14 | const bizConfig = {
15 | // your biz config
16 | };
17 |
18 | return {
19 | ...config as {},
20 | ...bizConfig,
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/sequelize-ts/config/config.unittest.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { EggAppConfig, PowerPartial } from 'egg';
4 |
5 | export default function() {
6 | const config = {} as PowerPartial;
7 |
8 | config.sequelize = {
9 | database: 'egg-sequelize-ts-unittest',
10 | };
11 |
12 | return config;
13 | }
14 |
--------------------------------------------------------------------------------
/sequelize-ts/config/plugin.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { EggPlugin } from 'egg';
4 |
5 | const plugin: EggPlugin = {};
6 |
7 | plugin.sequelize = {
8 | package: 'egg-sequelize',
9 | enable: true,
10 | };
11 |
12 | export default plugin;
13 |
--------------------------------------------------------------------------------
/sequelize-ts/database/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "username": "root",
4 | "password": null,
5 | "database": "egg-sequelize-ts-dev",
6 | "host": "127.0.0.1",
7 | "dialect": "mysql"
8 | },
9 | "test": {
10 | "username": "root",
11 | "password": null,
12 | "database": "egg-sequelize-ts-unittest",
13 | "host": "127.0.0.1",
14 | "dialect": "mysql"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/sequelize-ts/database/migrations/20180813112934-user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | const { INTEGER, DATE, STRING } = Sequelize;
6 | await queryInterface.createTable('users', {
7 | id: { type: INTEGER, primaryKey: true, autoIncrement: true },
8 | name: STRING(30),
9 | age: INTEGER,
10 | created_at: DATE(6),
11 | updated_at: DATE(6),
12 | });
13 | },
14 |
15 | down: async queryInterface => {
16 | await queryInterface.dropTable('users');
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/sequelize-ts/database/migrations/20180813112942-post.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | const { INTEGER, DATE, STRING } = Sequelize;
6 | await queryInterface.createTable('posts', {
7 | id: { type: INTEGER, primaryKey: true, autoIncrement: true },
8 | title: STRING(30),
9 | content: STRING(255),
10 | user_id: INTEGER,
11 | created_at: DATE(6),
12 | updated_at: DATE(6),
13 | });
14 | },
15 |
16 | down: async queryInterface => {
17 | await queryInterface.dropTable('posts');
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/sequelize-ts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sequelize-ts-example",
3 | "version": "1.0.0",
4 | "description": "The egg ts example project that uses egg-sequelize plugin.",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^2.10.0",
8 | "egg-sequelize": "^5.0.0",
9 | "mysql2": "^1.6.1"
10 | },
11 | "devDependencies": {
12 | "@types/mocha": "^5.2.6",
13 | "autod": "^3.0.1",
14 | "egg-bin": "^4.8.1",
15 | "egg-mock": "^3.19.2",
16 | "factory-girl": "^5.0.2",
17 | "lodash": "^4.17.10",
18 | "sequelize-cli": "^5.0.0"
19 | },
20 | "engines": {
21 | "node": ">=8.9.0"
22 | },
23 | "egg": {
24 | "typescript": true,
25 | "declarations": true
26 | },
27 | "scripts": {
28 | "dev": "egg-bin dev",
29 | "test": "NODE_ENV=test npm run sequelize -- db:migrate && egg-bin test",
30 | "cov": "egg-bin cov",
31 | "ci": "npm run cov",
32 | "autod": "autod",
33 | "sequelize": "sequelize --"
34 | },
35 | "author": "Qi Yu ",
36 | "license": "MIT"
37 | }
38 |
--------------------------------------------------------------------------------
/sequelize-ts/test/factories.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { MockApplication } from 'egg-mock';
4 | import { factory } from 'factory-girl';
5 |
6 | export default function(app: MockApplication) {
7 | app.factory = factory;
8 | factory.define('user', app.model.User, {
9 | name: factory.sequence('User.name', n => `name_${n}`),
10 | age: 18,
11 | });
12 |
13 | factory.define('post', app.model.Post, {
14 | title: factory.sequence('Post.title', n => `title_${n}`),
15 | content: factory.chance('sentence', { word: 5 }),
16 | user_id: factory.assoc('user', 'id'),
17 | });
18 | }
19 |
20 | declare module 'egg' {
21 | interface Application {
22 | factory: any;
23 | }
24 | }
--------------------------------------------------------------------------------
/sequelize-ts/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --file ./test/setup.ts
--------------------------------------------------------------------------------
/sequelize-ts/test/setup.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { app } from 'egg-mock/bootstrap';
4 | import factories from './factories';
5 |
6 | before(() => {
7 | // defined app.factory for build test data
8 | factories(app);
9 | });
10 |
11 | afterEach(async () => {
12 | // clear database after each test case
13 | await Promise.all([
14 | app.model.User.destroy({ truncate: true, force: true }),
15 | app.model.Post.destroy({ truncate: true, force: true }),
16 | ]);
17 | });
18 |
--------------------------------------------------------------------------------
/sequelize-ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "compilerOptions": {
4 | "target": "es2017",
5 | "module": "commonjs",
6 | "strict": true,
7 | "noImplicitAny": false,
8 | "experimentalDecorators": true,
9 | "emitDecoratorMetadata": true,
10 | "allowSyntheticDefaultImports": true,
11 | "charset": "utf8",
12 | "allowJs": false,
13 | "pretty": true,
14 | "lib": ["es6", "dom"],
15 | "noEmitOnError": false,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "allowUnreachableCode": false,
19 | "allowUnusedLabels": false,
20 | "strictPropertyInitialization": false,
21 | "noFallthroughCasesInSwitch": true,
22 | "inlineSourceMap": true
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sequelize/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'ues strict';
2 |
3 | module.exports = {
4 | write: true,
5 | prefix: '^',
6 | devprefix: '^',
7 | exclude: [
8 | 'test/fixtures',
9 | 'run',
10 | ],
11 | devdep: [
12 | 'egg-bin',
13 | 'sequelize-cli',
14 | ],
15 | dep: [
16 | 'egg',
17 | 'egg-sequelize',
18 | 'mysql2',
19 | ],
20 | semver: [
21 | ],
22 | };
23 |
--------------------------------------------------------------------------------
/sequelize/.sequelizerc:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | module.exports = {
6 | config: path.join(__dirname, 'database/config.json'),
7 | 'migrations-path': path.join(__dirname, 'database/migrations'),
8 | 'seeders-path': path.join(__dirname, 'database/seeders'),
9 | };
10 |
--------------------------------------------------------------------------------
/sequelize/app/extend/helper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | parseInt(string) {
5 | if (typeof string === 'number') return string;
6 | if (!string) return string;
7 | return parseInt(string) || 0;
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/sequelize/app/model/post.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { STRING, INTEGER, DATE } = app.Sequelize;
5 |
6 | const Post = app.model.define('post', {
7 | id: {
8 | type: INTEGER,
9 | primaryKey: true,
10 | autoIncrement: true,
11 | },
12 | title: STRING(30),
13 | content: STRING(255),
14 | user_id: INTEGER,
15 | created_at: DATE,
16 | updated_at: DATE,
17 | });
18 |
19 | Post.associate = function() {
20 | app.model.Post.belongsTo(app.model.User, { as: 'user', foreignKey: 'user_id' });
21 | };
22 |
23 | Post.findByIdWithUser = async function(id, userId) {
24 | return await this.findOne({
25 | where: { id, user_id: userId },
26 | });
27 | };
28 |
29 | return Post;
30 | };
31 |
--------------------------------------------------------------------------------
/sequelize/app/model/user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { STRING, INTEGER, DATE } = app.Sequelize;
5 |
6 | const User = app.model.define('user', {
7 | id: {
8 | type: INTEGER,
9 | primaryKey: true,
10 | autoIncrement: true,
11 | },
12 | name: STRING(30),
13 | age: INTEGER,
14 | created_at: DATE,
15 | updated_at: DATE,
16 | });
17 |
18 | User.prototype.associate = function() {
19 | app.model.User.hasMany(app.model.Post, { as: 'posts' });
20 | };
21 |
22 | return User;
23 | };
24 |
--------------------------------------------------------------------------------
/sequelize/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.resources('users', '/users', app.controller.user);
5 | app.resources('posts', '/posts', app.controller.post);
6 | };
7 |
--------------------------------------------------------------------------------
/sequelize/app/service/user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Service = require('egg').Service;
4 |
5 | class User extends Service {
6 | async list({ offset = 0, limit = 10 }) {
7 | return this.ctx.model.User.findAndCountAll({
8 | offset,
9 | limit,
10 | order: [[ 'created_at', 'desc' ], [ 'id', 'desc' ]],
11 | });
12 | }
13 |
14 | async find(id) {
15 | const user = await this.ctx.model.User.findByPk(id);
16 | if (!user) {
17 | this.ctx.throw(404, 'user not found');
18 | }
19 | return user;
20 | }
21 |
22 | async create(user) {
23 | return this.ctx.model.User.create(user);
24 | }
25 |
26 | async update({ id, updates }) {
27 | const user = await this.ctx.model.User.findByPk(id);
28 | if (!user) {
29 | this.ctx.throw(404, 'user not found');
30 | }
31 | return user.update(updates);
32 | }
33 |
34 | async del(id) {
35 | const user = await this.ctx.model.User.findByPk(id);
36 | if (!user) {
37 | this.ctx.throw(404, 'user not found');
38 | }
39 | return user.destroy();
40 | }
41 | }
42 |
43 | module.exports = User;
44 |
--------------------------------------------------------------------------------
/sequelize/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = {};
5 |
6 | // should change to your own
7 | config.keys = appInfo.name + '_sequelize-example';
8 |
9 | config.sequelize = {
10 | dialect: 'mysql', // support: mysql, mariadb, postgres, mssql
11 | database: 'egg-sequelize-example-dev',
12 | host: '127.0.0.1',
13 | port: 3306,
14 | };
15 |
16 | return config;
17 | };
18 |
--------------------------------------------------------------------------------
/sequelize/config/config.unittest.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.sequelize = {
4 | dialect: 'mysql', // support: mysql, mariadb, postgres, mssql
5 | database: 'egg-sequelize-example-unittest',
6 | };
7 |
--------------------------------------------------------------------------------
/sequelize/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // had enabled by egg
4 | // exports.static = true;
5 | exports.sequelize = {
6 | enable: true,
7 | package: 'egg-sequelize',
8 | };
9 |
--------------------------------------------------------------------------------
/sequelize/database/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "development": {
3 | "username": "root",
4 | "password": null,
5 | "database": "egg-sequelize-example-dev",
6 | "host": "127.0.0.1",
7 | "dialect": "mysql"
8 | },
9 | "test": {
10 | "username": "root",
11 | "password": null,
12 | "database": "egg-sequelize-example-unittest",
13 | "host": "127.0.0.1",
14 | "dialect": "mysql"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/sequelize/database/migrations/20180813112934-user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | const { INTEGER, DATE, STRING } = Sequelize;
6 | await queryInterface.createTable('users', {
7 | id: { type: INTEGER, primaryKey: true, autoIncrement: true },
8 | name: STRING(30),
9 | age: INTEGER,
10 | created_at: DATE,
11 | updated_at: DATE,
12 | });
13 | },
14 |
15 | down: async queryInterface => {
16 | await queryInterface.dropTable('users');
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/sequelize/database/migrations/20180813112942-post.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | const { INTEGER, DATE, STRING } = Sequelize;
6 | await queryInterface.createTable('posts', {
7 | id: { type: INTEGER, primaryKey: true, autoIncrement: true },
8 | title: STRING(30),
9 | content: STRING(255),
10 | user_id: INTEGER,
11 | created_at: DATE,
12 | updated_at: DATE,
13 | });
14 | },
15 |
16 | down: async queryInterface => {
17 | await queryInterface.dropTable('posts');
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/sequelize/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sequelize-example",
3 | "version": "1.0.0",
4 | "description": "The egg example project that uses egg-sequelize plugin.",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^2.10.0",
8 | "egg-sequelize": "^5.0.1",
9 | "mysql2": "^1.6.1"
10 | },
11 | "devDependencies": {
12 | "autod": "^3.0.1",
13 | "egg-bin": "^4.8.1",
14 | "egg-mock": "^3.19.2",
15 | "factory-girl": "^5.0.2",
16 | "lodash": "^4.17.10",
17 | "sequelize-cli": "^5.0.0"
18 | },
19 | "engines": {
20 | "node": ">=8.9.0"
21 | },
22 | "scripts": {
23 | "dev": "egg-bin dev",
24 | "test": "NODE_ENV=test npm run sequelize -- db:migrate && egg-bin test",
25 | "cov": "egg-bin cov",
26 | "ci": "npm run cov",
27 | "autod": "autod",
28 | "sequelize": "sequelize --"
29 | },
30 | "author": "Qi Yu ",
31 | "license": "MIT"
32 | }
33 |
--------------------------------------------------------------------------------
/sequelize/test/.setup.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app } = require('egg-mock/bootstrap');
4 | const factories = require('./factories');
5 |
6 | before(() => {
7 | // defined app.factory for build test data
8 | factories(app);
9 | });
10 |
11 | afterEach(async () => {
12 | // clear database after each test case
13 | await Promise.all([
14 | app.model.User.destroy({ truncate: true, force: true }),
15 | app.model.Post.destroy({ truncate: true, force: true }),
16 | ]);
17 | });
18 |
--------------------------------------------------------------------------------
/sequelize/test/factories.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { factory } = require('factory-girl');
4 |
5 | module.exports = app => {
6 | app.factory = factory;
7 | factory.define('user', app.model.User, {
8 | name: factory.sequence('User.name', n => `name_${n}`),
9 | age: 18,
10 | });
11 |
12 | factory.define('post', app.model.Post, {
13 | title: factory.sequence('Post.title', n => `title_${n}`),
14 | content: factory.chance('sentence', { word: 5 }),
15 | user_id: factory.assoc('user', 'id'),
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/sofa-rpc/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | write: true,
5 | prefix: '^',
6 | plugin: 'autod-egg',
7 | test: [
8 | 'test',
9 | 'benchmark',
10 | ],
11 | dep: [
12 | 'egg',
13 | 'egg-scripts',
14 | ],
15 | devdep: [
16 | 'egg-ci',
17 | 'egg-bin',
18 | 'egg-mock',
19 | 'autod',
20 | 'autod-egg',
21 | 'eslint',
22 | 'eslint-config-egg',
23 | 'webstorm-disable-index',
24 | ],
25 | exclude: [
26 | './test/fixtures',
27 | './dist',
28 | ],
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/sofa-rpc/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | app/proxy/*
3 |
--------------------------------------------------------------------------------
/sofa-rpc/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-egg"
3 | }
4 |
--------------------------------------------------------------------------------
/sofa-rpc/.gitignore:
--------------------------------------------------------------------------------
1 | app/proxy
2 | logs/
3 | npm-debug.log
4 | yarn-error.log
5 | node_modules/
6 | package-lock.json
7 | yarn.lock
8 | coverage/
9 | .idea/
10 | run/
11 | .DS_Store
12 | *.sw*
13 | *.un~
14 |
--------------------------------------------------------------------------------
/sofa-rpc/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '8'
5 | install:
6 | - npm i npminstall && npminstall
7 | script:
8 | - npm run ci
9 | after_script:
10 | - npminstall codecov && codecov
11 |
--------------------------------------------------------------------------------
/sofa-rpc/README.md:
--------------------------------------------------------------------------------
1 | # sofa-rpc
2 |
3 | sofa rpc demo
4 |
5 | ## QuickStart
6 |
7 |
8 |
9 | see [egg-sofa-rpc tutorial][https://github.com/eggjs/egg-sofa-rpc/wiki/Eggjs-%E5%92%8C-SOFA-%E7%9A%84%E8%B7%A8%E8%AF%AD%E8%A8%80%E4%BA%92%E8%B0%83] for more detail.
10 |
11 | ### Development
12 |
13 | ```bash
14 | $ npm i
15 | $ npm run dev
16 | $ open http://localhost:7001/
17 | ```
18 |
19 | ### Deploy
20 |
21 | ```bash
22 | $ npm start
23 | $ npm stop
24 | ```
25 |
26 | ### npm scripts
27 |
28 | - Use `npm run lint` to check code style.
29 | - Use `npm test` to run unit test.
30 | - Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
31 |
32 |
33 | [egg]: https://eggjs.org
34 |
--------------------------------------------------------------------------------
/sofa-rpc/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # sofa-rpc
2 |
3 | sofa rpc demo
4 |
5 | ## 快速入门
6 |
7 |
8 |
9 | 如需进一步了解,参见 [Eggjs 和 SOFA 的跨语言互调][https://github.com/eggjs/egg-sofa-rpc/wiki/Eggjs-%E5%92%8C-SOFA-%E7%9A%84%E8%B7%A8%E8%AF%AD%E8%A8%80%E4%BA%92%E8%B0%83]。
10 |
11 | ### 本地开发
12 |
13 | ```bash
14 | $ npm i
15 | $ npm run dev
16 | $ open http://localhost:7001/
17 | ```
18 |
19 | ### 部署
20 |
21 | ```bash
22 | $ npm start
23 | $ npm stop
24 | ```
25 |
26 | ### 单元测试
27 |
28 | - [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。
29 | - 断言库非常推荐使用 [power-assert]。
30 | - 具体参见 [egg 文档 - 单元测试](https://eggjs.org/zh-cn/core/unittest)。
31 |
32 | ### 内置指令
33 |
34 | - 使用 `npm run lint` 来做代码风格检查。
35 | - 使用 `npm test` 来执行单元测试。
36 | - 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod) 。
37 |
38 |
39 | [egg]: https://eggjs.org
40 |
--------------------------------------------------------------------------------
/sofa-rpc/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async index() {
7 | const { ctx } = this;
8 | const res = await ctx.proxy.protoService.echoObj({
9 | name: 'gxcsoccer',
10 | group: 'A',
11 | });
12 | ctx.body = res;
13 | }
14 | }
15 |
16 | module.exports = HomeController;
17 |
--------------------------------------------------------------------------------
/sofa-rpc/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | const { router, controller } = app;
8 | router.get('/', controller.home.index);
9 | };
10 |
--------------------------------------------------------------------------------
/sofa-rpc/app/rpc/ProtoService.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.echoObj = async function(req) {
4 | return {
5 | code: 200,
6 | message: 'hello ' + req.name + ', you are in ' + req.group,
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/sofa-rpc/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '8'
4 |
5 | install:
6 | - ps: Install-Product node $env:nodejs_version
7 | - npm i npminstall && node_modules\.bin\npminstall
8 |
9 | test_script:
10 | - node --version
11 | - npm --version
12 | - npm run test
13 |
14 | build: off
15 |
--------------------------------------------------------------------------------
/sofa-rpc/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = appInfo => {
4 | const config = exports = {};
5 |
6 | // use for cookie sign key, should change to your own and keep security
7 | config.keys = appInfo.name + '_1528713428903_3456';
8 |
9 | // add your config here
10 | config.middleware = [];
11 |
12 | config.rpc = {
13 | registry: {
14 | address: '127.0.0.1:2181', // 根据实际情况配置
15 | },
16 | server: {
17 | namespace: 'com.alipay.sofa.rpc.protobuf',
18 | codecType: 'protobuf',
19 | },
20 | };
21 |
22 | return config;
23 | };
24 |
--------------------------------------------------------------------------------
/sofa-rpc/config/proxy.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | services: [{
5 | appName: 'sofarpc',
6 | api: {
7 | ProtoService: 'com.alipay.sofa.rpc.protobuf.ProtoService',
8 | },
9 | }],
10 | };
11 |
--------------------------------------------------------------------------------
/sofa-rpc/proto/ProtoService.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.alipay.sofa.rpc.protobuf;
4 | option java_multiple_files = true; // 可选
5 | option java_outer_classname = "ProtoServiceModels"; // 可选
6 |
7 | service ProtoService {
8 | rpc echoObj (EchoRequest) returns (EchoResponse) {}
9 | }
10 |
11 | message EchoRequest {
12 | string name = 1;
13 | Group group = 2;
14 | }
15 |
16 | message EchoResponse {
17 | int32 code = 1;
18 | string message = 2;
19 | }
20 |
21 | enum Group {
22 | A = 0;
23 | B = 1;
24 | }
25 |
--------------------------------------------------------------------------------
/sofa-rpc/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app, assert } = require('egg-mock/bootstrap');
4 | const sleep = require('mz-modules/sleep');
5 |
6 | describe('test/app/controller/home.test.js', () => {
7 |
8 | it('should assert', function* () {
9 | const pkg = require('../../../package.json');
10 | assert(app.config.keys.startsWith(pkg.name));
11 |
12 | // const ctx = app.mockContext({});
13 | // yield ctx.service.xx();
14 | });
15 |
16 | it('should GET /', async function() {
17 | await sleep(1000);
18 | return app.httpRequest()
19 | .get('/')
20 | .expect('{"code":200,"message":"hello gxcsoccer, you are in 0"}')
21 | .expect(200);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/sofa-rpc/test/server.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mm = require('egg-mock');
4 | const sleep = require('mz-modules/sleep');
5 |
6 | describe('test/server.test.js', () => {
7 | let app;
8 | before(async function() {
9 | app = mm.app();
10 | await app.ready();
11 | await sleep(3000);
12 | });
13 | after(async function() {
14 | await app.close();
15 | });
16 |
17 | it('should invoke echoObj ok', done => {
18 | app.rpcRequest('ProtoService')
19 | .invoke('echoObj')
20 | .send([{
21 | name: 'gxcsoccer',
22 | group: 'B',
23 | }])
24 | .expect({
25 | code: 200,
26 | message: 'hello gxcsoccer, you are in 1',
27 | }, done);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/static/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async render() {
7 | const ctx = this.ctx;
8 | ctx.body = ``;
14 | }
15 | }
16 |
17 | module.exports = Home;
18 |
--------------------------------------------------------------------------------
/static/app/public/foo.js:
--------------------------------------------------------------------------------
1 | alert('hi egg');
2 |
--------------------------------------------------------------------------------
/static/app/public/hi.txt:
--------------------------------------------------------------------------------
1 | hi egg.
2 | 你好,蛋蛋。
3 |
--------------------------------------------------------------------------------
/static/app/public/蛋蛋Web框架.txt:
--------------------------------------------------------------------------------
1 | test only.
2 | 测试专用。
3 |
--------------------------------------------------------------------------------
/static/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', 'home.render');
5 | };
6 |
--------------------------------------------------------------------------------
/static/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my keys';
4 |
--------------------------------------------------------------------------------
/static/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.static = true;
4 |
--------------------------------------------------------------------------------
/static/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "static-example",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1"
9 | },
10 | "scripts": {
11 | "dev": "egg-bin dev",
12 | "test": "egg-bin test",
13 | "cov": "egg-bin cov"
14 | },
15 | "private": true
16 | }
17 |
--------------------------------------------------------------------------------
/static/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mm = require('egg-mock');
5 |
6 | describe('example static test', () => {
7 | let app;
8 |
9 | before(() => {
10 | app = mm.app();
11 | return app.ready();
12 | });
13 |
14 | after(() => app.close());
15 |
16 | it('should GET / 200', () => {
17 | return app.httpRequest()
18 | .get('/')
19 | .expect(200)
20 | .expect(/Download hi\.txt<\/a>\.<\/li>/);
21 | });
22 |
23 | it('should GET /public/hi.txt', () => {
24 | return app.httpRequest()
25 | .get('/public/hi.txt')
26 | .expect(200)
27 | .expect('hi egg.\n你好,蛋蛋。\n');
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/todomvc/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 |
--------------------------------------------------------------------------------
/todomvc/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "eslint-config-egg",
4 | "parserOptions": {
5 | "ecmaVersion": 2022
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/todomvc/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | yarn-error.log
4 | node_modules/
5 | package-lock.json
6 | yarn.lock
7 | coverage/
8 | .idea/
9 | run/
10 | .DS_Store
11 | *.sw*
12 | *.un~
13 | typings/
14 | .nyc_output/
15 | *.sqlite3
16 |
--------------------------------------------------------------------------------
/todomvc/README.md:
--------------------------------------------------------------------------------
1 | # TodoMVC powered by Egg
2 |
3 | - [TodoMVC](http://todomvc.com/)
4 | - [Egg](egg)
5 |
6 | 
7 |
8 | ### QuickStart
9 |
10 | ```bash
11 | $ npm i
12 | $ npm run dev
13 | $ open http://localhost:7001/
14 | ```
15 |
16 | [egg]: https://eggjs.org
17 |
--------------------------------------------------------------------------------
/todomvc/app.js:
--------------------------------------------------------------------------------
1 | const initDatabase = require('./config/database/init');
2 |
3 | class AppBootHook {
4 | constructor(app) {
5 | this.app = app;
6 | }
7 |
8 | async didLoad() {
9 | await initDatabase(this.app);
10 | }
11 | }
12 |
13 | module.exports = AppBootHook;
14 |
--------------------------------------------------------------------------------
/todomvc/app/controller/home.js:
--------------------------------------------------------------------------------
1 | const { Controller } = require('egg');
2 |
3 | class HomeController extends Controller {
4 | async index() {
5 | const { ctx } = this;
6 | await ctx.render('home.tpl');
7 | }
8 | }
9 |
10 | module.exports = HomeController;
11 |
--------------------------------------------------------------------------------
/todomvc/app/middleware/response_time.js:
--------------------------------------------------------------------------------
1 | module.exports = options => {
2 | return async function responseTime(ctx, next) {
3 | const start = Date.now();
4 | await next();
5 | const cost = Date.now() - start;
6 | ctx.set(options.headerKey, `${cost}ms`);
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/todomvc/app/model/todo.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const { Bone, DataTypes: { DATE, STRING, BOOLEAN } } = app.model;
3 |
4 | class Todo extends Bone {
5 | static table = 'todos';
6 | static attributes = {
7 | title: STRING(1000),
8 | createdAt: DATE,
9 | updatedAt: DATE,
10 | deletedAt: DATE,
11 | completed: BOOLEAN,
12 | };
13 | }
14 |
15 | return Todo;
16 | };
17 |
--------------------------------------------------------------------------------
/todomvc/app/router.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {Egg.Application} app - egg application
3 | */
4 | module.exports = app => {
5 | const { router, controller } = app;
6 |
7 | router.get('/', controller.home.index);
8 | router.resources('/api/todo', controller.todo);
9 | };
10 |
--------------------------------------------------------------------------------
/todomvc/config/config.unittest.js:
--------------------------------------------------------------------------------
1 | /* eslint valid-jsdoc: "off" */
2 |
3 | const path = require('path');
4 |
5 | module.exports = () => {
6 | /**
7 | * built-in config
8 | * @type {Egg.EggAppConfig}
9 | **/
10 | const config = {};
11 |
12 | config.orm = {
13 | database: path.join(__dirname, '..', 'todos_unittest.sqlite3'),
14 | };
15 |
16 | return {
17 | ...config,
18 | };
19 | };
20 |
--------------------------------------------------------------------------------
/todomvc/config/database/init.js:
--------------------------------------------------------------------------------
1 | // init database here
2 | module.exports = async app => {
3 | // sync database defines
4 | await app.model.sync();
5 |
6 | if (app.config.env === 'unittest') {
7 | await app.model.Todo.remove({}, true);
8 | await app.model.Todo.bulkCreate([
9 | { title: 'Read history of Node.js', completed: true },
10 | { title: 'Learn Koa', completed: true },
11 | { title: 'Star Egg', completed: false },
12 | ]);
13 | const rows = await app.model.Todo.findAll();
14 | console.log(rows);
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/todomvc/config/plugin.js:
--------------------------------------------------------------------------------
1 | /** @type Egg.EggPlugin */
2 | module.exports = {
3 | nunjucks: {
4 | enable: true,
5 | package: 'egg-view-nunjucks',
6 | },
7 | validate: {
8 | enable: true,
9 | package: 'egg-validate',
10 | },
11 | orm: {
12 | enable: true,
13 | package: 'egg-orm',
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/todomvc/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "**/*"
4 | ]
5 | }
--------------------------------------------------------------------------------
/todomvc/todomvc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggjs/examples/5ea83ef36dede99ae057adfb6972c5086d8d2e4c/todomvc/todomvc.png
--------------------------------------------------------------------------------
/unittest-jest/README.md:
--------------------------------------------------------------------------------
1 | # unittest-jest
2 |
3 | Example use on https://github.com/eggjs/egg/blob/master/docs/source/zh-cn/core/unittest.md
4 |
--------------------------------------------------------------------------------
/unittest-jest/__tests__/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app } = require('egg-mock/bootstrap');
4 |
5 | describe('__tests__/controller/home.test.js', () => {
6 | it('should status 200 and get the body', () => {
7 | return app.httpRequest()
8 | .get('/')
9 | .expect(200)
10 | .expect('hello world');
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/unittest-jest/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app } = require('egg-mock/bootstrap');
4 |
5 | describe('__tests__/index.test.js', () => {
6 | it('should app exist', () => {
7 | expect(app.test).toBe('123');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/unittest-jest/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async index() {
7 | const ctx = this.ctx;
8 | ctx.body = 'hello world';
9 | }
10 | }
11 |
12 | module.exports = Home;
13 |
--------------------------------------------------------------------------------
/unittest-jest/app/extend/application.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | test: '123',
5 | };
6 |
--------------------------------------------------------------------------------
/unittest-jest/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('homepage', '/', 'home.index');
5 | };
6 |
--------------------------------------------------------------------------------
/unittest-jest/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my super cool keys';
4 |
--------------------------------------------------------------------------------
/unittest-jest/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unittest-jest-example",
3 | "dependencies": {
4 | "egg": "^1.10.1"
5 | },
6 | "devDependencies": {
7 | "egg-bin": "^4.3.5",
8 | "egg-mock": "^3.13.1",
9 | "jest": "^23.6.0"
10 | },
11 | "scripts": {
12 | "dev": "egg-bin dev",
13 | "test": "jest",
14 | "cov": "jest --coverage",
15 | "ci": "eslint . && npm run cov"
16 | },
17 | "private": true
18 | }
19 |
--------------------------------------------------------------------------------
/unittest/README.md:
--------------------------------------------------------------------------------
1 | # unittest
2 |
3 | Example use on https://github.com/eggjs/egg/blob/master/docs/source/zh-cn/core/unittest.md
4 |
--------------------------------------------------------------------------------
/unittest/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 |
5 | app.beforeStart(async () => {
6 | // 示例:启动的时候去读取 https://registry.npmjs.com/egg/latest 的版本信息
7 | const result = await app.curl('https://registry.npmjs.com/egg/latest', {
8 | dataType: 'json',
9 | });
10 | app.logger.info('egg latest version: %s', result.data.version);
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/unittest/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async index() {
7 | const ctx = this.ctx;
8 | ctx.body = 'hello world';
9 | }
10 |
11 | async post() {
12 | const ctx = this.ctx;
13 | ctx.body = ctx.request.body;
14 | }
15 |
16 | async session() {
17 | const ctx = this.ctx;
18 | ctx.body = {
19 | session: ctx.session,
20 | };
21 | }
22 |
23 | async user() {
24 | const ctx = this.ctx;
25 | const user = await ctx.service.user.get(ctx.query.name);
26 | ctx.body = {
27 | user,
28 | };
29 | }
30 |
31 | async httpclient() {
32 | const ctx = this.ctx;
33 | const res = await ctx.curl('https://eggjs.org');
34 | ctx.body = res.data.toString();
35 | }
36 | }
37 |
38 | module.exports = Home;
39 |
--------------------------------------------------------------------------------
/unittest/app/extend/application.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const LRU = Symbol('Application#lru');
4 | const LRUCache = require('ylru');
5 |
6 | module.exports = {
7 | get lru() {
8 | if (!this[LRU]) {
9 | this[LRU] = new LRUCache(1000);
10 | }
11 | return this[LRU];
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/unittest/app/extend/context.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | get isXHR() {
5 | return this.get('X-Requested-With') === 'XMLHttpRequest';
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/unittest/app/extend/helper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | money(val) {
5 | const lang = this.ctx.get('Accept-Language');
6 | if (lang.includes('zh-CN')) {
7 | return `¥ ${val}`;
8 | }
9 | return `$ ${val}`;
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/unittest/app/extend/request.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const IS_CHROME = Symbol('Request#isChrome');
4 |
5 | module.exports = {
6 | get isChrome() {
7 | if (!this[IS_CHROME]) {
8 | const ua = this.get('User-Agent').toLowerCase();
9 | this[IS_CHROME] = ua.includes('chrome/');
10 | }
11 | return this[IS_CHROME];
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/unittest/app/extend/response.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | get isSuccess() {
5 | return this.status === 200;
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/unittest/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('homepage', '/', 'home.index');
5 | app.router.post('postdata', '/post', 'home.post');
6 | app.router.get('session', '/session', 'home.session');
7 | app.router.get('user', '/user', 'home.user');
8 | app.router.get('httpclient', '/httpclient', 'home.httpclient');
9 | };
10 |
--------------------------------------------------------------------------------
/unittest/app/service/user.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Service = require('egg').Service;
4 |
5 | const mockUsers = [
6 | {
7 | name: 'fengmk2',
8 | home: 'HangZhou',
9 | url: 'https://fengmk2.com',
10 | },
11 | ];
12 |
13 | const userDatabase = {
14 | async get(name) {
15 | for (const user of mockUsers) {
16 | if (user.name === name) {
17 | return user;
18 | }
19 | }
20 | return null;
21 | },
22 | };
23 |
24 | class User extends Service {
25 | async get(name) {
26 | return userDatabase.get(name);
27 | }
28 | }
29 |
30 | module.exports = User;
31 |
--------------------------------------------------------------------------------
/unittest/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my super cool keys';
4 |
--------------------------------------------------------------------------------
/unittest/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unittest-example",
3 | "dependencies": {
4 | "egg": "^1.10.1",
5 | "ylru": "^1.2.0"
6 | },
7 | "devDependencies": {
8 | "egg-bin": "^4.3.5",
9 | "egg-mock": "^3.13.1"
10 | },
11 | "scripts": {
12 | "dev": "egg-bin dev",
13 | "test": "egg-bin test",
14 | "cov": "egg-bin cov",
15 | "ci": "eslint . && egg-bin cov"
16 | },
17 | "private": true
18 | }
19 |
--------------------------------------------------------------------------------
/unittest/test/extend/application.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const mock = require('egg-mock');
5 |
6 | describe('test/extend/application.test.js', () => {
7 | let app;
8 | before(() => {
9 | app = mock.app();
10 | return app.ready();
11 | });
12 |
13 | describe('get lru', () => {
14 | it('should get a lru and it work', () => {
15 | app.lru.set('foo', 'bar');
16 | assert(app.lru.get('foo') === 'bar');
17 | });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/unittest/test/extend/context.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const mock = require('egg-mock');
5 |
6 | describe('test/extend/context.test.js', () => {
7 | let app;
8 | before(() => {
9 | app = mock.app();
10 | return app.ready();
11 | });
12 |
13 | describe('isXHR()', () => {
14 | it('should true', () => {
15 | const ctx = app.mockContext({
16 | headers: {
17 | 'X-Requested-With': 'XMLHttpRequest',
18 | },
19 | });
20 | assert(ctx.isXHR === true);
21 | });
22 |
23 | it('should false', () => {
24 | const ctx = app.mockContext({
25 | headers: {
26 | 'X-Requested-With': 'SuperAgent',
27 | },
28 | });
29 | assert(ctx.isXHR === false);
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/unittest/test/extend/helper.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const mock = require('egg-mock');
5 |
6 | describe('test/extend/helper.test.js', () => {
7 | let app;
8 | before(() => {
9 | app = mock.app();
10 | return app.ready();
11 | });
12 |
13 | describe('money()', () => {
14 | it('should RMB', () => {
15 | const ctx = app.mockContext({
16 | // 模拟 ctx 的 headers
17 | headers: {
18 | 'Accept-Language': 'zh-CN,zh;q=0.5',
19 | },
20 | });
21 | assert(ctx.helper.money(100) === '¥ 100');
22 | });
23 |
24 | it('should US Dolar', () => {
25 | const ctx = app.mockContext();
26 | assert(ctx.helper.money(100) === '$ 100');
27 | });
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/unittest/test/extend/request.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const mock = require('egg-mock');
5 |
6 | describe('test/extend/request.test.js', () => {
7 | let app;
8 | before(() => {
9 | app = mock.app();
10 | return app.ready();
11 | });
12 |
13 | describe('isChrome()', () => {
14 | it('should true', () => {
15 | const ctx = app.mockContext({
16 | headers: {
17 | 'User-Agent': 'Chrome/56.0.2924.51',
18 | },
19 | });
20 | assert(ctx.request.isChrome === true);
21 | });
22 |
23 | it('should false', () => {
24 | const ctx = app.mockContext({
25 | headers: {
26 | 'User-Agent': 'FireFox/1',
27 | },
28 | });
29 | assert(ctx.request.isChrome === false);
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/unittest/test/extend/response.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const mock = require('egg-mock');
5 |
6 | describe('test/extend/response.test.js', () => {
7 | let app;
8 | before(() => {
9 | app = mock.app();
10 | return app.ready();
11 | });
12 |
13 | describe('isSuccess()', () => {
14 | it('should true', () => {
15 | const ctx = app.mockContext();
16 | ctx.status = 200;
17 | assert(ctx.response.isSuccess === true);
18 | });
19 |
20 | it('should false', () => {
21 | const ctx = app.mockContext();
22 | ctx.status = 404;
23 | assert(ctx.response.isSuccess === false);
24 | });
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/unittest/test/hello.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 |
5 | describe('test/hello.test.js', () => {
6 | it('should work', () => {
7 | assert(Date.now() > 0);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/view-nunjucks/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class Home extends Controller {
6 | async render() {
7 | const ctx = this.ctx;
8 | await ctx.render('home.html', {
9 | user: {
10 | name: 'foobar',
11 | },
12 | title: 'egg view example',
13 | });
14 | }
15 | }
16 |
17 | module.exports = Home;
18 |
--------------------------------------------------------------------------------
/view-nunjucks/app/public/css/home.css:
--------------------------------------------------------------------------------
1 | body {}
2 |
--------------------------------------------------------------------------------
/view-nunjucks/app/public/css/layout.css:
--------------------------------------------------------------------------------
1 | body {}
2 |
--------------------------------------------------------------------------------
/view-nunjucks/app/public/js/home.js:
--------------------------------------------------------------------------------
1 | console.log('hello egg view');
2 |
--------------------------------------------------------------------------------
/view-nunjucks/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | app.router.get('/', 'home.render');
5 | };
6 |
--------------------------------------------------------------------------------
/view-nunjucks/app/view/home.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% block body %}
4 |
5 |
6 |
egg view example here, welcome {{ user.name }}
7 |
8 |
9 | {% endblock %}
10 |
--------------------------------------------------------------------------------
/view-nunjucks/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = 'my secret keys';
4 |
5 | exports.view = {
6 | defaultViewEngine: 'nunjucks',
7 | };
8 | exports.nunjucks = {
9 | // dir: 'path/to/template/dir', // default to `{app_root}/app/view`
10 | cache: true, // local env is false
11 | };
12 |
--------------------------------------------------------------------------------
/view-nunjucks/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.nunjucks = {
4 | enable: true,
5 | package: 'egg-view-nunjucks',
6 | };
7 |
--------------------------------------------------------------------------------
/view-nunjucks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "view-nunjucks-example",
3 | "dependencies": {
4 | "egg": "^1.10.1",
5 | "egg-view-nunjucks": "^2.1.4"
6 | },
7 | "devDependencies": {
8 | "egg-bin": "^4.3.5",
9 | "egg-mock": "^3.13.1",
10 | "macaca-electron": "2",
11 | "macaca-wd": "2"
12 | },
13 | "scripts": {
14 | "dev": "egg-bin dev",
15 | "test": "egg-bin test",
16 | "test:ui": "macaca run -d ./uitest --reporter macaca-reporter",
17 | "cov": "egg-bin cov"
18 | },
19 | "private": true
20 | }
21 |
--------------------------------------------------------------------------------
/view-nunjucks/test/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mm = require('egg-mock');
4 |
5 | describe('example view-nunjucks test', () => {
6 | let app;
7 |
8 | before(() => {
9 | app = mm.app();
10 | return app.ready();
11 | });
12 |
13 | after(() => app.close());
14 |
15 | it('should GET / 200', () => {
16 | return app.httpRequest()
17 | .get('/')
18 | .expect(200)
19 | .expect(/egg view example here, welcome foobar<\/h2>/)
20 | .expect(/egg view example<\/title>/);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/view-nunjucks/uitest/helper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const wd = require('macaca-wd');
4 | const {
5 | extendsMixIn,
6 | } = require('macaca-wd/lib/helper');
7 |
8 | extendsMixIn(wd);
9 |
10 | const port = 7001;
11 |
12 | const BASE_URL = `http://127.0.0.1:${port}`;
13 |
14 | wd.addPromiseChainMethod('initWindow', function(options = {}) {
15 | return this
16 | .init(Object.assign({
17 | platformName: 'desktop',
18 | browserName: 'electron',
19 | deviceScaleFactor: 2,
20 | }, options))
21 | .setWindowSize(options.width, options.height);
22 | });
23 |
24 | const driver = wd.promiseChainRemote({
25 | host: 'localhost',
26 | port: process.env.MACACA_SERVER_PORT || 3456,
27 | });
28 |
29 | exports.driver = driver;
30 | exports.BASE_URL = BASE_URL;
31 |
--------------------------------------------------------------------------------
/view-nunjucks/uitest/mocha.opts:
--------------------------------------------------------------------------------
1 | --require babel-register
2 | --recursive
3 | --timeout 60000
4 |
--------------------------------------------------------------------------------